Repository: bang590/JSPatch Branch: master Commit: e80a5573af22 Files: 228 Total size: 1.1 MB Directory structure: gitextract_5skxgrji/ ├── .gitignore ├── .travis.yml ├── Demo/ │ ├── DribbbleDemo/ │ │ ├── Podfile │ │ ├── README.md │ │ ├── dribbbleDemo/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Images.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage-1.launchimage/ │ │ │ │ │ └── Contents.json │ │ │ │ └── LaunchImage.launchimage/ │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── dribbble/ │ │ │ │ ├── CommonDefine.js │ │ │ │ ├── DBDataSource.js │ │ │ │ ├── DBDetailController.js │ │ │ │ ├── DBDetailViews.js │ │ │ │ ├── DBTimelineController.js │ │ │ │ ├── DBTimelineViews.js │ │ │ │ ├── DBUserController.js │ │ │ │ ├── DBUserViews.js │ │ │ │ ├── main.js │ │ │ │ └── tmpData.js │ │ │ └── main.m │ │ ├── dribbbleDemo.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── project.xcworkspace/ │ │ │ └── contents.xcworkspacedata │ │ └── dribbbleDemoTests/ │ │ ├── Info.plist │ │ └── dribbbleDemoTests.m │ ├── OSXDemo/ │ │ ├── JSPatchOSXDemo/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Base.lproj/ │ │ │ │ └── MainMenu.xib │ │ │ ├── Info.plist │ │ │ ├── demo.js │ │ │ └── main.m │ │ └── JSPatchOSXDemo.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── SwiftDemo/ │ │ ├── SwiftDemo/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets/ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ ├── SwiftDemo-Bridging-Header.h │ │ │ ├── TestObject.swift │ │ │ ├── ViewController.swift │ │ │ └── demo.js │ │ └── SwiftDemo.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── iOSDemo/ │ │ ├── JSPatchDemo/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── JPViewController.h │ │ │ ├── JPViewController.m │ │ │ ├── Supporting Files/ │ │ │ │ ├── Images.xcassets/ │ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Info.plist │ │ │ │ └── main.m │ │ │ └── demo.js │ │ ├── JSPatchDemo.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ └── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ └── JSPatchDemo.xcscheme │ │ └── JSPatchTests/ │ │ ├── Info.plist │ │ ├── InheritTest.js │ │ ├── JPCFunctionTest.h │ │ ├── JPCFunctionTest.m │ │ ├── JPInheritanceTestObjects.h │ │ ├── JPInheritanceTestObjects.m │ │ ├── JPJSClassTest.h │ │ ├── JPJSClassTest.m │ │ ├── JPMultithreadTestObject.h │ │ ├── JPMultithreadTestObject.m │ │ ├── JPNumberTest.h │ │ ├── JPNumberTest.m │ │ ├── JPPerformanceTest.h │ │ ├── JPPerformanceTest.m │ │ ├── JPSuperTestObject.h │ │ ├── JPSuperTestObject.m │ │ ├── JPTestObject.h │ │ ├── JPTestObject.m │ │ ├── JSPatchTests.m │ │ ├── jsCFunctionTest.js │ │ ├── jsClassTest.js │ │ ├── jsNumberTest.js │ │ ├── multithreadTest.js │ │ ├── newBlockTest.h │ │ ├── newBlockTest.js │ │ ├── newBlockTest.m │ │ ├── newProtocolTest.h │ │ ├── newProtocolTest.js │ │ ├── newProtocolTest.m │ │ ├── performanceTest.js │ │ ├── protocolTest.js │ │ ├── superTest.js │ │ └── test.js │ ├── iOSPlayground/ │ │ ├── JSPatchPlayground/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Brand Assets.launchimage/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ └── LaunchImage.launchimage/ │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── JPErrorMsgViewController.h │ │ │ ├── JPErrorMsgViewController.m │ │ │ ├── JPRootViewController.h │ │ │ ├── JPRootViewController.m │ │ │ ├── libs/ │ │ │ │ ├── SGDirWatchdog.h │ │ │ │ └── SGDirWatchdog.m │ │ │ ├── main.m │ │ │ └── src/ │ │ │ ├── JPDemoController.js │ │ │ └── main.js │ │ ├── JSPatchPlayground.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── project.xcworkspace/ │ │ │ └── contents.xcworkspacedata │ │ └── README.md │ ├── iOSPlaygroundToolDemo/ │ │ ├── JSPatchPlaygroundDemo/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ └── apple.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ ├── JPRootViewController.h │ │ │ ├── JPRootViewController.m │ │ │ ├── js/ │ │ │ │ └── demo.js │ │ │ └── main.m │ │ ├── JSPatchPlaygroundDemo.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── project.xcworkspace/ │ │ │ └── contents.xcworkspacedata │ │ └── README.md │ └── tvOSDemo/ │ ├── JSPatchDemo/ │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── JPViewController.h │ │ ├── JPViewController.m │ │ ├── Supporting Files/ │ │ │ ├── Images.xcassets/ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ └── main.m │ │ └── demo.js │ └── JSPatchDemo.xcodeproj/ │ ├── project.pbxproj │ └── project.xcworkspace/ │ └── contents.xcworkspacedata ├── Extensions/ │ ├── JPBlock/ │ │ ├── JPBlock.h │ │ ├── JPBlock.m │ │ ├── JPBlockWrapper.h │ │ └── JPBlockWrapper.m │ ├── JPCFunction/ │ │ ├── JPCFunction.h │ │ ├── JPCFunction.m │ │ ├── JPMemory.h │ │ ├── JPMemory.m │ │ ├── JPStructPointer.h │ │ └── JPStructPointer.m │ ├── JPCFunctionBinder/ │ │ ├── CoreGraphics/ │ │ │ ├── JPCGBitmapContext.h │ │ │ ├── JPCGBitmapContext.m │ │ │ ├── JPCGColor.h │ │ │ ├── JPCGColor.m │ │ │ ├── JPCGContext.h │ │ │ ├── JPCGContext.m │ │ │ ├── JPCGGeometry.h │ │ │ ├── JPCGGeometry.m │ │ │ ├── JPCGImage.h │ │ │ ├── JPCGImage.m │ │ │ ├── JPCGPath.h │ │ │ ├── JPCGPath.m │ │ │ ├── JPCGTransform.h │ │ │ ├── JPCGTransform.m │ │ │ ├── JPCoreGraphics.h │ │ │ └── JPCoreGraphics.m │ │ └── UIKit/ │ │ ├── JPUIGeometry.h │ │ ├── JPUIGeometry.m │ │ ├── JPUIGraphics.h │ │ ├── JPUIGraphics.m │ │ ├── JPUIImage.h │ │ ├── JPUIImage.m │ │ ├── JPUIKit.h │ │ └── JPUIKit.m │ ├── JPCleaner.h │ ├── JPCleaner.m │ ├── JPDispatch.h │ ├── JPDispatch.m │ ├── JPLibffi/ │ │ ├── JPMethodSignature.h │ │ ├── JPMethodSignature.m │ │ └── libffi/ │ │ ├── ffi.h │ │ ├── ffi_arm.h │ │ ├── ffi_arm64.h │ │ ├── ffi_i386.h │ │ ├── ffi_x86_64.h │ │ ├── ffitarget.h │ │ ├── ffitarget_arm.h │ │ ├── ffitarget_arm64.h │ │ ├── ffitarget_i386.h │ │ ├── ffitarget_x86_64.h │ │ └── libffi.a │ ├── JPLocker.h │ ├── JPLocker.m │ ├── JPNumber.h │ ├── JPNumber.m │ ├── JPPlaygroundTool/ │ │ ├── JPPlayground.h │ │ ├── JPPlayground.m │ │ ├── JPPlaygroundModule/ │ │ │ ├── JPKeyCommands.h │ │ │ ├── JPKeyCommands.m │ │ │ ├── SGDirWatchdog.h │ │ │ └── SGDirWatchdog.m │ │ ├── JPPlaygroundView/ │ │ │ ├── JPDevErrorView.h │ │ │ ├── JPDevErrorView.m │ │ │ ├── JPDevMenu.h │ │ │ ├── JPDevMenu.m │ │ │ ├── JPDevTipView.h │ │ │ └── JPDevTipView.m │ │ └── README.md │ ├── JPProtocol.h │ ├── JPProtocol.m │ ├── JPSpecialInit.h │ └── JPSpecialInit.m ├── JSPatch/ │ ├── JPEngine.h │ ├── JPEngine.m │ └── JSPatch.js ├── JSPatch.podspec ├── LICENSE ├── Loader/ │ ├── JPLoader.h │ ├── JPLoader.m │ ├── libs/ │ │ ├── RSA.h │ │ ├── RSA.m │ │ ├── ZipArchive.h │ │ ├── ZipArchive.m │ │ └── minizip/ │ │ ├── crypt.h │ │ ├── ioapi.c │ │ ├── ioapi.h │ │ ├── mztools.c │ │ ├── mztools.h │ │ ├── unzip.c │ │ ├── unzip.h │ │ ├── zip.c │ │ └── zip.h │ └── tools/ │ └── packer.php ├── README-CN.md └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # General .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control Pods/ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build ================================================ FILE: .travis.yml ================================================ language: objective-c osx_image: xcode7.3 env: - UDID="D72029C0-E8E1-4349-B423-E458466135B3", IOS_DEVICE="iPhone 4s (8.1)" - UDID="5752202B-E7A2-4B6C-9D7B-B211C2F54654", IOS_DEVICE="iPhone 6s (9.3)" script: - xcrun instruments -s devices - open -a "simulator" --args -CurrentDeviceUDID $UDID - xcodebuild test -project ./Demo/iOSDemo/JSPatchDemo.xcodeproj -scheme JSPatchDemo -sdk iphonesimulator -destination "platform=iOS Simulator,id=$UDID" - osascript -e 'tell app "Simulator" to quit' ================================================ FILE: Demo/DribbbleDemo/Podfile ================================================ platform :ios, '7.0' target 'dribbbleDemo' do pod "AFNetworking", "~> 2.0" pod "SDWebImage" end ================================================ FILE: Demo/DribbbleDemo/README.md ================================================ # JSPatch Dribbble Demo ![Screenshot](https://raw.github.com/bang590/JSPatch/master/Demo/DribbbleDemo/Screenshot.gif) A Dribbble iOS client write in JSPatch. Please install the cocoapods and run `pod install`. ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/AppDelegate.h ================================================ // // AppDelegate.h // dribbbleDemo // // Created by bang on 15/9/1. // Copyright (c) 2015年 bang. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/AppDelegate.m ================================================ // // AppDelegate.m // dribbbleDemo // // Created by bang on 15/9/1. // Copyright (c) 2015年 bang. All rights reserved. // #import "AppDelegate.h" #import "JPEngine.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; [self.window makeKeyAndVisible]; [JPEngine startEngine]; NSString *sourcePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"dribbble/main.js"]; [JPEngine evaluateScriptWithPath:sourcePath]; [self initRootViewController]; return YES; } - (void)initRootViewController { } - (void)applicationWillResignActive:(UIApplication *)application { // 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. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // 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. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // 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. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/Images.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/Images.xcassets/LaunchImage-1.launchimage/Contents.json ================================================ { "images" : [ ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/Images.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "736h", "filename" : "Default-576@2x.png", "minimum-system-version" : "8.0", "orientation" : "portrait", "scale" : "3x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "736h", "filename" : "Default-736@3x.png", "minimum-system-version" : "8.0", "orientation" : "landscape", "scale" : "3x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "667h", "filename" : "Default-667@2x.png", "minimum-system-version" : "8.0", "orientation" : "portrait", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "Default@2x.png", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "retina4", "filename" : "Default-568h@2x.png", "minimum-system-version" : "7.0", "orientation" : "portrait", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "1x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier com.jspatch..$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/CommonDefine.js ================================================ global.SCREEN_WIDTH = require('UIScreen').mainScreen().bounds().width; global.SCREEN_HEIGHT = require('UIScreen').mainScreen().bounds().height; global.UIHelper = { bottomY: function(view) { var f = view.frame(); return f.height + f.y; }, rightX: function(view) { var f = view.frame(); return f.width + f.x; }, setWidth: function(view, width) { var f = view.frame(); f.width = width view.setFrame(f) }, setHeight: function(view, height) { var f = view.frame(); f.height = height view.setFrame(f) }, setX: function(view, x) { var f = view.frame(); f.x = x view.setFrame(f) }, setY: function(view, y) { var f = view.frame(); f.y = y view.setFrame(f) } } ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/DBDataSource.js ================================================ var _dataSourceShareInstance; defineJSClass('DBDataSource', { init: function(){ this.dribbbleHost = 'https://api.dribbble.com/v1'; this.requestManager = require('AFHTTPRequestOperationManager').manager(); this.requestManager.requestSerializer().setValue_forHTTPHeaderField('Bearer deeb37c0823d3866650db12df9e36730a0453a5a7b8e6493e0ac5ece15929613', 'Authorization'); return this; }, _get: function(path, params, succ, fail){ var url = this.dribbbleHost + path this.requestManager.GET_parameters_success_failure(url, params, block('AFHTTPRequestOperation *, id', function(operation, responseObject) { if (succ) succ(responseObject); }), block('AFHTTPRequestOperation *, NSError *', function(operation, error) { if (fail) fail(error); }) ); }, loadPublicShots: function(page, per_page, succ, fail) { var path = '/shots'; this._get(path, {page: page, per_page:per_page}, succ, fail) }, loadComments: function(id, page, per_page, succ, fail) { var path = '/shots/' + id + '/comments'; this._get(path, {page: page, per_page:per_page}, succ, fail) }, loadUserShots: function(userId, page, per_page, succ, fail) { var path = '/users/' + userId + '/shots'; this._get(path, {page: page, per_page:per_page}, succ, fail) }, }, { shareInstance: function(){ if (!_dataSourceShareInstance) { _dataSourceShareInstance = DBDataSource.alloc().init(); } return _dataSourceShareInstance; }, }) /*item struct: { "id": 2619381, "title": "Seaborn Oyster Co.", "description": null, "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_teaser.jpg" }, "views_count": 2166, "likes_count": 235, "comments_count": 2, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 11, "created_at": "2016-03-29T17:12:41Z", "updated_at": "2016-03-29T17:12:53Z", "html_url": "https://dribbble.com/shots/2619381-Seaborn-Oyster-Co", "attachments_url": "https://api.dribbble.com/v1/shots/2619381/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619381/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619381/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619381/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619381/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619381/rebounds", "animated": false, "tags": [ "charleston", "company", "ocean", "oyster", "sea", "wave" ], "user": { "id": 52758, "name": "Jay Fletcher", "username": "jfletcherdesign", "html_url": "https://dribbble.com/jfletcherdesign", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/52758/avatars/normal/J_FLETCHER_DESIGN_LOGO-01.jpg?1401983283", "bio": "", "location": "Charleston, SC", "links": { "web": "http://www.jfletcherdesign.com", "twitter": "https://twitter.com/jfletcherdesign" }, "buckets_count": 0, "comments_received_count": 5239, "followers_count": 13803, "followings_count": 558, "likes_count": 6531, "likes_received_count": 104895, "projects_count": 10, "rebounds_received_count": 325, "shots_count": 481, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/52758/buckets", "followers_url": "https://api.dribbble.com/v1/users/52758/followers", "following_url": "https://api.dribbble.com/v1/users/52758/following", "likes_url": "https://api.dribbble.com/v1/users/52758/likes", "projects_url": "https://api.dribbble.com/v1/users/52758/projects", "shots_url": "https://api.dribbble.com/v1/users/52758/shots", "teams_url": "https://api.dribbble.com/v1/users/52758/teams", "created_at": "2011-08-13T23:30:38Z", "updated_at": "2016-03-29T17:12:53Z" }, "team": null }, */ ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/DBDetailController.js ================================================ include('DBDetailViews.js') include('DBUserController.js') defineClass('DBDetailViewController: UITableViewController', [ 'loadingView', 'isLoading', 'commentsData', 'itemData', 'currPage' ], { initWithItem: function(item){ self = self.super().init(); if (self) { self.tableView().setSeparatorStyle(0); self.setTitle(item['title']); var headerView = DBDetailHeaderView.alloc().initWithItem(item); var slf = self; headerView.setTapUserCallback(function(user){ slf._handleGotoUser(user); }) self.tableView().setTableHeaderView(headerView); var loadingView = require('UIActivityIndicatorView').alloc().initWithActivityIndicatorStyle(2); loadingView.setFrame({x: (SCREEN_WIDTH - 40) / 2, y:headerView.frame().height + 30, width:40, height:40}); loadingView.startAnimating(); self.view().addSubview(loadingView); self.setLoadingView(loadingView); self.setCommentsData([]); self.setItemData(item); self.setCurrPage(1); self._loadComment(); } return self; }, _loadComment: function(){ self.setIsLoading(1) var item = self.itemData(); var perPage = 10; var slf = self; DBDataSource.shareInstance().loadComments(item['id'], self.currPage(), perPage, function(comments){ slf.loadingView().removeFromSuperview(); slf.setCommentsData(slf.commentsData().concat(comments)); slf.setCurrPage(slf.currPage() + 1); slf.setIsLoading(0); if (comments.length >= perPage) { slf.tableView().setTableFooterView(DBLoadMoreView.alloc().init()); } else { slf.tableView().setTableFooterView(null); } slf.tableView().reloadData(); }, function(){ //fail }) }, numberOfSectionsInTableView: function(tableView) { return 1; }, tableView_numberOfRowsInSection: function(tableView, section) { if (!self.commentsData()) return 0; return self.commentsData().length; }, tableView_cellForRowAtIndexPath: function(tableView, indexPath) { var cell = tableView.dequeueReusableCellWithIdentifier("cell") if (!cell) { cell = DBCommentViewCell.alloc().initWithStyle_reuseIdentifier(0, "cell") var slf = self; cell.setTapUserCallback(function(user){ slf._handleGotoUser(user); }) } cell.renderWithComment(self.commentsData()[indexPath.row()]); return cell }, tableView_heightForRowAtIndexPath: function(tableView, indexPath) { var comment = self.commentsData()[indexPath.row()]; if (!comment['contentHeight']) { comment['contentHeight'] = DBCommentViewCell.heightWithComment(comment); } return comment['contentHeight']; }, scrollViewDidScroll: function(scrollView) { var contentOffset = scrollView.contentOffset(); var contentSize = scrollView.contentSize(); if (!self.isLoading() && self.tableView().tableFooterView() && contentOffset.y - contentSize.height > -SCREEN_HEIGHT) { self._loadComment(); } }, _handleGotoUser: function(user) { var userVC = DBUserViewController.alloc().initWithUser(user); self.navigationController().pushViewController_animated(userVC, YES); } }) ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/DBDetailViews.js ================================================ require('UIView, UIImage') var gap = 10; var avatarSize = 40; defineClass('DBDetailHeaderView: UIView', ['tapUserCallback', 'itemData'], { initWithItem: function(item) { self = self.super().init(); if (self) { self.setItemData(item); var avatarButton = require('UIButton') .alloc() .initWithFrame({x:gap, y:gap, width:avatarSize, height:avatarSize}); avatarButton.addTarget_action_forControlEvents(self, 'handleTapUser', 1 << 6); var nameLabel = UILabel .alloc() .initWithFrame({x: gap * 2 + avatarSize, y:gap, width:SCREEN_WIDTH - avatarSize - gap * 3 , height:20}); nameLabel.setFont(UIFont.systemFontOfSize(14)); var timeLabel = UILabel .alloc() .initWithFrame({x: gap * 2 + avatarSize, y:gap + 20, width:SCREEN_WIDTH - avatarSize - gap * 3 , height:20}); timeLabel.setFont(UIFont.systemFontOfSize(12)); timeLabel.setTextColor(UIColor.grayColor()); var contentImageView = require('UIImageView') .alloc() .initWithFrame({x: gap, y:gap*2 + avatarSize, width:SCREEN_WIDTH - gap*2, height:(SCREEN_WIDTH - gap*2)*3/4}); self.addSubview(avatarButton); self.addSubview(nameLabel); self.addSubview(timeLabel); self.addSubview(contentImageView); var panelView = self._genPanelViewWithItem(item); var panelFrame = panelView.frame(); panelFrame.x = SCREEN_WIDTH - (gap + panelFrame.width); panelFrame.y = contentImageView.frame().y + contentImageView.frame().height + gap; panelView.setFrame(panelFrame); self.addSubview(panelView); avatarButton.sd__setImageWithURL_forState(require('NSURL').URLWithString(item['user']['avatar_url']), 0); contentImageView.sd__setImageWithURL(require('NSURL').URLWithString(item['images']['normal'])); nameLabel.setText(item['user']['name']) var d = new Date(item['created_at']); var dateStr = d.getFullYear() + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日' + ' ' + d.getHours() + ':' + d.getMinutes(); timeLabel.setText(dateStr); self.setFrame({x:0, y:0, width: SCREEN_WIDTH, height:panelView.frame().y + panelView.frame().height}); } return self; }, handleTapUser : function(){ var cb = self.tapUserCallback(); if (cb) cb(self.itemData()['user']); }, _genPanelViewWithItem : function(item) { var panelView = UIView .alloc() .init(); var iconSize = 12; var viewImageView = UIImageView .alloc() .initWithFrame({x:0, y:0, width:15, height: 15}); viewImageView.setImage(UIImage.imageWithContentsOfFile(resourcePath('imgs/view.png'))); panelView.addSubview(viewImageView); var viewLabel = self._genPanelLabel(item['views_count'], {x: UIHelper.rightX(viewImageView) + 5, y:0, width:40, height:iconSize}); panelView.addSubview(viewLabel); var commentImageView = UIImageView .alloc() .initWithFrame({x:UIHelper.rightX(viewLabel) + 10, y:3, width:iconSize, height: iconSize}); commentImageView.setImage(UIImage.imageWithContentsOfFile(resourcePath('imgs/comment.png'))); panelView.addSubview(commentImageView); var commentLabel = self._genPanelLabel(item['comments_count'], {x: UIHelper.rightX(commentImageView) + 5, y:0, width:40, height:iconSize}); panelView.addSubview(commentLabel); var likeImageView = UIImageView .alloc() .initWithFrame({x:UIHelper.rightX(commentLabel) + 10, y:3, width:iconSize, height: iconSize}); likeImageView.setImage(UIImage.imageWithContentsOfFile(resourcePath('imgs/like.png'))); panelView.addSubview(likeImageView); var commentLabel = self._genPanelLabel(item['likes_count'], {x: UIHelper.rightX(likeImageView) + 5, y:0, width:40, height:iconSize}); panelView.addSubview(commentLabel); panelView.setFrame({x:0, y:0, width:UIHelper.rightX(commentLabel), height:40}); return panelView; }, _genPanelLabel: function(val, frame) { var viewLabel = UILabel.alloc().initWithFrame(frame) viewLabel.setText(val.toString()); viewLabel.setFont(UIFont.systemFontOfSize(14)); viewLabel.setTextColor(UIColor.colorWithWhite_alpha(.5, 1)) viewLabel.sizeToFit(); return viewLabel; } }) defineClass('DBCommentViewCell: UITableViewCell', [ 'avatarButton', 'nameLabel', 'timeLabel', 'contentLabel', 'tapUserCallback', 'commentData', ], { initWithStyle_reuseIdentifier: function(style, reuseIdentifier) { self = self.super().initWithStyle_reuseIdentifier(style, reuseIdentifier); if (self) { self.setSelectionStyle(0); var avatarButton = require('UIButton') .alloc() .initWithFrame({x:gap, y:gap, width:avatarSize, height:avatarSize}); avatarButton.addTarget_action_forControlEvents(self, 'handleTapUser', 1 << 6); var nameLabel = UILabel .alloc() .initWithFrame({x: gap * 2 + avatarSize, y:gap, width:SCREEN_WIDTH - avatarSize - gap * 3 , height:20}); nameLabel.setFont(UIFont.systemFontOfSize(14)); nameLabel.setTextColor(UIColor.colorWithWhite_alpha(.5, 1)) var timeLabel = UILabel .alloc() .initWithFrame({x: SCREEN_WIDTH - gap - 200, y:gap, width:200 , height:20}); timeLabel.setFont(UIFont.systemFontOfSize(12)); timeLabel.setTextColor(UIColor.colorWithWhite_alpha(.7, 1)); timeLabel.setTextAlignment(2); var contentLabel = DBCommentViewCell._genContentLabel(); self.addSubview(avatarButton); self.addSubview(nameLabel); self.addSubview(timeLabel); self.addSubview(contentLabel); self.setAvatarButton(avatarButton); self.setNameLabel(nameLabel); self.setTimeLabel(timeLabel); self.setContentLabel(contentLabel); } return self; }, renderWithComment: function(comment) { self.avatarButton().sd__setImageWithURL_forState(require('NSURL').URLWithString(comment['user']['avatar_url']), 0); self.nameLabel().setText(comment['user']['name']) var d = new Date(comment['created_at']); var dateStr = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate() + '-';// + ' ' + d.getHours() + ':' + d.getMinutes(); self.timeLabel().setText(dateStr); DBCommentViewCell._renderContentLabel(comment, self.contentLabel()); self.setCommentData(comment); }, handleTapUser : function(){ var cb = self.tapUserCallback(); if (cb) cb(self.commentData()['user']); }, }, { heightWithComment: function(comment) { var contentLabel = self._genContentLabel(); self._renderContentLabel(comment, contentLabel); var contentFrame = contentLabel.frame(); return contentFrame.height + contentFrame.y + gap; }, _renderContentLabel: function(comment, contentLabel) { if (!comment['bodyText']) { comment['bodyText'] = comment['body'].replace('\n', '').replace('

', '\n').replace(/<[^>]+>/g,"") } contentLabel.setText(comment['bodyText']); var size = contentLabel.sizeThatFits({width:contentLabel.frame().width, height:1000}); var frame = contentLabel.frame(); frame.height = size.height; contentLabel.setFrame(frame); }, _genContentLabel: function() { var contentLabel = require('UILabel') .alloc() .initWithFrame({x:gap * 2 + avatarSize, y: gap*2 + 15, width:SCREEN_WIDTH - gap * 3 - avatarSize, height:0}); contentLabel.setFont(UIFont.systemFontOfSize(16)); contentLabel.setNumberOfLines(0); return contentLabel; } }) ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/DBTimelineController.js ================================================ include('DBTimelineViews.js') include('DBDetailController.js') defineClass('WBTimelineViewController: UITableViewController', [ 'loadingView', 'isLoading', 'shots', 'currPage' ], { init: function(){ self = self.super().init(); var loadingView = require('UIActivityIndicatorView').alloc().initWithActivityIndicatorStyle(2); loadingView.setFrame({x: (SCREEN_WIDTH - 40) / 2, y:(SCREEN_HEIGHT - 40 - 64) / 2, width:40, height:40}); loadingView.startAnimating(); self.view().addSubview(loadingView); self.setLoadingView(loadingView); self.tableView().setBackgroundColor(UIColor.colorWithWhite_alpha(.9, 1)); self.tableView().setSeparatorStyle(0); self.setTitle('Dribbble'); self.setShots([]); self.setCurrPage(1); self._loadShots(); return self; }, _loadShots: function() { self.setIsLoading(1) var perPage = 20; var slf = self; DBDataSource.shareInstance().loadPublicShots(self.currPage(), perPage, function(shots){ slf.loadingView().removeFromSuperview(); slf.setShots(slf.shots().concat(shots)); slf.setCurrPage(slf.currPage() + 1); slf.setIsLoading(0); if (shots.length >= perPage) { slf.tableView().setTableFooterView(DBLoadMoreView.alloc().init()); } else { slf.tableView().setTableFooterView(null); } slf.tableView().reloadData(); }, function(){ //fail }) }, numberOfSectionsInTableView: function(tableView) { return 1; }, tableView_numberOfRowsInSection: function(tableView, section) { return self.shots().length / 2; }, tableView_cellForRowAtIndexPath: function(tableView, indexPath) { var cell = tableView.dequeueReusableCellWithIdentifier("cell") if (!cell) { cell = DBTimelineViewCell.alloc().initWithStyle_reuseIdentifier(0, "cell") var slf = self; cell.setTapCallback(function(item){ slf._handleGotoItem(item); }) } cell.renderWithItems(self.shots()[indexPath.row()*2], self.shots()[indexPath.row()*2 + 1]); return cell }, tableView_heightForRowAtIndexPath: function(tableView, indexPath) { return (SCREEN_WIDTH / 2) *3/4 + 30; }, scrollViewDidScroll: function(scrollView) { var contentOffset = scrollView.contentOffset(); var contentSize = scrollView.contentSize(); if (!self.isLoading() && contentOffset.y - contentSize.height > -SCREEN_HEIGHT) { self._loadShots(); } }, _handleGotoItem: function(item) { var detailVC = DBDetailViewController.alloc().initWithItem(item); self.navigationController().pushViewController_animated(detailVC, YES); } }) ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/DBTimelineViews.js ================================================ var gap = 10; var avatarSize = 40; require('UILabel, UIColor, UIFont, UITextView'); defineClass('DBTimelineItemView: UIView', [ 'avatarImageView', 'nameLabel', 'contentImageBtn', 'tapCallback' ], { init: function(){ self = self.super().init(); var imgGap = 5; var width = (SCREEN_WIDTH - 10 * 3) / 2; self.setFrame({x: 0, y: 0, width:width, height: width * 3/4 + 30}); self.setBackgroundColor(UIColor.whiteColor()); var contentImageBtn = require('UIButton') .alloc() .initWithFrame({x: imgGap, y:imgGap, width:width - 2*imgGap, height:(width - 2*imgGap)*3/4}); self.addSubview(contentImageBtn); self.setContentImageBtn(contentImageBtn); contentImageBtn.addTarget_action_forControlEvents(self, 'handleTap', 1 << 6); var avatarSize = 18; var avatarImageView = require('UIImageView') .alloc() .initWithFrame({x:imgGap, y:contentImageBtn.frame().height + contentImageBtn.frame().y + imgGap + 2, width:avatarSize, height:avatarSize}); self.addSubview(avatarImageView); self.setAvatarImageView(avatarImageView); var nameLabel = UILabel .alloc() .initWithFrame({x: imgGap + avatarSize + 5, y:avatarImageView.frame().y, width:width - avatarSize - imgGap*2 - 5 , height:avatarSize}); nameLabel.setFont(UIFont.systemFontOfSize(12)); nameLabel.setTextColor(UIColor.grayColor()); self.addSubview(nameLabel); self.setNameLabel(nameLabel); return self; }, handleTap: function() { var cb = self.tapCallback(); if (cb) cb(); }, renderWithItem: function(item) { self.contentImageBtn().sd__setImageWithURL_forState(require('NSURL').URLWithString(item['images']['normal']), 0); self.avatarImageView().sd__setImageWithURL(require('NSURL').URLWithString(item['user']['avatar_url'])); self.nameLabel().setText(item['user']['name']); }, }) defineClass('DBTimelineViewCell: UITableViewCell', [ 'itemView1', 'itemView2', 'tapCallback', ], { initWithStyle_reuseIdentifier: function(style, reuseIdentifier) { self = self.super().initWithStyle_reuseIdentifier(style, reuseIdentifier); if (self) { self.setSelectionStyle(0); self.contentView().setBackgroundColor(UIColor.colorWithWhite_alpha(.9, 1)); self._initItemView(); } return self; }, _initItemView: function(){ var itemView1 = DBTimelineItemView.alloc().init(); var itemView2 = DBTimelineItemView.alloc().init(); itemView1.setFrame({x:gap, y: gap, width: itemView1.frame().width, height: itemView1.frame().height}); itemView2.setFrame({x:gap*2 + itemView1.frame().width, y: gap, width: itemView2.frame().width, height: itemView2.frame().height}); self.setItemView1(itemView1); self.setItemView2(itemView2); self.addSubview(itemView1); self.addSubview(itemView2); }, renderWithItems: function(item1, item2) { if (item1) { self.itemView1().renderWithItem(item1); } if (item2) { self.itemView2().renderWithItem(item2); } self.itemView1().setHidden(!item1); self.itemView2().setHidden(!item2); var slf = self self.itemView1().setTapCallback(function(){ var cb = slf.tapCallback(); if (cb) cb(item1); }) self.itemView2().setTapCallback(function(){ var cb = slf.tapCallback(); if (cb) cb(item2); }) } }) defineClass('DBLoadMoreView:UIView', { init: function(){ self = self.super().init(); var loadingView = require('UIActivityIndicatorView').alloc().initWithActivityIndicatorStyle(2); loadingView.startAnimating(); loadingView.setFrame({x:(SCREEN_WIDTH - 140) / 2, y: 10, width:40, height: 40}); var loadingLabel = require('UILabel').alloc().init(); loadingLabel.setText('Loading...'); loadingLabel.setFrame({x:(SCREEN_WIDTH - 140) / 2 + 40, y: 10, width:90, height: 40}); loadingLabel.setTextColor(require('UIColor').grayColor()); self.addSubview(loadingView); self.addSubview(loadingLabel); self.setFrame({x:0, y:0, width:SCREEN_WIDTH, height: 60}); return self; }, }) ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/DBUserController.js ================================================ include('DBTimelineViews.js') include('DBUserViews.js') defineClass('DBUserViewController: UITableViewController', [ 'loadingView', 'isLoading', 'commentsData', 'user', 'shots', 'currPage' ], { initWithUser: function(user){ self = self.super().init(); if (self) { self.tableView().setSeparatorStyle(0); self.tableView().setBackgroundColor(UIColor.colorWithWhite_alpha(.9, 1)); self.setTitle(user['name']); var headerView = DBUserHeaderView.alloc().initWithUser(user); self.tableView().setTableHeaderView(headerView); var loadingView = require('UIActivityIndicatorView').alloc().initWithActivityIndicatorStyle(2); loadingView.setFrame({x: (SCREEN_WIDTH - 40) / 2, y:headerView.frame().height + 30, width:40, height:40}); loadingView.startAnimating(); self.view().addSubview(loadingView); self.setLoadingView(loadingView); self.setShots([]); self.setUser(user); self.setCurrPage(1); self._loadShots(); } return self; }, _loadShots: function(){ self.setIsLoading(1) var user = self.user(); var perPage = 10; var slf = self; DBDataSource.shareInstance().loadUserShots(user['id'], self.currPage(), perPage, function(newShots){ slf.loadingView().removeFromSuperview(); slf.setShots(slf.shots().concat(newShots)); slf.setCurrPage(slf.currPage() + 1); slf.setIsLoading(0); if (newShots.length >= perPage) { slf.tableView().setTableFooterView(DBLoadMoreView.alloc().init()); } else { slf.tableView().setTableFooterView(null); } slf.tableView().reloadData(); }, function(){ //fail }) }, numberOfSectionsInTableView: function(tableView) { return 1; }, tableView_numberOfRowsInSection: function(tableView, section) { if (!self.shots()) return 0; return self.shots().length / 2; }, tableView_cellForRowAtIndexPath: function(tableView, indexPath) { var cell = tableView.dequeueReusableCellWithIdentifier("cell") if (!cell) { cell = DBUserViewCell.alloc().initWithStyle_reuseIdentifier(0, "cell") var slf = self; cell.setTapCallback(function(item){ slf._handleGotoItem(item); }) } cell.renderWithItems(self.shots()[indexPath.row()*2], self.shots()[indexPath.row()*2 + 1]); return cell }, tableView_heightForRowAtIndexPath: function(tableView, indexPath) { return (SCREEN_WIDTH / 2) *3/4; }, scrollViewDidScroll: function(scrollView) { var contentOffset = scrollView.contentOffset(); var contentSize = scrollView.contentSize(); if (!self.isLoading() && self.tableView().tableFooterView() && contentOffset.y - contentSize.height > -SCREEN_HEIGHT) { self._loadShots(); } }, _handleGotoItem: function(item) { if (!item.user) item.user = self.user(); var detailVC = DBDetailViewController.alloc().initWithItem(item); self.navigationController().pushViewController_animated(detailVC, YES); } }) ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/DBUserViews.js ================================================ var gap = 10; defineClass('DBUserHeaderView: UIView', { initWithUser: function(user) { self = self.super().init(); if (self) { var avatarSize = 100; var avatarImageView = require('UIImageView') .alloc() .initWithFrame({x:(SCREEN_WIDTH - avatarSize) / 2, y:30, width:avatarSize, height:avatarSize}); var nameLabel = UILabel .alloc() .initWithFrame({x: 0, y:UIHelper.bottomY(avatarImageView) + 10, width:SCREEN_WIDTH, height:30}); nameLabel.setFont(UIFont.systemFontOfSize(18)); nameLabel.setTextAlignment(1); var panelView = UIView .alloc() .initWithFrame({x:0, y:UIHelper.bottomY(nameLabel) + 10,width:SCREEN_WIDTH, height:80}); var followerView = self._genUserDataView('follower', user['followers_count']); var shotsView = self._genUserDataView('shots', user['shots_count']); var likeView = self._genUserDataView('likes', user['likes_received_count']); UIHelper.setX(shotsView, UIHelper.rightX(followerView)); UIHelper.setX(likeView, UIHelper.rightX(shotsView)); panelView.addSubview(followerView); panelView.addSubview(shotsView); panelView.addSubview(likeView); self.addSubview(avatarImageView); self.addSubview(nameLabel); self.addSubview(panelView); avatarImageView.sd__setImageWithURL(require('NSURL').URLWithString(user['avatar_url'])); nameLabel.setText(user['name']); self.setFrame({x:0, y:0, width:SCREEN_WIDTH, height: UIHelper.bottomY(panelView)}); } return self; }, _genUserDataView : function(name, num) { var width = SCREEN_WIDTH / 3 var panelView = UIView .alloc() .initWithFrame({x:0,y:0,width:width,height:80}); var numLabel = UILabel.alloc().initWithFrame({x:0,y:0,width:width,height:40}) numLabel.setText(self._formatNum(num)); numLabel.setFont(UIFont.systemFontOfSize(22)); numLabel.setTextAlignment(1); var nameLabel = UILabel.alloc().initWithFrame({x:0,y:35,width:width,height:30}) nameLabel.setText(name); nameLabel.setFont(UIFont.systemFontOfSize(15)); nameLabel.setTextColor(UIColor.colorWithWhite_alpha(.5, 1)) nameLabel.setTextAlignment(1); panelView.addSubview(numLabel); panelView.addSubview(nameLabel); return panelView; }, _formatNum: function(num){ if (num >= 1000) { return (num/1000).toFixed(1) + 'k' } return num ? num.toString() : 0; } }) defineClass('DBUserItemView: DBTimelineItemView', { init: function() { self = self.super().init(); self.avatarImageView().removeFromSuperview(); self.nameLabel().removeFromSuperview(); var width = (SCREEN_WIDTH - 10 * 3) / 2; self.setFrame({x: 0, y: 0, width:width, height: width * 3/4 + 5}); return self; }, renderWithItem: function(item) { self.contentImageBtn().sd__setImageWithURL_forState(require('NSURL').URLWithString(item['images']['normal']), 0); }, }); defineClass('DBUserViewCell: DBTimelineViewCell', { _initItemView: function() { var itemView1 = DBUserItemView.alloc().init(); var itemView2 = DBUserItemView.alloc().init(); itemView1.setFrame({x:gap, y: gap, width: itemView1.frame().width, height: itemView1.frame().height}); itemView2.setFrame({x:gap*2 + itemView1.frame().width, y: gap, width: itemView2.frame().width, height: itemView2.frame().height}); self.setItemView1(itemView1); self.setItemView2(itemView2); self.addSubview(itemView1); self.addSubview(itemView2); }, }); ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/main.js ================================================ autoConvertOCType(1) include('CommonDefine.js') include('DBDataSource.js') include('DBTimelineController.js') defineClass('AppDelegate', { initRootViewController: function() { var tableViewCtrl = WBTimelineViewController.alloc().init() var navCtrl = require('UINavigationController').alloc().initWithRootViewController(tableViewCtrl); self.window().setRootViewController(navCtrl); } }) ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/dribbble/tmpData.js ================================================ var tmpData = [ { "id": 2619381, "title": "Seaborn Oyster Co.", "description": null, "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_teaser.jpg" }, "views_count": 2166, "likes_count": 235, "comments_count": 2, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 11, "created_at": "2016-03-29T17:12:41Z", "updated_at": "2016-03-29T17:12:53Z", "html_url": "https://dribbble.com/shots/2619381-Seaborn-Oyster-Co", "attachments_url": "https://api.dribbble.com/v1/shots/2619381/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619381/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619381/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619381/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619381/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619381/rebounds", "animated": false, "tags": [ "charleston", "company", "ocean", "oyster", "sea", "wave" ], "user": { "id": 52758, "name": "Jay Fletcher", "username": "jfletcherdesign", "html_url": "https://dribbble.com/jfletcherdesign", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/52758/avatars/normal/J_FLETCHER_DESIGN_LOGO-01.jpg?1401983283", "bio": "", "location": "Charleston, SC", "links": { "web": "http://www.jfletcherdesign.com", "twitter": "https://twitter.com/jfletcherdesign" }, "buckets_count": 0, "comments_received_count": 5239, "followers_count": 13803, "followings_count": 558, "likes_count": 6531, "likes_received_count": 104895, "projects_count": 10, "rebounds_received_count": 325, "shots_count": 481, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/52758/buckets", "followers_url": "https://api.dribbble.com/v1/users/52758/followers", "following_url": "https://api.dribbble.com/v1/users/52758/following", "likes_url": "https://api.dribbble.com/v1/users/52758/likes", "projects_url": "https://api.dribbble.com/v1/users/52758/projects", "shots_url": "https://api.dribbble.com/v1/users/52758/shots", "teams_url": "https://api.dribbble.com/v1/users/52758/teams", "created_at": "2011-08-13T23:30:38Z", "updated_at": "2016-03-29T17:12:53Z" }, "team": null }, { "id": 2619494, "title": "Mystery Project 72.1", "description": "

We're excited to be onboard for a new year of Outside Lands festival branding! Stay tuned for weekly updates including Ranger Dave's new patch series, the 2016 lineup, and more!

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30_teaser.jpg" }, "views_count": 2304, "likes_count": 252, "comments_count": 4, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 11, "created_at": "2016-03-29T18:05:57Z", "updated_at": "2016-03-29T18:07:21Z", "html_url": "https://dribbble.com/shots/2619494-Mystery-Project-72-1", "attachments_url": "https://api.dribbble.com/v1/shots/2619494/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619494/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619494/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619494/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619494/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619494/rebounds", "rebound_source_url": "https://api.dribbble.com/v1/shots/2454166", "animated": false, "tags": [ "badge", "branding", "bridge", "city", "dan kuhlken", "dkng", "logo", "nathan goldman", "patch", "san francisco", "vector" ], "user": { "id": 31348, "name": "DKNG", "username": "DKNG", "html_url": "https://dribbble.com/DKNG", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/31348/avatars/original/dkng_twitter.jpg?1305140827", "bio": "Established in 2005, DKNG is a design studio based in Los Angeles, California with a focus on the music and entertainment industries.", "location": "Los Angeles, CA", "links": { "web": "http://www.dkngstudios.com", "twitter": "https://twitter.com/DKNGstudios" }, "buckets_count": 0, "comments_received_count": 5274, "followers_count": 24704, "followings_count": 256, "likes_count": 197, "likes_received_count": 125646, "projects_count": 47, "rebounds_received_count": 324, "shots_count": 479, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/31348/buckets", "followers_url": "https://api.dribbble.com/v1/users/31348/followers", "following_url": "https://api.dribbble.com/v1/users/31348/following", "likes_url": "https://api.dribbble.com/v1/users/31348/likes", "projects_url": "https://api.dribbble.com/v1/users/31348/projects", "shots_url": "https://api.dribbble.com/v1/users/31348/shots", "teams_url": "https://api.dribbble.com/v1/users/31348/teams", "created_at": "2011-04-28T20:48:48Z", "updated_at": "2016-03-29T18:07:21Z" }, "team": null }, { "id": 2619183, "title": "Bonsai", "description": null, "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai_teaser.png" }, "views_count": 2143, "likes_count": 259, "comments_count": 11, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 18, "created_at": "2016-03-29T15:48:38Z", "updated_at": "2016-03-29T15:49:04Z", "html_url": "https://dribbble.com/shots/2619183-Bonsai", "attachments_url": "https://api.dribbble.com/v1/shots/2619183/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619183/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619183/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619183/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619183/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619183/rebounds", "animated": false, "tags": [ "bonsai", "illustration", "nature", "plant", "pot", "tree", "zen" ], "user": { "id": 44323, "name": "Zach Roszczewski", "username": "ZachRoszczewski", "html_url": "https://dribbble.com/ZachRoszczewski", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/44323/avatars/normal/18f509c70a25627b40d5e3499b1cba2f.png?1419195740", "bio": "Iconographer & Illustrator. Creator of www.flaticons.co & www.mojiapp.net.", "location": "Encinitas, California", "links": { "web": "http://zachroszczewski.com", "twitter": "https://twitter.com/ZachRoszczewski" }, "buckets_count": 10, "comments_received_count": 1682, "followers_count": 9067, "followings_count": 1541, "likes_count": 14094, "likes_received_count": 34409, "projects_count": 7, "rebounds_received_count": 14, "shots_count": 113, "teams_count": 2, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/44323/buckets", "followers_url": "https://api.dribbble.com/v1/users/44323/followers", "following_url": "https://api.dribbble.com/v1/users/44323/following", "likes_url": "https://api.dribbble.com/v1/users/44323/likes", "projects_url": "https://api.dribbble.com/v1/users/44323/projects", "shots_url": "https://api.dribbble.com/v1/users/44323/shots", "teams_url": "https://api.dribbble.com/v1/users/44323/teams", "created_at": "2011-07-07T14:49:07Z", "updated_at": "2016-03-29T15:49:04Z" }, "team": null }, { "id": 2619255, "title": "Canvas—A new space for big ideas", "description": "

A month ago the our team launched Canvas, a product for brands to tell their story and highlight products. It's been amazing to see your excitement for the creative possibilities and we can't wait to see how you use it.

\n\n

One of the best aspects of working on ads at Facebook is striving to find the sweet spot between the goals of our advertisers and those of people browsing their feed. Canvas allows businesses to create a more compelling experience for people, and in turn provides people with an ad they actually enjoy. Stay tuned for more :)

\n\n

If your interested in learning more about Canvas, or building one, you should check out https://canvas.facebook.com/\n
To learn more about our process check out Jaime Rovira's medium post https://medium.com/facebook-design/canvas-how-we-crafted-facebook-s-new-immersive-ads-696870e66b3f#.jy9w9l51m

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble.gif", "normal": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble_1x.gif", "teaser": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble_teaser.gif" }, "views_count": 3502, "likes_count": 262, "comments_count": 9, "attachments_count": 2, "rebounds_count": 0, "buckets_count": 12, "created_at": "2016-03-29T16:18:33Z", "updated_at": "2016-03-29T16:19:50Z", "html_url": "https://dribbble.com/shots/2619255-Canvas-A-new-space-for-big-ideas", "attachments_url": "https://api.dribbble.com/v1/shots/2619255/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619255/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619255/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619255/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619255/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619255/rebounds", "animated": true, "tags": [ "android", "animation", "creative", "illustration", "ios", "mobile", "tool" ], "user": { "id": 476251, "name": "ali griffin", "username": "aligdanger", "html_url": "https://dribbble.com/aligdanger", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/476251/avatars/normal/ali.png?1404762398", "bio": "Designing product @Facebook", "location": "San Francisco, CA", "links": { "twitter": "https://twitter.com/aligdanger" }, "buckets_count": 0, "comments_received_count": 203, "followers_count": 513, "followings_count": 289, "likes_count": 1302, "likes_received_count": 2487, "projects_count": 3, "rebounds_received_count": 9, "shots_count": 22, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/476251/buckets", "followers_url": "https://api.dribbble.com/v1/users/476251/followers", "following_url": "https://api.dribbble.com/v1/users/476251/following", "likes_url": "https://api.dribbble.com/v1/users/476251/likes", "projects_url": "https://api.dribbble.com/v1/users/476251/projects", "shots_url": "https://api.dribbble.com/v1/users/476251/shots", "teams_url": "https://api.dribbble.com/v1/users/476251/teams", "created_at": "2014-01-10T18:37:14Z", "updated_at": "2016-03-30T04:07:49Z" }, "team": { "id": 333588, "name": "Facebook", "username": "Facebook", "html_url": "https://dribbble.com/Facebook", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/333588/avatars/normal/9a9d5301e289975fa16abd070f1615c0.png?1440610176", "bio": "", "location": "1 Hacker Way, Menlo Park, CA", "links": { "web": "https://www.facebook.com/design", "twitter": "https://twitter.com/facebookdesign" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 14039, "followings_count": 0, "likes_count": 2, "likes_received_count": 0, "projects_count": 0, "rebounds_received_count": 0, "shots_count": 121, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/333588/buckets", "followers_url": "https://api.dribbble.com/v1/users/333588/followers", "following_url": "https://api.dribbble.com/v1/users/333588/following", "likes_url": "https://api.dribbble.com/v1/users/333588/likes", "projects_url": "https://api.dribbble.com/v1/users/333588/projects", "shots_url": "https://api.dribbble.com/v1/users/333588/shots", "created_at": "2013-05-15T23:13:37Z", "updated_at": "2016-03-30T04:07:49Z", "members_count": 39, "members_url": "https://api.dribbble.com/v1/teams/333588/members", "team_shots_url": "https://api.dribbble.com/v1/teams/333588/shots" } }, { "id": 2619346, "title": "Sunset", "description": "

Baker Beach sunset from this weekend.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset_teaser.png" }, "views_count": 2897, "likes_count": 231, "comments_count": 3, "attachments_count": 1, "rebounds_count": 0, "buckets_count": 6, "created_at": "2016-03-29T16:55:27Z", "updated_at": "2016-03-29T16:56:47Z", "html_url": "https://dribbble.com/shots/2619346-Sunset", "attachments_url": "https://api.dribbble.com/v1/shots/2619346/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619346/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619346/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619346/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619346/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619346/rebounds", "animated": false, "tags": [ "beach", "cartoon", "comics", "hand-darwn", "illustration", "nature", "sketch", "sunset" ], "user": { "id": 3460, "name": "Ryan Putnam", "username": "RypeArts", "html_url": "https://dribbble.com/RypeArts", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/3460/avatars/normal/4ed7a7a4737e971e3fa37f0705f5cc51.png?1457564367", "bio": "designer, illustrator, potter, and father", "location": "San Francisco, CA", "links": { "web": "http://ryanputn.am", "twitter": "https://twitter.com/RypeArts" }, "buckets_count": 3, "comments_received_count": 9722, "followers_count": 46667, "followings_count": 518, "likes_count": 10207, "likes_received_count": 211321, "projects_count": 34, "rebounds_received_count": 373, "shots_count": 589, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/3460/buckets", "followers_url": "https://api.dribbble.com/v1/users/3460/followers", "following_url": "https://api.dribbble.com/v1/users/3460/following", "likes_url": "https://api.dribbble.com/v1/users/3460/likes", "projects_url": "https://api.dribbble.com/v1/users/3460/projects", "shots_url": "https://api.dribbble.com/v1/users/3460/shots", "teams_url": "https://api.dribbble.com/v1/users/3460/teams", "created_at": "2010-07-16T12:48:16Z", "updated_at": "2016-03-29T16:56:47Z" }, "team": null }, { "id": 2619340, "title": "Skies Like These ", "description": "

In anticipation for their release of the paperback version of the book, Skies Like These, Macmillan commissioned us to redesign the cover artwork.

\n\n

The story is about a twelve-year-old girl name Jade who is sent to spend the summer with her aunt in Wyoming by her parents. She meets a rebellious boy who called himself Roy Parker, after the legendary Butch Cassidy. Jade tries to be a good friend Roy, but worries about the trouble he might get her into while he tries to plan stunts worthy of Butch Cassidy himself.\n

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble_teaser.png" }, "views_count": 1548, "likes_count": 177, "comments_count": 5, "attachments_count": 1, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T16:50:48Z", "updated_at": "2016-03-29T16:53:16Z", "html_url": "https://dribbble.com/shots/2619340-Skies-Like-These", "attachments_url": "https://api.dribbble.com/v1/shots/2619340/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619340/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619340/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619340/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619340/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619340/rebounds", "animated": false, "tags": [ "book", "book cover", "cover artwork", "cover design", "cowboy hat", "illustration", "mountain", "planets", "sky", "stars" ], "user": { "id": 44585, "name": "Brad Woodard", "username": "bradwwoodard", "html_url": "https://dribbble.com/bradwwoodard", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/44585/avatars/normal/593686b9b9c0d2b6a496d8404f24ce1f.png?1444862250", "bio": "Designer • Illustrator • Braver of the Woods", "location": "Austin, TX", "links": { "web": "http://www.bravethewoods.com/", "twitter": "https://twitter.com/brave_the_woods" }, "buckets_count": 1, "comments_received_count": 2598, "followers_count": 8556, "followings_count": 412, "likes_count": 2285, "likes_received_count": 45938, "projects_count": 21, "rebounds_received_count": 16, "shots_count": 324, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/44585/buckets", "followers_url": "https://api.dribbble.com/v1/users/44585/followers", "following_url": "https://api.dribbble.com/v1/users/44585/following", "likes_url": "https://api.dribbble.com/v1/users/44585/likes", "projects_url": "https://api.dribbble.com/v1/users/44585/projects", "shots_url": "https://api.dribbble.com/v1/users/44585/shots", "teams_url": "https://api.dribbble.com/v1/users/44585/teams", "created_at": "2011-07-08T15:47:58Z", "updated_at": "2016-03-29T16:53:16Z" }, "team": null }, { "id": 2619544, "title": "Robinhood", "description": "

Robinhood integrations illustration.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01_teaser.png" }, "views_count": 1530, "likes_count": 177, "comments_count": 6, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T18:24:59Z", "updated_at": "2016-03-29T18:26:47Z", "html_url": "https://dribbble.com/shots/2619544-Robinhood", "attachments_url": "https://api.dribbble.com/v1/shots/2619544/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619544/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619544/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619544/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619544/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619544/rebounds", "animated": false, "tags": [ "chart", "finance", "illustration", "money", "stock" ], "user": { "id": 4598, "name": "Ty Wilkins", "username": "tywilkins", "html_url": "https://dribbble.com/tywilkins", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/4598/avatars/normal/fox2.jpg?1391573055", "bio": "hello@tywilkins.com", "location": "San Francisco, CA", "links": { "web": "http://www.tywilkins.com", "twitter": "https://twitter.com/tywilkins" }, "buckets_count": 0, "comments_received_count": 1080, "followers_count": 8222, "followings_count": 527, "likes_count": 0, "likes_received_count": 21359, "projects_count": 8, "rebounds_received_count": 0, "shots_count": 97, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/4598/buckets", "followers_url": "https://api.dribbble.com/v1/users/4598/followers", "following_url": "https://api.dribbble.com/v1/users/4598/following", "likes_url": "https://api.dribbble.com/v1/users/4598/likes", "projects_url": "https://api.dribbble.com/v1/users/4598/projects", "shots_url": "https://api.dribbble.com/v1/users/4598/shots", "teams_url": "https://api.dribbble.com/v1/users/4598/teams", "created_at": "2010-09-30T20:31:02Z", "updated_at": "2016-03-29T18:27:54Z" }, "team": null }, { "id": 2619187, "title": "Confidential iPad App part #2", "description": "

Over the holidays, Rally built an iPad app for a confidential client and conference. This is video directly from interacting with the native iOS app.

\n\n

Myself, @Geof Crowl, and Wes tackled the project in just 15 days. It was intense but fun. Geof and I did the design and helped with layout in Xcode using Nibs. Wes built the globe and the data visualizations from a json file using our own Open GL globe library we've been building on an off for the past year.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally.gif", "normal": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally_1x.gif", "teaser": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally_teaser.gif" }, "views_count": 3205, "likes_count": 183, "comments_count": 9, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 20, "created_at": "2016-03-29T15:50:05Z", "updated_at": "2016-03-29T15:51:33Z", "html_url": "https://dribbble.com/shots/2619187-Confidential-iPad-App-part-2", "attachments_url": "https://api.dribbble.com/v1/shots/2619187/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619187/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619187/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619187/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619187/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619187/rebounds", "animated": true, "tags": [ ], "user": { "id": 3816, "name": "Ben Cline", "username": "letsgorally", "html_url": "https://dribbble.com/letsgorally", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/3816/avatars/normal/bb00fd14001a8cdd5e0e354df52a7fa4.png?1450769044", "bio": "@RALLY Co-Founder / Designer", "location": "Salt Lake City", "links": { "web": "http://beta.rallyinteractive.com", "twitter": "https://twitter.com/yocline" }, "buckets_count": 3, "comments_received_count": 4525, "followers_count": 30105, "followings_count": 241, "likes_count": 6878, "likes_received_count": 87892, "projects_count": 10, "rebounds_received_count": 28, "shots_count": 257, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/3816/buckets", "followers_url": "https://api.dribbble.com/v1/users/3816/followers", "following_url": "https://api.dribbble.com/v1/users/3816/following", "likes_url": "https://api.dribbble.com/v1/users/3816/likes", "projects_url": "https://api.dribbble.com/v1/users/3816/projects", "shots_url": "https://api.dribbble.com/v1/users/3816/shots", "teams_url": "https://api.dribbble.com/v1/users/3816/teams", "created_at": "2010-07-30T17:30:31Z", "updated_at": "2016-03-29T15:51:33Z" }, "team": { "id": 559317, "name": "RALLY", "username": "rally", "html_url": "https://dribbble.com/rally", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/559317/avatars/normal/rally_logo.png?1398641637", "bio": "Interactive Studio. Design & Development", "location": "Salt Lake City", "links": { "web": "http://beta.rallyinteractive.com", "twitter": "https://twitter.com/letsgorally" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 8281, "followings_count": 6, "likes_count": 73, "likes_received_count": 0, "projects_count": 14, "rebounds_received_count": 0, "shots_count": 273, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/559317/buckets", "followers_url": "https://api.dribbble.com/v1/users/559317/followers", "following_url": "https://api.dribbble.com/v1/users/559317/following", "likes_url": "https://api.dribbble.com/v1/users/559317/likes", "projects_url": "https://api.dribbble.com/v1/users/559317/projects", "shots_url": "https://api.dribbble.com/v1/users/559317/shots", "created_at": "2014-04-27T23:31:42Z", "updated_at": "2016-03-29T15:51:33Z", "members_count": 5, "members_url": "https://api.dribbble.com/v1/teams/559317/members", "team_shots_url": "https://api.dribbble.com/v1/teams/559317/shots" } }, { "id": 2619200, "title": "Eilean Donan Castle", "description": "

Day 209/365

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01_teaser.jpg" }, "views_count": 1434, "likes_count": 162, "comments_count": 4, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T15:54:42Z", "updated_at": "2016-03-29T15:55:23Z", "html_url": "https://dribbble.com/shots/2619200-Eilean-Donan-Castle", "attachments_url": "https://api.dribbble.com/v1/shots/2619200/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619200/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619200/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619200/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619200/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619200/rebounds", "rebound_source_url": "https://api.dribbble.com/v1/shots/2614735", "animated": false, "tags": [ "icon", "illustration", "lake", "scotland", "vector" ], "user": { "id": 283823, "name": "Scott Tusk", "username": "Tusk", "html_url": "https://dribbble.com/Tusk", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/283823/avatars/normal/c71f583fd2f781e48da28697c6ec2211.jpg?1456193406", "bio": "", "location": "Chicago", "links": { }, "buckets_count": 0, "comments_received_count": 1118, "followers_count": 5013, "followings_count": 812, "likes_count": 2295, "likes_received_count": 45133, "projects_count": 1, "rebounds_received_count": 214, "shots_count": 282, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/283823/buckets", "followers_url": "https://api.dribbble.com/v1/users/283823/followers", "following_url": "https://api.dribbble.com/v1/users/283823/following", "likes_url": "https://api.dribbble.com/v1/users/283823/likes", "projects_url": "https://api.dribbble.com/v1/users/283823/projects", "shots_url": "https://api.dribbble.com/v1/users/283823/shots", "teams_url": "https://api.dribbble.com/v1/users/283823/teams", "created_at": "2013-02-17T16:32:29Z", "updated_at": "2016-03-29T15:55:23Z" }, "team": null }, { "id": 2619378, "title": "Infinite Coffee", "description": "

It's Monday, I need coffee. Forever.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee_teaser.jpg" }, "views_count": 1301, "likes_count": 146, "comments_count": 6, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 2, "created_at": "2016-03-29T17:11:50Z", "updated_at": "2016-03-29T17:18:17Z", "html_url": "https://dribbble.com/shots/2619378-Infinite-Coffee", "attachments_url": "https://api.dribbble.com/v1/shots/2619378/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619378/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619378/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619378/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619378/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619378/rebounds", "animated": false, "tags": [ "8", "coffee", "cup", "food", "geometric", "illustration", "infinite", "kite", "liquid", "mug", "stroke" ], "user": { "id": 60266, "name": "Gustavo Zambelli", "username": "zamax", "html_url": "https://dribbble.com/zamax", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/60266/avatars/normal/83d4ac61d50bf5b2fedc9f9cc45a62d9.png?1453312126", "bio": "Hi, I'm Lead of illustration at @aerolab & Superman at @RicosQuesos", "location": "Neuquén, Argentina.", "links": { "web": "http://zamax.tumblr.com", "twitter": "https://twitter.com/zamax4" }, "buckets_count": 19, "comments_received_count": 1645, "followers_count": 4198, "followings_count": 1253, "likes_count": 8828, "likes_received_count": 36018, "projects_count": 4, "rebounds_received_count": 133, "shots_count": 305, "teams_count": 4, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/60266/buckets", "followers_url": "https://api.dribbble.com/v1/users/60266/followers", "following_url": "https://api.dribbble.com/v1/users/60266/following", "likes_url": "https://api.dribbble.com/v1/users/60266/likes", "projects_url": "https://api.dribbble.com/v1/users/60266/projects", "shots_url": "https://api.dribbble.com/v1/users/60266/shots", "teams_url": "https://api.dribbble.com/v1/users/60266/teams", "created_at": "2011-09-07T19:27:31Z", "updated_at": "2016-03-29T17:18:17Z" }, "team": { "id": 171431, "name": "Aerolab", "username": "aerolab", "html_url": "https://dribbble.com/aerolab", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/171431/avatars/normal/1283d5fbcd21a809d0cdc2f96a560096.png?1458077891", "bio": "We design and develop beautiful digital products for startups and leading brands.", "location": "Buenos Aires - San Francisco", "links": { "web": "http://aerolab.co", "twitter": "https://twitter.com/aerolab" }, "buckets_count": 5, "comments_received_count": 157, "followers_count": 3845, "followings_count": 128, "likes_count": 4228, "likes_received_count": 2121, "projects_count": 24, "rebounds_received_count": 2, "shots_count": 579, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/171431/buckets", "followers_url": "https://api.dribbble.com/v1/users/171431/followers", "following_url": "https://api.dribbble.com/v1/users/171431/following", "likes_url": "https://api.dribbble.com/v1/users/171431/likes", "projects_url": "https://api.dribbble.com/v1/users/171431/projects", "shots_url": "https://api.dribbble.com/v1/users/171431/shots", "created_at": "2012-07-04T02:31:07Z", "updated_at": "2016-03-29T17:18:17Z", "members_count": 21, "members_url": "https://api.dribbble.com/v1/teams/171431/members", "team_shots_url": "https://api.dribbble.com/v1/teams/171431/shots" } }, { "id": 2619645, "title": "Hello, Is It Me You're Looking For?", "description": "

I had the privilege of getting to collaborate with @Jordan Wade on a hero illustration for his SVG post. And let me tell you, watching your work come alive with CSS and JS is pretty much the jam.

\n\n

Check it out all alive n' stuff!

\n\n

Go read about why you should learn more about SVG for the web.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello_teaser.png" }, "views_count": 1771, "likes_count": 146, "comments_count": 2, "attachments_count": 0, "rebounds_count": 1, "buckets_count": 2, "created_at": "2016-03-29T19:12:57Z", "updated_at": "2016-03-29T20:26:49Z", "html_url": "https://dribbble.com/shots/2619645-Hello-Is-It-Me-You-re-Looking-For", "attachments_url": "https://api.dribbble.com/v1/shots/2619645/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619645/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619645/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619645/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619645/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619645/rebounds", "animated": false, "tags": [ "hello" ], "user": { "id": 13774, "name": "Justin Mezzell", "username": "JustinMezzell", "html_url": "https://dribbble.com/JustinMezzell", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/13774/avatars/normal/Me_Web.jpg?1380768479", "bio": "Designer? Illustrator? Why not. Directing Art at @codeschool.", "location": "Orlando, FL", "links": { "web": "http://justinmezzell.com/", "twitter": "https://twitter.com/JustinMezzell" }, "buckets_count": 0, "comments_received_count": 5736, "followers_count": 31449, "followings_count": 713, "likes_count": 5548, "likes_received_count": 113425, "projects_count": 0, "rebounds_received_count": 55, "shots_count": 312, "teams_count": 4, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/13774/buckets", "followers_url": "https://api.dribbble.com/v1/users/13774/followers", "following_url": "https://api.dribbble.com/v1/users/13774/following", "likes_url": "https://api.dribbble.com/v1/users/13774/likes", "projects_url": "https://api.dribbble.com/v1/users/13774/projects", "shots_url": "https://api.dribbble.com/v1/users/13774/shots", "teams_url": "https://api.dribbble.com/v1/users/13774/teams", "created_at": "2011-01-26T06:58:50Z", "updated_at": "2016-03-29T20:26:49Z" }, "team": { "id": 333539, "name": "Code School", "username": "codeschool", "html_url": "https://dribbble.com/codeschool", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/333539/avatars/normal/329ac818d30ca1a7b900c09b105ce277.jpg?1410890340", "bio": "Code School teaches web technologies in the comfort of your browser with video lessons, coding challenges, and screencasts.", "location": "Orlando, FL", "links": { "web": "http://codeschool.com", "twitter": "https://twitter.com/codeschool" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 3057, "followings_count": 13, "likes_count": 1, "likes_received_count": 0, "projects_count": 0, "rebounds_received_count": 0, "shots_count": 154, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/333539/buckets", "followers_url": "https://api.dribbble.com/v1/users/333539/followers", "following_url": "https://api.dribbble.com/v1/users/333539/following", "likes_url": "https://api.dribbble.com/v1/users/333539/likes", "projects_url": "https://api.dribbble.com/v1/users/333539/projects", "shots_url": "https://api.dribbble.com/v1/users/333539/shots", "created_at": "2013-05-15T21:37:44Z", "updated_at": "2016-03-29T20:26:49Z", "members_count": 10, "members_url": "https://api.dribbble.com/v1/teams/333539/members", "team_shots_url": "https://api.dribbble.com/v1/teams/333539/shots" } }, { "id": 2619181, "title": "Costa Rica", "description": "

Shirt graphic for offsite meeting in Costa Rica.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa_teaser.png" }, "views_count": 1261, "likes_count": 136, "comments_count": 7, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T15:48:25Z", "updated_at": "2016-03-29T15:49:13Z", "html_url": "https://dribbble.com/shots/2619181-Costa-Rica", "attachments_url": "https://api.dribbble.com/v1/shots/2619181/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619181/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619181/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619181/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619181/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619181/rebounds", "animated": false, "tags": [ "bird", "costa rica", "design", "illustration", "leaf", "toucan", "tropical" ], "user": { "id": 21030, "name": "Trevor Basset", "username": "trevorbasset", "html_url": "https://dribbble.com/trevorbasset", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/21030/avatars/normal/e9907b8b54ea842b30c5787ef95acc3a.png?1426787498", "bio": "Design, art direction, illustration, birds. ", "location": "Seattle, WA", "links": { "web": "http://www.trevorbasset.com", "twitter": "https://twitter.com/trevorbasset" }, "buckets_count": 0, "comments_received_count": 244, "followers_count": 1169, "followings_count": 367, "likes_count": 1204, "likes_received_count": 3660, "projects_count": 0, "rebounds_received_count": 4, "shots_count": 85, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/21030/buckets", "followers_url": "https://api.dribbble.com/v1/users/21030/followers", "following_url": "https://api.dribbble.com/v1/users/21030/following", "likes_url": "https://api.dribbble.com/v1/users/21030/likes", "projects_url": "https://api.dribbble.com/v1/users/21030/projects", "shots_url": "https://api.dribbble.com/v1/users/21030/shots", "teams_url": "https://api.dribbble.com/v1/users/21030/teams", "created_at": "2011-03-03T20:05:14Z", "updated_at": "2016-03-30T04:08:03Z" }, "team": null }, { "id": 2619381, "title": "Seaborn Oyster Co.", "description": null, "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_teaser.jpg" }, "views_count": 2166, "likes_count": 235, "comments_count": 2, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 11, "created_at": "2016-03-29T17:12:41Z", "updated_at": "2016-03-29T17:12:53Z", "html_url": "https://dribbble.com/shots/2619381-Seaborn-Oyster-Co", "attachments_url": "https://api.dribbble.com/v1/shots/2619381/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619381/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619381/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619381/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619381/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619381/rebounds", "animated": false, "tags": [ "charleston", "company", "ocean", "oyster", "sea", "wave" ], "user": { "id": 52758, "name": "Jay Fletcher", "username": "jfletcherdesign", "html_url": "https://dribbble.com/jfletcherdesign", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/52758/avatars/normal/J_FLETCHER_DESIGN_LOGO-01.jpg?1401983283", "bio": "", "location": "Charleston, SC", "links": { "web": "http://www.jfletcherdesign.com", "twitter": "https://twitter.com/jfletcherdesign" }, "buckets_count": 0, "comments_received_count": 5239, "followers_count": 13803, "followings_count": 558, "likes_count": 6531, "likes_received_count": 104895, "projects_count": 10, "rebounds_received_count": 325, "shots_count": 481, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/52758/buckets", "followers_url": "https://api.dribbble.com/v1/users/52758/followers", "following_url": "https://api.dribbble.com/v1/users/52758/following", "likes_url": "https://api.dribbble.com/v1/users/52758/likes", "projects_url": "https://api.dribbble.com/v1/users/52758/projects", "shots_url": "https://api.dribbble.com/v1/users/52758/shots", "teams_url": "https://api.dribbble.com/v1/users/52758/teams", "created_at": "2011-08-13T23:30:38Z", "updated_at": "2016-03-29T17:12:53Z" }, "team": null }, { "id": 2619494, "title": "Mystery Project 72.1", "description": "

We're excited to be onboard for a new year of Outside Lands festival branding! Stay tuned for weekly updates including Ranger Dave's new patch series, the 2016 lineup, and more!

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30_teaser.jpg" }, "views_count": 2304, "likes_count": 252, "comments_count": 4, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 11, "created_at": "2016-03-29T18:05:57Z", "updated_at": "2016-03-29T18:07:21Z", "html_url": "https://dribbble.com/shots/2619494-Mystery-Project-72-1", "attachments_url": "https://api.dribbble.com/v1/shots/2619494/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619494/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619494/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619494/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619494/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619494/rebounds", "rebound_source_url": "https://api.dribbble.com/v1/shots/2454166", "animated": false, "tags": [ "badge", "branding", "bridge", "city", "dan kuhlken", "dkng", "logo", "nathan goldman", "patch", "san francisco", "vector" ], "user": { "id": 31348, "name": "DKNG", "username": "DKNG", "html_url": "https://dribbble.com/DKNG", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/31348/avatars/original/dkng_twitter.jpg?1305140827", "bio": "Established in 2005, DKNG is a design studio based in Los Angeles, California with a focus on the music and entertainment industries.", "location": "Los Angeles, CA", "links": { "web": "http://www.dkngstudios.com", "twitter": "https://twitter.com/DKNGstudios" }, "buckets_count": 0, "comments_received_count": 5274, "followers_count": 24704, "followings_count": 256, "likes_count": 197, "likes_received_count": 125646, "projects_count": 47, "rebounds_received_count": 324, "shots_count": 479, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/31348/buckets", "followers_url": "https://api.dribbble.com/v1/users/31348/followers", "following_url": "https://api.dribbble.com/v1/users/31348/following", "likes_url": "https://api.dribbble.com/v1/users/31348/likes", "projects_url": "https://api.dribbble.com/v1/users/31348/projects", "shots_url": "https://api.dribbble.com/v1/users/31348/shots", "teams_url": "https://api.dribbble.com/v1/users/31348/teams", "created_at": "2011-04-28T20:48:48Z", "updated_at": "2016-03-29T18:07:21Z" }, "team": null }, { "id": 2619183, "title": "Bonsai", "description": null, "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai_teaser.png" }, "views_count": 2143, "likes_count": 259, "comments_count": 11, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 18, "created_at": "2016-03-29T15:48:38Z", "updated_at": "2016-03-29T15:49:04Z", "html_url": "https://dribbble.com/shots/2619183-Bonsai", "attachments_url": "https://api.dribbble.com/v1/shots/2619183/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619183/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619183/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619183/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619183/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619183/rebounds", "animated": false, "tags": [ "bonsai", "illustration", "nature", "plant", "pot", "tree", "zen" ], "user": { "id": 44323, "name": "Zach Roszczewski", "username": "ZachRoszczewski", "html_url": "https://dribbble.com/ZachRoszczewski", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/44323/avatars/normal/18f509c70a25627b40d5e3499b1cba2f.png?1419195740", "bio": "Iconographer & Illustrator. Creator of www.flaticons.co & www.mojiapp.net.", "location": "Encinitas, California", "links": { "web": "http://zachroszczewski.com", "twitter": "https://twitter.com/ZachRoszczewski" }, "buckets_count": 10, "comments_received_count": 1682, "followers_count": 9067, "followings_count": 1541, "likes_count": 14094, "likes_received_count": 34409, "projects_count": 7, "rebounds_received_count": 14, "shots_count": 113, "teams_count": 2, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/44323/buckets", "followers_url": "https://api.dribbble.com/v1/users/44323/followers", "following_url": "https://api.dribbble.com/v1/users/44323/following", "likes_url": "https://api.dribbble.com/v1/users/44323/likes", "projects_url": "https://api.dribbble.com/v1/users/44323/projects", "shots_url": "https://api.dribbble.com/v1/users/44323/shots", "teams_url": "https://api.dribbble.com/v1/users/44323/teams", "created_at": "2011-07-07T14:49:07Z", "updated_at": "2016-03-29T15:49:04Z" }, "team": null }, { "id": 2619255, "title": "Canvas—A new space for big ideas", "description": "

A month ago the our team launched Canvas, a product for brands to tell their story and highlight products. It's been amazing to see your excitement for the creative possibilities and we can't wait to see how you use it.

\n\n

One of the best aspects of working on ads at Facebook is striving to find the sweet spot between the goals of our advertisers and those of people browsing their feed. Canvas allows businesses to create a more compelling experience for people, and in turn provides people with an ad they actually enjoy. Stay tuned for more :)

\n\n

If your interested in learning more about Canvas, or building one, you should check out https://canvas.facebook.com/\n
To learn more about our process check out Jaime Rovira's medium post https://medium.com/facebook-design/canvas-how-we-crafted-facebook-s-new-immersive-ads-696870e66b3f#.jy9w9l51m

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble.gif", "normal": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble_1x.gif", "teaser": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble_teaser.gif" }, "views_count": 3502, "likes_count": 262, "comments_count": 9, "attachments_count": 2, "rebounds_count": 0, "buckets_count": 12, "created_at": "2016-03-29T16:18:33Z", "updated_at": "2016-03-29T16:19:50Z", "html_url": "https://dribbble.com/shots/2619255-Canvas-A-new-space-for-big-ideas", "attachments_url": "https://api.dribbble.com/v1/shots/2619255/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619255/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619255/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619255/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619255/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619255/rebounds", "animated": true, "tags": [ "android", "animation", "creative", "illustration", "ios", "mobile", "tool" ], "user": { "id": 476251, "name": "ali griffin", "username": "aligdanger", "html_url": "https://dribbble.com/aligdanger", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/476251/avatars/normal/ali.png?1404762398", "bio": "Designing product @Facebook", "location": "San Francisco, CA", "links": { "twitter": "https://twitter.com/aligdanger" }, "buckets_count": 0, "comments_received_count": 203, "followers_count": 513, "followings_count": 289, "likes_count": 1302, "likes_received_count": 2487, "projects_count": 3, "rebounds_received_count": 9, "shots_count": 22, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/476251/buckets", "followers_url": "https://api.dribbble.com/v1/users/476251/followers", "following_url": "https://api.dribbble.com/v1/users/476251/following", "likes_url": "https://api.dribbble.com/v1/users/476251/likes", "projects_url": "https://api.dribbble.com/v1/users/476251/projects", "shots_url": "https://api.dribbble.com/v1/users/476251/shots", "teams_url": "https://api.dribbble.com/v1/users/476251/teams", "created_at": "2014-01-10T18:37:14Z", "updated_at": "2016-03-30T04:07:49Z" }, "team": { "id": 333588, "name": "Facebook", "username": "Facebook", "html_url": "https://dribbble.com/Facebook", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/333588/avatars/normal/9a9d5301e289975fa16abd070f1615c0.png?1440610176", "bio": "", "location": "1 Hacker Way, Menlo Park, CA", "links": { "web": "https://www.facebook.com/design", "twitter": "https://twitter.com/facebookdesign" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 14039, "followings_count": 0, "likes_count": 2, "likes_received_count": 0, "projects_count": 0, "rebounds_received_count": 0, "shots_count": 121, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/333588/buckets", "followers_url": "https://api.dribbble.com/v1/users/333588/followers", "following_url": "https://api.dribbble.com/v1/users/333588/following", "likes_url": "https://api.dribbble.com/v1/users/333588/likes", "projects_url": "https://api.dribbble.com/v1/users/333588/projects", "shots_url": "https://api.dribbble.com/v1/users/333588/shots", "created_at": "2013-05-15T23:13:37Z", "updated_at": "2016-03-30T04:07:49Z", "members_count": 39, "members_url": "https://api.dribbble.com/v1/teams/333588/members", "team_shots_url": "https://api.dribbble.com/v1/teams/333588/shots" } }, { "id": 2619346, "title": "Sunset", "description": "

Baker Beach sunset from this weekend.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset_teaser.png" }, "views_count": 2897, "likes_count": 231, "comments_count": 3, "attachments_count": 1, "rebounds_count": 0, "buckets_count": 6, "created_at": "2016-03-29T16:55:27Z", "updated_at": "2016-03-29T16:56:47Z", "html_url": "https://dribbble.com/shots/2619346-Sunset", "attachments_url": "https://api.dribbble.com/v1/shots/2619346/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619346/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619346/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619346/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619346/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619346/rebounds", "animated": false, "tags": [ "beach", "cartoon", "comics", "hand-darwn", "illustration", "nature", "sketch", "sunset" ], "user": { "id": 3460, "name": "Ryan Putnam", "username": "RypeArts", "html_url": "https://dribbble.com/RypeArts", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/3460/avatars/normal/4ed7a7a4737e971e3fa37f0705f5cc51.png?1457564367", "bio": "designer, illustrator, potter, and father", "location": "San Francisco, CA", "links": { "web": "http://ryanputn.am", "twitter": "https://twitter.com/RypeArts" }, "buckets_count": 3, "comments_received_count": 9722, "followers_count": 46667, "followings_count": 518, "likes_count": 10207, "likes_received_count": 211321, "projects_count": 34, "rebounds_received_count": 373, "shots_count": 589, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/3460/buckets", "followers_url": "https://api.dribbble.com/v1/users/3460/followers", "following_url": "https://api.dribbble.com/v1/users/3460/following", "likes_url": "https://api.dribbble.com/v1/users/3460/likes", "projects_url": "https://api.dribbble.com/v1/users/3460/projects", "shots_url": "https://api.dribbble.com/v1/users/3460/shots", "teams_url": "https://api.dribbble.com/v1/users/3460/teams", "created_at": "2010-07-16T12:48:16Z", "updated_at": "2016-03-29T16:56:47Z" }, "team": null }, { "id": 2619340, "title": "Skies Like These ", "description": "

In anticipation for their release of the paperback version of the book, Skies Like These, Macmillan commissioned us to redesign the cover artwork.

\n\n

The story is about a twelve-year-old girl name Jade who is sent to spend the summer with her aunt in Wyoming by her parents. She meets a rebellious boy who called himself Roy Parker, after the legendary Butch Cassidy. Jade tries to be a good friend Roy, but worries about the trouble he might get her into while he tries to plan stunts worthy of Butch Cassidy himself.\n

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble_teaser.png" }, "views_count": 1548, "likes_count": 177, "comments_count": 5, "attachments_count": 1, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T16:50:48Z", "updated_at": "2016-03-29T16:53:16Z", "html_url": "https://dribbble.com/shots/2619340-Skies-Like-These", "attachments_url": "https://api.dribbble.com/v1/shots/2619340/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619340/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619340/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619340/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619340/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619340/rebounds", "animated": false, "tags": [ "book", "book cover", "cover artwork", "cover design", "cowboy hat", "illustration", "mountain", "planets", "sky", "stars" ], "user": { "id": 44585, "name": "Brad Woodard", "username": "bradwwoodard", "html_url": "https://dribbble.com/bradwwoodard", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/44585/avatars/normal/593686b9b9c0d2b6a496d8404f24ce1f.png?1444862250", "bio": "Designer • Illustrator • Braver of the Woods", "location": "Austin, TX", "links": { "web": "http://www.bravethewoods.com/", "twitter": "https://twitter.com/brave_the_woods" }, "buckets_count": 1, "comments_received_count": 2598, "followers_count": 8556, "followings_count": 412, "likes_count": 2285, "likes_received_count": 45938, "projects_count": 21, "rebounds_received_count": 16, "shots_count": 324, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/44585/buckets", "followers_url": "https://api.dribbble.com/v1/users/44585/followers", "following_url": "https://api.dribbble.com/v1/users/44585/following", "likes_url": "https://api.dribbble.com/v1/users/44585/likes", "projects_url": "https://api.dribbble.com/v1/users/44585/projects", "shots_url": "https://api.dribbble.com/v1/users/44585/shots", "teams_url": "https://api.dribbble.com/v1/users/44585/teams", "created_at": "2011-07-08T15:47:58Z", "updated_at": "2016-03-29T16:53:16Z" }, "team": null }, { "id": 2619544, "title": "Robinhood", "description": "

Robinhood integrations illustration.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01_teaser.png" }, "views_count": 1530, "likes_count": 177, "comments_count": 6, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T18:24:59Z", "updated_at": "2016-03-29T18:26:47Z", "html_url": "https://dribbble.com/shots/2619544-Robinhood", "attachments_url": "https://api.dribbble.com/v1/shots/2619544/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619544/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619544/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619544/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619544/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619544/rebounds", "animated": false, "tags": [ "chart", "finance", "illustration", "money", "stock" ], "user": { "id": 4598, "name": "Ty Wilkins", "username": "tywilkins", "html_url": "https://dribbble.com/tywilkins", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/4598/avatars/normal/fox2.jpg?1391573055", "bio": "hello@tywilkins.com", "location": "San Francisco, CA", "links": { "web": "http://www.tywilkins.com", "twitter": "https://twitter.com/tywilkins" }, "buckets_count": 0, "comments_received_count": 1080, "followers_count": 8222, "followings_count": 527, "likes_count": 0, "likes_received_count": 21359, "projects_count": 8, "rebounds_received_count": 0, "shots_count": 97, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/4598/buckets", "followers_url": "https://api.dribbble.com/v1/users/4598/followers", "following_url": "https://api.dribbble.com/v1/users/4598/following", "likes_url": "https://api.dribbble.com/v1/users/4598/likes", "projects_url": "https://api.dribbble.com/v1/users/4598/projects", "shots_url": "https://api.dribbble.com/v1/users/4598/shots", "teams_url": "https://api.dribbble.com/v1/users/4598/teams", "created_at": "2010-09-30T20:31:02Z", "updated_at": "2016-03-29T18:27:54Z" }, "team": null }, { "id": 2619187, "title": "Confidential iPad App part #2", "description": "

Over the holidays, Rally built an iPad app for a confidential client and conference. This is video directly from interacting with the native iOS app.

\n\n

Myself, @Geof Crowl, and Wes tackled the project in just 15 days. It was intense but fun. Geof and I did the design and helped with layout in Xcode using Nibs. Wes built the globe and the data visualizations from a json file using our own Open GL globe library we've been building on an off for the past year.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally.gif", "normal": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally_1x.gif", "teaser": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally_teaser.gif" }, "views_count": 3205, "likes_count": 183, "comments_count": 9, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 20, "created_at": "2016-03-29T15:50:05Z", "updated_at": "2016-03-29T15:51:33Z", "html_url": "https://dribbble.com/shots/2619187-Confidential-iPad-App-part-2", "attachments_url": "https://api.dribbble.com/v1/shots/2619187/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619187/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619187/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619187/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619187/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619187/rebounds", "animated": true, "tags": [ ], "user": { "id": 3816, "name": "Ben Cline", "username": "letsgorally", "html_url": "https://dribbble.com/letsgorally", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/3816/avatars/normal/bb00fd14001a8cdd5e0e354df52a7fa4.png?1450769044", "bio": "@RALLY Co-Founder / Designer", "location": "Salt Lake City", "links": { "web": "http://beta.rallyinteractive.com", "twitter": "https://twitter.com/yocline" }, "buckets_count": 3, "comments_received_count": 4525, "followers_count": 30105, "followings_count": 241, "likes_count": 6878, "likes_received_count": 87892, "projects_count": 10, "rebounds_received_count": 28, "shots_count": 257, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/3816/buckets", "followers_url": "https://api.dribbble.com/v1/users/3816/followers", "following_url": "https://api.dribbble.com/v1/users/3816/following", "likes_url": "https://api.dribbble.com/v1/users/3816/likes", "projects_url": "https://api.dribbble.com/v1/users/3816/projects", "shots_url": "https://api.dribbble.com/v1/users/3816/shots", "teams_url": "https://api.dribbble.com/v1/users/3816/teams", "created_at": "2010-07-30T17:30:31Z", "updated_at": "2016-03-29T15:51:33Z" }, "team": { "id": 559317, "name": "RALLY", "username": "rally", "html_url": "https://dribbble.com/rally", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/559317/avatars/normal/rally_logo.png?1398641637", "bio": "Interactive Studio. Design & Development", "location": "Salt Lake City", "links": { "web": "http://beta.rallyinteractive.com", "twitter": "https://twitter.com/letsgorally" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 8281, "followings_count": 6, "likes_count": 73, "likes_received_count": 0, "projects_count": 14, "rebounds_received_count": 0, "shots_count": 273, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/559317/buckets", "followers_url": "https://api.dribbble.com/v1/users/559317/followers", "following_url": "https://api.dribbble.com/v1/users/559317/following", "likes_url": "https://api.dribbble.com/v1/users/559317/likes", "projects_url": "https://api.dribbble.com/v1/users/559317/projects", "shots_url": "https://api.dribbble.com/v1/users/559317/shots", "created_at": "2014-04-27T23:31:42Z", "updated_at": "2016-03-29T15:51:33Z", "members_count": 5, "members_url": "https://api.dribbble.com/v1/teams/559317/members", "team_shots_url": "https://api.dribbble.com/v1/teams/559317/shots" } }, { "id": 2619200, "title": "Eilean Donan Castle", "description": "

Day 209/365

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01_teaser.jpg" }, "views_count": 1434, "likes_count": 162, "comments_count": 4, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T15:54:42Z", "updated_at": "2016-03-29T15:55:23Z", "html_url": "https://dribbble.com/shots/2619200-Eilean-Donan-Castle", "attachments_url": "https://api.dribbble.com/v1/shots/2619200/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619200/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619200/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619200/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619200/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619200/rebounds", "rebound_source_url": "https://api.dribbble.com/v1/shots/2614735", "animated": false, "tags": [ "icon", "illustration", "lake", "scotland", "vector" ], "user": { "id": 283823, "name": "Scott Tusk", "username": "Tusk", "html_url": "https://dribbble.com/Tusk", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/283823/avatars/normal/c71f583fd2f781e48da28697c6ec2211.jpg?1456193406", "bio": "", "location": "Chicago", "links": { }, "buckets_count": 0, "comments_received_count": 1118, "followers_count": 5013, "followings_count": 812, "likes_count": 2295, "likes_received_count": 45133, "projects_count": 1, "rebounds_received_count": 214, "shots_count": 282, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/283823/buckets", "followers_url": "https://api.dribbble.com/v1/users/283823/followers", "following_url": "https://api.dribbble.com/v1/users/283823/following", "likes_url": "https://api.dribbble.com/v1/users/283823/likes", "projects_url": "https://api.dribbble.com/v1/users/283823/projects", "shots_url": "https://api.dribbble.com/v1/users/283823/shots", "teams_url": "https://api.dribbble.com/v1/users/283823/teams", "created_at": "2013-02-17T16:32:29Z", "updated_at": "2016-03-29T15:55:23Z" }, "team": null }, { "id": 2619378, "title": "Infinite Coffee", "description": "

It's Monday, I need coffee. Forever.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee_teaser.jpg" }, "views_count": 1301, "likes_count": 146, "comments_count": 6, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 2, "created_at": "2016-03-29T17:11:50Z", "updated_at": "2016-03-29T17:18:17Z", "html_url": "https://dribbble.com/shots/2619378-Infinite-Coffee", "attachments_url": "https://api.dribbble.com/v1/shots/2619378/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619378/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619378/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619378/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619378/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619378/rebounds", "animated": false, "tags": [ "8", "coffee", "cup", "food", "geometric", "illustration", "infinite", "kite", "liquid", "mug", "stroke" ], "user": { "id": 60266, "name": "Gustavo Zambelli", "username": "zamax", "html_url": "https://dribbble.com/zamax", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/60266/avatars/normal/83d4ac61d50bf5b2fedc9f9cc45a62d9.png?1453312126", "bio": "Hi, I'm Lead of illustration at @aerolab & Superman at @RicosQuesos", "location": "Neuquén, Argentina.", "links": { "web": "http://zamax.tumblr.com", "twitter": "https://twitter.com/zamax4" }, "buckets_count": 19, "comments_received_count": 1645, "followers_count": 4198, "followings_count": 1253, "likes_count": 8828, "likes_received_count": 36018, "projects_count": 4, "rebounds_received_count": 133, "shots_count": 305, "teams_count": 4, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/60266/buckets", "followers_url": "https://api.dribbble.com/v1/users/60266/followers", "following_url": "https://api.dribbble.com/v1/users/60266/following", "likes_url": "https://api.dribbble.com/v1/users/60266/likes", "projects_url": "https://api.dribbble.com/v1/users/60266/projects", "shots_url": "https://api.dribbble.com/v1/users/60266/shots", "teams_url": "https://api.dribbble.com/v1/users/60266/teams", "created_at": "2011-09-07T19:27:31Z", "updated_at": "2016-03-29T17:18:17Z" }, "team": { "id": 171431, "name": "Aerolab", "username": "aerolab", "html_url": "https://dribbble.com/aerolab", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/171431/avatars/normal/1283d5fbcd21a809d0cdc2f96a560096.png?1458077891", "bio": "We design and develop beautiful digital products for startups and leading brands.", "location": "Buenos Aires - San Francisco", "links": { "web": "http://aerolab.co", "twitter": "https://twitter.com/aerolab" }, "buckets_count": 5, "comments_received_count": 157, "followers_count": 3845, "followings_count": 128, "likes_count": 4228, "likes_received_count": 2121, "projects_count": 24, "rebounds_received_count": 2, "shots_count": 579, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/171431/buckets", "followers_url": "https://api.dribbble.com/v1/users/171431/followers", "following_url": "https://api.dribbble.com/v1/users/171431/following", "likes_url": "https://api.dribbble.com/v1/users/171431/likes", "projects_url": "https://api.dribbble.com/v1/users/171431/projects", "shots_url": "https://api.dribbble.com/v1/users/171431/shots", "created_at": "2012-07-04T02:31:07Z", "updated_at": "2016-03-29T17:18:17Z", "members_count": 21, "members_url": "https://api.dribbble.com/v1/teams/171431/members", "team_shots_url": "https://api.dribbble.com/v1/teams/171431/shots" } }, { "id": 2619645, "title": "Hello, Is It Me You're Looking For?", "description": "

I had the privilege of getting to collaborate with @Jordan Wade on a hero illustration for his SVG post. And let me tell you, watching your work come alive with CSS and JS is pretty much the jam.

\n\n

Check it out all alive n' stuff!

\n\n

Go read about why you should learn more about SVG for the web.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello_teaser.png" }, "views_count": 1771, "likes_count": 146, "comments_count": 2, "attachments_count": 0, "rebounds_count": 1, "buckets_count": 2, "created_at": "2016-03-29T19:12:57Z", "updated_at": "2016-03-29T20:26:49Z", "html_url": "https://dribbble.com/shots/2619645-Hello-Is-It-Me-You-re-Looking-For", "attachments_url": "https://api.dribbble.com/v1/shots/2619645/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619645/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619645/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619645/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619645/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619645/rebounds", "animated": false, "tags": [ "hello" ], "user": { "id": 13774, "name": "Justin Mezzell", "username": "JustinMezzell", "html_url": "https://dribbble.com/JustinMezzell", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/13774/avatars/normal/Me_Web.jpg?1380768479", "bio": "Designer? Illustrator? Why not. Directing Art at @codeschool.", "location": "Orlando, FL", "links": { "web": "http://justinmezzell.com/", "twitter": "https://twitter.com/JustinMezzell" }, "buckets_count": 0, "comments_received_count": 5736, "followers_count": 31449, "followings_count": 713, "likes_count": 5548, "likes_received_count": 113425, "projects_count": 0, "rebounds_received_count": 55, "shots_count": 312, "teams_count": 4, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/13774/buckets", "followers_url": "https://api.dribbble.com/v1/users/13774/followers", "following_url": "https://api.dribbble.com/v1/users/13774/following", "likes_url": "https://api.dribbble.com/v1/users/13774/likes", "projects_url": "https://api.dribbble.com/v1/users/13774/projects", "shots_url": "https://api.dribbble.com/v1/users/13774/shots", "teams_url": "https://api.dribbble.com/v1/users/13774/teams", "created_at": "2011-01-26T06:58:50Z", "updated_at": "2016-03-29T20:26:49Z" }, "team": { "id": 333539, "name": "Code School", "username": "codeschool", "html_url": "https://dribbble.com/codeschool", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/333539/avatars/normal/329ac818d30ca1a7b900c09b105ce277.jpg?1410890340", "bio": "Code School teaches web technologies in the comfort of your browser with video lessons, coding challenges, and screencasts.", "location": "Orlando, FL", "links": { "web": "http://codeschool.com", "twitter": "https://twitter.com/codeschool" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 3057, "followings_count": 13, "likes_count": 1, "likes_received_count": 0, "projects_count": 0, "rebounds_received_count": 0, "shots_count": 154, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/333539/buckets", "followers_url": "https://api.dribbble.com/v1/users/333539/followers", "following_url": "https://api.dribbble.com/v1/users/333539/following", "likes_url": "https://api.dribbble.com/v1/users/333539/likes", "projects_url": "https://api.dribbble.com/v1/users/333539/projects", "shots_url": "https://api.dribbble.com/v1/users/333539/shots", "created_at": "2013-05-15T21:37:44Z", "updated_at": "2016-03-29T20:26:49Z", "members_count": 10, "members_url": "https://api.dribbble.com/v1/teams/333539/members", "team_shots_url": "https://api.dribbble.com/v1/teams/333539/shots" } }, { "id": 2619181, "title": "Costa Rica", "description": "

Shirt graphic for offsite meeting in Costa Rica.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa_teaser.png" }, "views_count": 1261, "likes_count": 136, "comments_count": 7, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T15:48:25Z", "updated_at": "2016-03-29T15:49:13Z", "html_url": "https://dribbble.com/shots/2619181-Costa-Rica", "attachments_url": "https://api.dribbble.com/v1/shots/2619181/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619181/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619181/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619181/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619181/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619181/rebounds", "animated": false, "tags": [ "bird", "costa rica", "design", "illustration", "leaf", "toucan", "tropical" ], "user": { "id": 21030, "name": "Trevor Basset", "username": "trevorbasset", "html_url": "https://dribbble.com/trevorbasset", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/21030/avatars/normal/e9907b8b54ea842b30c5787ef95acc3a.png?1426787498", "bio": "Design, art direction, illustration, birds. ", "location": "Seattle, WA", "links": { "web": "http://www.trevorbasset.com", "twitter": "https://twitter.com/trevorbasset" }, "buckets_count": 0, "comments_received_count": 244, "followers_count": 1169, "followings_count": 367, "likes_count": 1204, "likes_received_count": 3660, "projects_count": 0, "rebounds_received_count": 4, "shots_count": 85, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/21030/buckets", "followers_url": "https://api.dribbble.com/v1/users/21030/followers", "following_url": "https://api.dribbble.com/v1/users/21030/following", "likes_url": "https://api.dribbble.com/v1/users/21030/likes", "projects_url": "https://api.dribbble.com/v1/users/21030/projects", "shots_url": "https://api.dribbble.com/v1/users/21030/shots", "teams_url": "https://api.dribbble.com/v1/users/21030/teams", "created_at": "2011-03-03T20:05:14Z", "updated_at": "2016-03-30T04:08:03Z" }, "team": null }, { "id": 2619381, "title": "Seaborn Oyster Co.", "description": null, "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_teaser.jpg" }, "views_count": 2166, "likes_count": 235, "comments_count": 2, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 11, "created_at": "2016-03-29T17:12:41Z", "updated_at": "2016-03-29T17:12:53Z", "html_url": "https://dribbble.com/shots/2619381-Seaborn-Oyster-Co", "attachments_url": "https://api.dribbble.com/v1/shots/2619381/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619381/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619381/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619381/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619381/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619381/rebounds", "animated": false, "tags": [ "charleston", "company", "ocean", "oyster", "sea", "wave" ], "user": { "id": 52758, "name": "Jay Fletcher", "username": "jfletcherdesign", "html_url": "https://dribbble.com/jfletcherdesign", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/52758/avatars/normal/J_FLETCHER_DESIGN_LOGO-01.jpg?1401983283", "bio": "", "location": "Charleston, SC", "links": { "web": "http://www.jfletcherdesign.com", "twitter": "https://twitter.com/jfletcherdesign" }, "buckets_count": 0, "comments_received_count": 5239, "followers_count": 13803, "followings_count": 558, "likes_count": 6531, "likes_received_count": 104895, "projects_count": 10, "rebounds_received_count": 325, "shots_count": 481, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/52758/buckets", "followers_url": "https://api.dribbble.com/v1/users/52758/followers", "following_url": "https://api.dribbble.com/v1/users/52758/following", "likes_url": "https://api.dribbble.com/v1/users/52758/likes", "projects_url": "https://api.dribbble.com/v1/users/52758/projects", "shots_url": "https://api.dribbble.com/v1/users/52758/shots", "teams_url": "https://api.dribbble.com/v1/users/52758/teams", "created_at": "2011-08-13T23:30:38Z", "updated_at": "2016-03-29T17:12:53Z" }, "team": null }, { "id": 2619494, "title": "Mystery Project 72.1", "description": "

We're excited to be onboard for a new year of Outside Lands festival branding! Stay tuned for weekly updates including Ranger Dave's new patch series, the 2016 lineup, and more!

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/31348/screenshots/2619494/patches-30_teaser.jpg" }, "views_count": 2304, "likes_count": 252, "comments_count": 4, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 11, "created_at": "2016-03-29T18:05:57Z", "updated_at": "2016-03-29T18:07:21Z", "html_url": "https://dribbble.com/shots/2619494-Mystery-Project-72-1", "attachments_url": "https://api.dribbble.com/v1/shots/2619494/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619494/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619494/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619494/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619494/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619494/rebounds", "rebound_source_url": "https://api.dribbble.com/v1/shots/2454166", "animated": false, "tags": [ "badge", "branding", "bridge", "city", "dan kuhlken", "dkng", "logo", "nathan goldman", "patch", "san francisco", "vector" ], "user": { "id": 31348, "name": "DKNG", "username": "DKNG", "html_url": "https://dribbble.com/DKNG", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/31348/avatars/original/dkng_twitter.jpg?1305140827", "bio": "Established in 2005, DKNG is a design studio based in Los Angeles, California with a focus on the music and entertainment industries.", "location": "Los Angeles, CA", "links": { "web": "http://www.dkngstudios.com", "twitter": "https://twitter.com/DKNGstudios" }, "buckets_count": 0, "comments_received_count": 5274, "followers_count": 24704, "followings_count": 256, "likes_count": 197, "likes_received_count": 125646, "projects_count": 47, "rebounds_received_count": 324, "shots_count": 479, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/31348/buckets", "followers_url": "https://api.dribbble.com/v1/users/31348/followers", "following_url": "https://api.dribbble.com/v1/users/31348/following", "likes_url": "https://api.dribbble.com/v1/users/31348/likes", "projects_url": "https://api.dribbble.com/v1/users/31348/projects", "shots_url": "https://api.dribbble.com/v1/users/31348/shots", "teams_url": "https://api.dribbble.com/v1/users/31348/teams", "created_at": "2011-04-28T20:48:48Z", "updated_at": "2016-03-29T18:07:21Z" }, "team": null }, { "id": 2619183, "title": "Bonsai", "description": null, "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/44323/screenshots/2619183/bonsai_teaser.png" }, "views_count": 2143, "likes_count": 259, "comments_count": 11, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 18, "created_at": "2016-03-29T15:48:38Z", "updated_at": "2016-03-29T15:49:04Z", "html_url": "https://dribbble.com/shots/2619183-Bonsai", "attachments_url": "https://api.dribbble.com/v1/shots/2619183/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619183/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619183/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619183/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619183/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619183/rebounds", "animated": false, "tags": [ "bonsai", "illustration", "nature", "plant", "pot", "tree", "zen" ], "user": { "id": 44323, "name": "Zach Roszczewski", "username": "ZachRoszczewski", "html_url": "https://dribbble.com/ZachRoszczewski", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/44323/avatars/normal/18f509c70a25627b40d5e3499b1cba2f.png?1419195740", "bio": "Iconographer & Illustrator. Creator of www.flaticons.co & www.mojiapp.net.", "location": "Encinitas, California", "links": { "web": "http://zachroszczewski.com", "twitter": "https://twitter.com/ZachRoszczewski" }, "buckets_count": 10, "comments_received_count": 1682, "followers_count": 9067, "followings_count": 1541, "likes_count": 14094, "likes_received_count": 34409, "projects_count": 7, "rebounds_received_count": 14, "shots_count": 113, "teams_count": 2, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/44323/buckets", "followers_url": "https://api.dribbble.com/v1/users/44323/followers", "following_url": "https://api.dribbble.com/v1/users/44323/following", "likes_url": "https://api.dribbble.com/v1/users/44323/likes", "projects_url": "https://api.dribbble.com/v1/users/44323/projects", "shots_url": "https://api.dribbble.com/v1/users/44323/shots", "teams_url": "https://api.dribbble.com/v1/users/44323/teams", "created_at": "2011-07-07T14:49:07Z", "updated_at": "2016-03-29T15:49:04Z" }, "team": null }, { "id": 2619255, "title": "Canvas—A new space for big ideas", "description": "

A month ago the our team launched Canvas, a product for brands to tell their story and highlight products. It's been amazing to see your excitement for the creative possibilities and we can't wait to see how you use it.

\n\n

One of the best aspects of working on ads at Facebook is striving to find the sweet spot between the goals of our advertisers and those of people browsing their feed. Canvas allows businesses to create a more compelling experience for people, and in turn provides people with an ad they actually enjoy. Stay tuned for more :)

\n\n

If your interested in learning more about Canvas, or building one, you should check out https://canvas.facebook.com/\n
To learn more about our process check out Jaime Rovira's medium post https://medium.com/facebook-design/canvas-how-we-crafted-facebook-s-new-immersive-ads-696870e66b3f#.jy9w9l51m

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble.gif", "normal": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble_1x.gif", "teaser": "https://d13yacurqjgara.cloudfront.net/users/476251/screenshots/2619255/startdribbble_teaser.gif" }, "views_count": 3502, "likes_count": 262, "comments_count": 9, "attachments_count": 2, "rebounds_count": 0, "buckets_count": 12, "created_at": "2016-03-29T16:18:33Z", "updated_at": "2016-03-29T16:19:50Z", "html_url": "https://dribbble.com/shots/2619255-Canvas-A-new-space-for-big-ideas", "attachments_url": "https://api.dribbble.com/v1/shots/2619255/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619255/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619255/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619255/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619255/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619255/rebounds", "animated": true, "tags": [ "android", "animation", "creative", "illustration", "ios", "mobile", "tool" ], "user": { "id": 476251, "name": "ali griffin", "username": "aligdanger", "html_url": "https://dribbble.com/aligdanger", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/476251/avatars/normal/ali.png?1404762398", "bio": "Designing product @Facebook", "location": "San Francisco, CA", "links": { "twitter": "https://twitter.com/aligdanger" }, "buckets_count": 0, "comments_received_count": 203, "followers_count": 513, "followings_count": 289, "likes_count": 1302, "likes_received_count": 2487, "projects_count": 3, "rebounds_received_count": 9, "shots_count": 22, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/476251/buckets", "followers_url": "https://api.dribbble.com/v1/users/476251/followers", "following_url": "https://api.dribbble.com/v1/users/476251/following", "likes_url": "https://api.dribbble.com/v1/users/476251/likes", "projects_url": "https://api.dribbble.com/v1/users/476251/projects", "shots_url": "https://api.dribbble.com/v1/users/476251/shots", "teams_url": "https://api.dribbble.com/v1/users/476251/teams", "created_at": "2014-01-10T18:37:14Z", "updated_at": "2016-03-30T04:07:49Z" }, "team": { "id": 333588, "name": "Facebook", "username": "Facebook", "html_url": "https://dribbble.com/Facebook", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/333588/avatars/normal/9a9d5301e289975fa16abd070f1615c0.png?1440610176", "bio": "", "location": "1 Hacker Way, Menlo Park, CA", "links": { "web": "https://www.facebook.com/design", "twitter": "https://twitter.com/facebookdesign" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 14039, "followings_count": 0, "likes_count": 2, "likes_received_count": 0, "projects_count": 0, "rebounds_received_count": 0, "shots_count": 121, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/333588/buckets", "followers_url": "https://api.dribbble.com/v1/users/333588/followers", "following_url": "https://api.dribbble.com/v1/users/333588/following", "likes_url": "https://api.dribbble.com/v1/users/333588/likes", "projects_url": "https://api.dribbble.com/v1/users/333588/projects", "shots_url": "https://api.dribbble.com/v1/users/333588/shots", "created_at": "2013-05-15T23:13:37Z", "updated_at": "2016-03-30T04:07:49Z", "members_count": 39, "members_url": "https://api.dribbble.com/v1/teams/333588/members", "team_shots_url": "https://api.dribbble.com/v1/teams/333588/shots" } }, { "id": 2619346, "title": "Sunset", "description": "

Baker Beach sunset from this weekend.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/2619346/sunset_teaser.png" }, "views_count": 2897, "likes_count": 231, "comments_count": 3, "attachments_count": 1, "rebounds_count": 0, "buckets_count": 6, "created_at": "2016-03-29T16:55:27Z", "updated_at": "2016-03-29T16:56:47Z", "html_url": "https://dribbble.com/shots/2619346-Sunset", "attachments_url": "https://api.dribbble.com/v1/shots/2619346/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619346/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619346/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619346/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619346/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619346/rebounds", "animated": false, "tags": [ "beach", "cartoon", "comics", "hand-darwn", "illustration", "nature", "sketch", "sunset" ], "user": { "id": 3460, "name": "Ryan Putnam", "username": "RypeArts", "html_url": "https://dribbble.com/RypeArts", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/3460/avatars/normal/4ed7a7a4737e971e3fa37f0705f5cc51.png?1457564367", "bio": "designer, illustrator, potter, and father", "location": "San Francisco, CA", "links": { "web": "http://ryanputn.am", "twitter": "https://twitter.com/RypeArts" }, "buckets_count": 3, "comments_received_count": 9722, "followers_count": 46667, "followings_count": 518, "likes_count": 10207, "likes_received_count": 211321, "projects_count": 34, "rebounds_received_count": 373, "shots_count": 589, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/3460/buckets", "followers_url": "https://api.dribbble.com/v1/users/3460/followers", "following_url": "https://api.dribbble.com/v1/users/3460/following", "likes_url": "https://api.dribbble.com/v1/users/3460/likes", "projects_url": "https://api.dribbble.com/v1/users/3460/projects", "shots_url": "https://api.dribbble.com/v1/users/3460/shots", "teams_url": "https://api.dribbble.com/v1/users/3460/teams", "created_at": "2010-07-16T12:48:16Z", "updated_at": "2016-03-29T16:56:47Z" }, "team": null }, { "id": 2619340, "title": "Skies Like These ", "description": "

In anticipation for their release of the paperback version of the book, Skies Like These, Macmillan commissioned us to redesign the cover artwork.

\n\n

The story is about a twelve-year-old girl name Jade who is sent to spend the summer with her aunt in Wyoming by her parents. She meets a rebellious boy who called himself Roy Parker, after the legendary Butch Cassidy. Jade tries to be a good friend Roy, but worries about the trouble he might get her into while he tries to plan stunts worthy of Butch Cassidy himself.\n

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/44585/screenshots/2619340/skies-like-these-dribbble_teaser.png" }, "views_count": 1548, "likes_count": 177, "comments_count": 5, "attachments_count": 1, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T16:50:48Z", "updated_at": "2016-03-29T16:53:16Z", "html_url": "https://dribbble.com/shots/2619340-Skies-Like-These", "attachments_url": "https://api.dribbble.com/v1/shots/2619340/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619340/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619340/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619340/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619340/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619340/rebounds", "animated": false, "tags": [ "book", "book cover", "cover artwork", "cover design", "cowboy hat", "illustration", "mountain", "planets", "sky", "stars" ], "user": { "id": 44585, "name": "Brad Woodard", "username": "bradwwoodard", "html_url": "https://dribbble.com/bradwwoodard", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/44585/avatars/normal/593686b9b9c0d2b6a496d8404f24ce1f.png?1444862250", "bio": "Designer • Illustrator • Braver of the Woods", "location": "Austin, TX", "links": { "web": "http://www.bravethewoods.com/", "twitter": "https://twitter.com/brave_the_woods" }, "buckets_count": 1, "comments_received_count": 2598, "followers_count": 8556, "followings_count": 412, "likes_count": 2285, "likes_received_count": 45938, "projects_count": 21, "rebounds_received_count": 16, "shots_count": 324, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/44585/buckets", "followers_url": "https://api.dribbble.com/v1/users/44585/followers", "following_url": "https://api.dribbble.com/v1/users/44585/following", "likes_url": "https://api.dribbble.com/v1/users/44585/likes", "projects_url": "https://api.dribbble.com/v1/users/44585/projects", "shots_url": "https://api.dribbble.com/v1/users/44585/shots", "teams_url": "https://api.dribbble.com/v1/users/44585/teams", "created_at": "2011-07-08T15:47:58Z", "updated_at": "2016-03-29T16:53:16Z" }, "team": null }, { "id": 2619544, "title": "Robinhood", "description": "

Robinhood integrations illustration.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/4598/screenshots/2619544/integrations_header_01_teaser.png" }, "views_count": 1530, "likes_count": 177, "comments_count": 6, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T18:24:59Z", "updated_at": "2016-03-29T18:26:47Z", "html_url": "https://dribbble.com/shots/2619544-Robinhood", "attachments_url": "https://api.dribbble.com/v1/shots/2619544/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619544/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619544/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619544/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619544/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619544/rebounds", "animated": false, "tags": [ "chart", "finance", "illustration", "money", "stock" ], "user": { "id": 4598, "name": "Ty Wilkins", "username": "tywilkins", "html_url": "https://dribbble.com/tywilkins", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/4598/avatars/normal/fox2.jpg?1391573055", "bio": "hello@tywilkins.com", "location": "San Francisco, CA", "links": { "web": "http://www.tywilkins.com", "twitter": "https://twitter.com/tywilkins" }, "buckets_count": 0, "comments_received_count": 1080, "followers_count": 8222, "followings_count": 527, "likes_count": 0, "likes_received_count": 21359, "projects_count": 8, "rebounds_received_count": 0, "shots_count": 97, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/4598/buckets", "followers_url": "https://api.dribbble.com/v1/users/4598/followers", "following_url": "https://api.dribbble.com/v1/users/4598/following", "likes_url": "https://api.dribbble.com/v1/users/4598/likes", "projects_url": "https://api.dribbble.com/v1/users/4598/projects", "shots_url": "https://api.dribbble.com/v1/users/4598/shots", "teams_url": "https://api.dribbble.com/v1/users/4598/teams", "created_at": "2010-09-30T20:31:02Z", "updated_at": "2016-03-29T18:27:54Z" }, "team": null }, { "id": 2619187, "title": "Confidential iPad App part #2", "description": "

Over the holidays, Rally built an iPad app for a confidential client and conference. This is video directly from interacting with the native iOS app.

\n\n

Myself, @Geof Crowl, and Wes tackled the project in just 15 days. It was intense but fun. Geof and I did the design and helped with layout in Xcode using Nibs. Wes built the globe and the data visualizations from a json file using our own Open GL globe library we've been building on an off for the past year.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally.gif", "normal": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally_1x.gif", "teaser": "https://d13yacurqjgara.cloudfront.net/users/3816/screenshots/2619187/confidential-ipad-app-rally_teaser.gif" }, "views_count": 3205, "likes_count": 183, "comments_count": 9, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 20, "created_at": "2016-03-29T15:50:05Z", "updated_at": "2016-03-29T15:51:33Z", "html_url": "https://dribbble.com/shots/2619187-Confidential-iPad-App-part-2", "attachments_url": "https://api.dribbble.com/v1/shots/2619187/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619187/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619187/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619187/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619187/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619187/rebounds", "animated": true, "tags": [ ], "user": { "id": 3816, "name": "Ben Cline", "username": "letsgorally", "html_url": "https://dribbble.com/letsgorally", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/3816/avatars/normal/bb00fd14001a8cdd5e0e354df52a7fa4.png?1450769044", "bio": "@RALLY Co-Founder / Designer", "location": "Salt Lake City", "links": { "web": "http://beta.rallyinteractive.com", "twitter": "https://twitter.com/yocline" }, "buckets_count": 3, "comments_received_count": 4525, "followers_count": 30105, "followings_count": 241, "likes_count": 6878, "likes_received_count": 87892, "projects_count": 10, "rebounds_received_count": 28, "shots_count": 257, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/3816/buckets", "followers_url": "https://api.dribbble.com/v1/users/3816/followers", "following_url": "https://api.dribbble.com/v1/users/3816/following", "likes_url": "https://api.dribbble.com/v1/users/3816/likes", "projects_url": "https://api.dribbble.com/v1/users/3816/projects", "shots_url": "https://api.dribbble.com/v1/users/3816/shots", "teams_url": "https://api.dribbble.com/v1/users/3816/teams", "created_at": "2010-07-30T17:30:31Z", "updated_at": "2016-03-29T15:51:33Z" }, "team": { "id": 559317, "name": "RALLY", "username": "rally", "html_url": "https://dribbble.com/rally", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/559317/avatars/normal/rally_logo.png?1398641637", "bio": "Interactive Studio. Design & Development", "location": "Salt Lake City", "links": { "web": "http://beta.rallyinteractive.com", "twitter": "https://twitter.com/letsgorally" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 8281, "followings_count": 6, "likes_count": 73, "likes_received_count": 0, "projects_count": 14, "rebounds_received_count": 0, "shots_count": 273, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/559317/buckets", "followers_url": "https://api.dribbble.com/v1/users/559317/followers", "following_url": "https://api.dribbble.com/v1/users/559317/following", "likes_url": "https://api.dribbble.com/v1/users/559317/likes", "projects_url": "https://api.dribbble.com/v1/users/559317/projects", "shots_url": "https://api.dribbble.com/v1/users/559317/shots", "created_at": "2014-04-27T23:31:42Z", "updated_at": "2016-03-29T15:51:33Z", "members_count": 5, "members_url": "https://api.dribbble.com/v1/teams/559317/members", "team_shots_url": "https://api.dribbble.com/v1/teams/559317/shots" } }, { "id": 2619200, "title": "Eilean Donan Castle", "description": "

Day 209/365

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/283823/screenshots/2619200/eilean_donan_castle-01_teaser.jpg" }, "views_count": 1434, "likes_count": 162, "comments_count": 4, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T15:54:42Z", "updated_at": "2016-03-29T15:55:23Z", "html_url": "https://dribbble.com/shots/2619200-Eilean-Donan-Castle", "attachments_url": "https://api.dribbble.com/v1/shots/2619200/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619200/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619200/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619200/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619200/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619200/rebounds", "rebound_source_url": "https://api.dribbble.com/v1/shots/2614735", "animated": false, "tags": [ "icon", "illustration", "lake", "scotland", "vector" ], "user": { "id": 283823, "name": "Scott Tusk", "username": "Tusk", "html_url": "https://dribbble.com/Tusk", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/283823/avatars/normal/c71f583fd2f781e48da28697c6ec2211.jpg?1456193406", "bio": "", "location": "Chicago", "links": { }, "buckets_count": 0, "comments_received_count": 1118, "followers_count": 5013, "followings_count": 812, "likes_count": 2295, "likes_received_count": 45133, "projects_count": 1, "rebounds_received_count": 214, "shots_count": 282, "teams_count": 1, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/283823/buckets", "followers_url": "https://api.dribbble.com/v1/users/283823/followers", "following_url": "https://api.dribbble.com/v1/users/283823/following", "likes_url": "https://api.dribbble.com/v1/users/283823/likes", "projects_url": "https://api.dribbble.com/v1/users/283823/projects", "shots_url": "https://api.dribbble.com/v1/users/283823/shots", "teams_url": "https://api.dribbble.com/v1/users/283823/teams", "created_at": "2013-02-17T16:32:29Z", "updated_at": "2016-03-29T15:55:23Z" }, "team": null }, { "id": 2619378, "title": "Infinite Coffee", "description": "

It's Monday, I need coffee. Forever.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/60266/screenshots/2619378/coffee_teaser.jpg" }, "views_count": 1301, "likes_count": 146, "comments_count": 6, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 2, "created_at": "2016-03-29T17:11:50Z", "updated_at": "2016-03-29T17:18:17Z", "html_url": "https://dribbble.com/shots/2619378-Infinite-Coffee", "attachments_url": "https://api.dribbble.com/v1/shots/2619378/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619378/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619378/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619378/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619378/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619378/rebounds", "animated": false, "tags": [ "8", "coffee", "cup", "food", "geometric", "illustration", "infinite", "kite", "liquid", "mug", "stroke" ], "user": { "id": 60266, "name": "Gustavo Zambelli", "username": "zamax", "html_url": "https://dribbble.com/zamax", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/60266/avatars/normal/83d4ac61d50bf5b2fedc9f9cc45a62d9.png?1453312126", "bio": "Hi, I'm Lead of illustration at @aerolab & Superman at @RicosQuesos", "location": "Neuquén, Argentina.", "links": { "web": "http://zamax.tumblr.com", "twitter": "https://twitter.com/zamax4" }, "buckets_count": 19, "comments_received_count": 1645, "followers_count": 4198, "followings_count": 1253, "likes_count": 8828, "likes_received_count": 36018, "projects_count": 4, "rebounds_received_count": 133, "shots_count": 305, "teams_count": 4, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/60266/buckets", "followers_url": "https://api.dribbble.com/v1/users/60266/followers", "following_url": "https://api.dribbble.com/v1/users/60266/following", "likes_url": "https://api.dribbble.com/v1/users/60266/likes", "projects_url": "https://api.dribbble.com/v1/users/60266/projects", "shots_url": "https://api.dribbble.com/v1/users/60266/shots", "teams_url": "https://api.dribbble.com/v1/users/60266/teams", "created_at": "2011-09-07T19:27:31Z", "updated_at": "2016-03-29T17:18:17Z" }, "team": { "id": 171431, "name": "Aerolab", "username": "aerolab", "html_url": "https://dribbble.com/aerolab", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/171431/avatars/normal/1283d5fbcd21a809d0cdc2f96a560096.png?1458077891", "bio": "We design and develop beautiful digital products for startups and leading brands.", "location": "Buenos Aires - San Francisco", "links": { "web": "http://aerolab.co", "twitter": "https://twitter.com/aerolab" }, "buckets_count": 5, "comments_received_count": 157, "followers_count": 3845, "followings_count": 128, "likes_count": 4228, "likes_received_count": 2121, "projects_count": 24, "rebounds_received_count": 2, "shots_count": 579, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/171431/buckets", "followers_url": "https://api.dribbble.com/v1/users/171431/followers", "following_url": "https://api.dribbble.com/v1/users/171431/following", "likes_url": "https://api.dribbble.com/v1/users/171431/likes", "projects_url": "https://api.dribbble.com/v1/users/171431/projects", "shots_url": "https://api.dribbble.com/v1/users/171431/shots", "created_at": "2012-07-04T02:31:07Z", "updated_at": "2016-03-29T17:18:17Z", "members_count": 21, "members_url": "https://api.dribbble.com/v1/teams/171431/members", "team_shots_url": "https://api.dribbble.com/v1/teams/171431/shots" } }, { "id": 2619645, "title": "Hello, Is It Me You're Looking For?", "description": "

I had the privilege of getting to collaborate with @Jordan Wade on a hero illustration for his SVG post. And let me tell you, watching your work come alive with CSS and JS is pretty much the jam.

\n\n

Check it out all alive n' stuff!

\n\n

Go read about why you should learn more about SVG for the web.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/13774/screenshots/2619645/hello_teaser.png" }, "views_count": 1771, "likes_count": 146, "comments_count": 2, "attachments_count": 0, "rebounds_count": 1, "buckets_count": 2, "created_at": "2016-03-29T19:12:57Z", "updated_at": "2016-03-29T20:26:49Z", "html_url": "https://dribbble.com/shots/2619645-Hello-Is-It-Me-You-re-Looking-For", "attachments_url": "https://api.dribbble.com/v1/shots/2619645/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619645/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619645/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619645/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619645/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619645/rebounds", "animated": false, "tags": [ "hello" ], "user": { "id": 13774, "name": "Justin Mezzell", "username": "JustinMezzell", "html_url": "https://dribbble.com/JustinMezzell", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/13774/avatars/normal/Me_Web.jpg?1380768479", "bio": "Designer? Illustrator? Why not. Directing Art at @codeschool.", "location": "Orlando, FL", "links": { "web": "http://justinmezzell.com/", "twitter": "https://twitter.com/JustinMezzell" }, "buckets_count": 0, "comments_received_count": 5736, "followers_count": 31449, "followings_count": 713, "likes_count": 5548, "likes_received_count": 113425, "projects_count": 0, "rebounds_received_count": 55, "shots_count": 312, "teams_count": 4, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/13774/buckets", "followers_url": "https://api.dribbble.com/v1/users/13774/followers", "following_url": "https://api.dribbble.com/v1/users/13774/following", "likes_url": "https://api.dribbble.com/v1/users/13774/likes", "projects_url": "https://api.dribbble.com/v1/users/13774/projects", "shots_url": "https://api.dribbble.com/v1/users/13774/shots", "teams_url": "https://api.dribbble.com/v1/users/13774/teams", "created_at": "2011-01-26T06:58:50Z", "updated_at": "2016-03-29T20:26:49Z" }, "team": { "id": 333539, "name": "Code School", "username": "codeschool", "html_url": "https://dribbble.com/codeschool", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/333539/avatars/normal/329ac818d30ca1a7b900c09b105ce277.jpg?1410890340", "bio": "Code School teaches web technologies in the comfort of your browser with video lessons, coding challenges, and screencasts.", "location": "Orlando, FL", "links": { "web": "http://codeschool.com", "twitter": "https://twitter.com/codeschool" }, "buckets_count": 0, "comments_received_count": 0, "followers_count": 3057, "followings_count": 13, "likes_count": 1, "likes_received_count": 0, "projects_count": 0, "rebounds_received_count": 0, "shots_count": 154, "can_upload_shot": true, "type": "Team", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/333539/buckets", "followers_url": "https://api.dribbble.com/v1/users/333539/followers", "following_url": "https://api.dribbble.com/v1/users/333539/following", "likes_url": "https://api.dribbble.com/v1/users/333539/likes", "projects_url": "https://api.dribbble.com/v1/users/333539/projects", "shots_url": "https://api.dribbble.com/v1/users/333539/shots", "created_at": "2013-05-15T21:37:44Z", "updated_at": "2016-03-29T20:26:49Z", "members_count": 10, "members_url": "https://api.dribbble.com/v1/teams/333539/members", "team_shots_url": "https://api.dribbble.com/v1/teams/333539/shots" } }, { "id": 2619181, "title": "Costa Rica", "description": "

Shirt graphic for offsite meeting in Costa Rica.

", "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa.png", "normal": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa_1x.png", "teaser": "https://d13yacurqjgara.cloudfront.net/users/21030/screenshots/2619181/costa_teaser.png" }, "views_count": 1261, "likes_count": 136, "comments_count": 7, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 7, "created_at": "2016-03-29T15:48:25Z", "updated_at": "2016-03-29T15:49:13Z", "html_url": "https://dribbble.com/shots/2619181-Costa-Rica", "attachments_url": "https://api.dribbble.com/v1/shots/2619181/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619181/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619181/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619181/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619181/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619181/rebounds", "animated": false, "tags": [ "bird", "costa rica", "design", "illustration", "leaf", "toucan", "tropical" ], "user": { "id": 21030, "name": "Trevor Basset", "username": "trevorbasset", "html_url": "https://dribbble.com/trevorbasset", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/21030/avatars/normal/e9907b8b54ea842b30c5787ef95acc3a.png?1426787498", "bio": "Design, art direction, illustration, birds. ", "location": "Seattle, WA", "links": { "web": "http://www.trevorbasset.com", "twitter": "https://twitter.com/trevorbasset" }, "buckets_count": 0, "comments_received_count": 244, "followers_count": 1169, "followings_count": 367, "likes_count": 1204, "likes_received_count": 3660, "projects_count": 0, "rebounds_received_count": 4, "shots_count": 85, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": false, "buckets_url": "https://api.dribbble.com/v1/users/21030/buckets", "followers_url": "https://api.dribbble.com/v1/users/21030/followers", "following_url": "https://api.dribbble.com/v1/users/21030/following", "likes_url": "https://api.dribbble.com/v1/users/21030/likes", "projects_url": "https://api.dribbble.com/v1/users/21030/projects", "shots_url": "https://api.dribbble.com/v1/users/21030/shots", "teams_url": "https://api.dribbble.com/v1/users/21030/teams", "created_at": "2011-03-03T20:05:14Z", "updated_at": "2016-03-30T04:08:03Z" }, "team": null } ]; ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo/main.m ================================================ // // main.m // dribbbleDemo // // Created by bang on 15/9/1. // Copyright (c) 2015年 bang. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 36091A1B1CAAA2830012490F /* JPEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 36091A191CAAA2830012490F /* JPEngine.m */; }; 36091A1C1CAAA2830012490F /* JSPatch.js in Resources */ = {isa = PBXBuildFile; fileRef = 36091A1A1CAAA2830012490F /* JSPatch.js */; }; 36091A771CAB91990012490F /* JPCleaner.m in Sources */ = {isa = PBXBuildFile; fileRef = 36091A5B1CAB91980012490F /* JPCleaner.m */; }; 36091A791CAB91990012490F /* JPLocker.m in Sources */ = {isa = PBXBuildFile; fileRef = 36091A5F1CAB91980012490F /* JPLocker.m */; }; 36091A7B1CAB91990012490F /* JPSpecialInit.m in Sources */ = {isa = PBXBuildFile; fileRef = 36091A631CAB91980012490F /* JPSpecialInit.m */; }; 36CE19221CB17D6A007D73AC /* dribbble in Resources */ = {isa = PBXBuildFile; fileRef = 36CE19211CB17D6A007D73AC /* dribbble */; }; DEBA57DF1B95D5A200B4DC66 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DEBA57DE1B95D5A200B4DC66 /* main.m */; }; DEBA57E21B95D5A300B4DC66 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DEBA57E11B95D5A300B4DC66 /* AppDelegate.m */; }; DEBA57EA1B95D5A300B4DC66 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DEBA57E91B95D5A300B4DC66 /* Images.xcassets */; }; DEBA57F91B95D5A300B4DC66 /* dribbbleDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEBA57F81B95D5A300B4DC66 /* dribbbleDemoTests.m */; }; DEBA58531B95DA6E00B4DC66 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEBA58521B95DA6E00B4DC66 /* UIKit.framework */; }; DEBA58551B95DA7C00B4DC66 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEBA58541B95DA7C00B4DC66 /* Security.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ DEBA57F31B95D5A300B4DC66 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DEBA57D11B95D5A200B4DC66 /* Project object */; proxyType = 1; remoteGlobalIDString = DEBA57D81B95D5A200B4DC66; remoteInfo = dribbbleDemo; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 0A8B1CDBA40FFAD086BA1A15 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 15903DAE6B51ADB1AEC38472 /* libPods-dribbbleDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-dribbbleDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 36091A181CAAA2830012490F /* JPEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPEngine.h; sourceTree = ""; }; 36091A191CAAA2830012490F /* JPEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPEngine.m; sourceTree = ""; }; 36091A1A1CAAA2830012490F /* JSPatch.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSPatch.js; sourceTree = ""; }; 36091A5A1CAB91980012490F /* JPCleaner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCleaner.h; sourceTree = ""; }; 36091A5B1CAB91980012490F /* JPCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCleaner.m; sourceTree = ""; }; 36091A5E1CAB91980012490F /* JPLocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPLocker.h; sourceTree = ""; }; 36091A5F1CAB91980012490F /* JPLocker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPLocker.m; sourceTree = ""; }; 36091A621CAB91980012490F /* JPSpecialInit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPSpecialInit.h; sourceTree = ""; }; 36091A631CAB91980012490F /* JPSpecialInit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPSpecialInit.m; sourceTree = ""; }; 36CE19211CB17D6A007D73AC /* dribbble */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dribbble; sourceTree = ""; }; 4E9FF79023501B4C7B8780E6 /* Pods-dribbbleDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dribbbleDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-dribbbleDemo/Pods-dribbbleDemo.debug.xcconfig"; sourceTree = ""; }; 5B21F30B82AD2BCFBD981366 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; A354BF41D400455B098BBF0B /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; C74009A42925FAD86E7D36C0 /* Pods-dribbbleDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dribbbleDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-dribbbleDemo/Pods-dribbbleDemo.release.xcconfig"; sourceTree = ""; }; DEBA57D91B95D5A200B4DC66 /* dribbbleDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dribbbleDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; DEBA57DD1B95D5A200B4DC66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DEBA57DE1B95D5A200B4DC66 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; DEBA57E01B95D5A300B4DC66 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; DEBA57E11B95D5A300B4DC66 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; DEBA57E91B95D5A300B4DC66 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; DEBA57F21B95D5A300B4DC66 /* dribbbleDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = dribbbleDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DEBA57F71B95D5A300B4DC66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DEBA57F81B95D5A300B4DC66 /* dribbbleDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = dribbbleDemoTests.m; sourceTree = ""; }; DEBA58521B95DA6E00B4DC66 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; DEBA58541B95DA7C00B4DC66 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ DEBA57D61B95D5A200B4DC66 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( DEBA58551B95DA7C00B4DC66 /* Security.framework in Frameworks */, DEBA58531B95DA6E00B4DC66 /* UIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; DEBA57EF1B95D5A300B4DC66 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 31AAE1067DD5D5B8CB52EAD4 /* Pods */ = { isa = PBXGroup; children = ( 5B21F30B82AD2BCFBD981366 /* Pods.debug.xcconfig */, 0A8B1CDBA40FFAD086BA1A15 /* Pods.release.xcconfig */, 4E9FF79023501B4C7B8780E6 /* Pods-dribbbleDemo.debug.xcconfig */, C74009A42925FAD86E7D36C0 /* Pods-dribbbleDemo.release.xcconfig */, ); name = Pods; sourceTree = ""; }; 36091A171CAAA2830012490F /* JSPatch */ = { isa = PBXGroup; children = ( 36091A481CAB91980012490F /* Extensions */, 36091A181CAAA2830012490F /* JPEngine.h */, 36091A191CAAA2830012490F /* JPEngine.m */, 36091A1A1CAAA2830012490F /* JSPatch.js */, ); name = JSPatch; path = ../../../JSPatch; sourceTree = ""; }; 36091A481CAB91980012490F /* Extensions */ = { isa = PBXGroup; children = ( 36091A5A1CAB91980012490F /* JPCleaner.h */, 36091A5B1CAB91980012490F /* JPCleaner.m */, 36091A5E1CAB91980012490F /* JPLocker.h */, 36091A5F1CAB91980012490F /* JPLocker.m */, 36091A621CAB91980012490F /* JPSpecialInit.h */, 36091A631CAB91980012490F /* JPSpecialInit.m */, ); name = Extensions; path = ../Extensions; sourceTree = ""; }; DEBA57D01B95D5A200B4DC66 = { isa = PBXGroup; children = ( DEBA58541B95DA7C00B4DC66 /* Security.framework */, DEBA58521B95DA6E00B4DC66 /* UIKit.framework */, DEBA57DB1B95D5A200B4DC66 /* dribbbleDemo */, DEBA57F51B95D5A300B4DC66 /* dribbbleDemoTests */, DEBA57DA1B95D5A200B4DC66 /* Products */, 31AAE1067DD5D5B8CB52EAD4 /* Pods */, FF293541306D58FD4BDAA5CD /* Frameworks */, ); sourceTree = ""; }; DEBA57DA1B95D5A200B4DC66 /* Products */ = { isa = PBXGroup; children = ( DEBA57D91B95D5A200B4DC66 /* dribbbleDemo.app */, DEBA57F21B95D5A300B4DC66 /* dribbbleDemoTests.xctest */, ); name = Products; sourceTree = ""; }; DEBA57DB1B95D5A200B4DC66 /* dribbbleDemo */ = { isa = PBXGroup; children = ( 36091A171CAAA2830012490F /* JSPatch */, DEBA57E01B95D5A300B4DC66 /* AppDelegate.h */, DEBA57E11B95D5A300B4DC66 /* AppDelegate.m */, 36CE19211CB17D6A007D73AC /* dribbble */, DEBA57E91B95D5A300B4DC66 /* Images.xcassets */, DEBA57DC1B95D5A200B4DC66 /* Supporting Files */, ); path = dribbbleDemo; sourceTree = ""; }; DEBA57DC1B95D5A200B4DC66 /* Supporting Files */ = { isa = PBXGroup; children = ( DEBA57DD1B95D5A200B4DC66 /* Info.plist */, DEBA57DE1B95D5A200B4DC66 /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; DEBA57F51B95D5A300B4DC66 /* dribbbleDemoTests */ = { isa = PBXGroup; children = ( DEBA57F81B95D5A300B4DC66 /* dribbbleDemoTests.m */, DEBA57F61B95D5A300B4DC66 /* Supporting Files */, ); path = dribbbleDemoTests; sourceTree = ""; }; DEBA57F61B95D5A300B4DC66 /* Supporting Files */ = { isa = PBXGroup; children = ( DEBA57F71B95D5A300B4DC66 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; FF293541306D58FD4BDAA5CD /* Frameworks */ = { isa = PBXGroup; children = ( A354BF41D400455B098BBF0B /* libPods.a */, 15903DAE6B51ADB1AEC38472 /* libPods-dribbbleDemo.a */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ DEBA57D81B95D5A200B4DC66 /* dribbbleDemo */ = { isa = PBXNativeTarget; buildConfigurationList = DEBA57FC1B95D5A300B4DC66 /* Build configuration list for PBXNativeTarget "dribbbleDemo" */; buildPhases = ( 379F843EA00F8D428B9036AE /* 📦 Check Pods Manifest.lock */, DEBA57D51B95D5A200B4DC66 /* Sources */, DEBA57D61B95D5A200B4DC66 /* Frameworks */, DEBA57D71B95D5A200B4DC66 /* Resources */, 5051F1B8E1BE3F57F4085EA8 /* 📦 Copy Pods Resources */, 3E10562C003A078AFFFB76ED /* 📦 Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); name = dribbbleDemo; productName = dribbbleDemo; productReference = DEBA57D91B95D5A200B4DC66 /* dribbbleDemo.app */; productType = "com.apple.product-type.application"; }; DEBA57F11B95D5A300B4DC66 /* dribbbleDemoTests */ = { isa = PBXNativeTarget; buildConfigurationList = DEBA57FF1B95D5A300B4DC66 /* Build configuration list for PBXNativeTarget "dribbbleDemoTests" */; buildPhases = ( DEBA57EE1B95D5A300B4DC66 /* Sources */, DEBA57EF1B95D5A300B4DC66 /* Frameworks */, DEBA57F01B95D5A300B4DC66 /* Resources */, ); buildRules = ( ); dependencies = ( DEBA57F41B95D5A300B4DC66 /* PBXTargetDependency */, ); name = dribbbleDemoTests; productName = dribbbleDemoTests; productReference = DEBA57F21B95D5A300B4DC66 /* dribbbleDemoTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ DEBA57D11B95D5A200B4DC66 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0640; ORGANIZATIONNAME = bang; TargetAttributes = { DEBA57D81B95D5A200B4DC66 = { CreatedOnToolsVersion = 6.4; }; DEBA57F11B95D5A300B4DC66 = { CreatedOnToolsVersion = 6.4; TestTargetID = DEBA57D81B95D5A200B4DC66; }; }; }; buildConfigurationList = DEBA57D41B95D5A200B4DC66 /* Build configuration list for PBXProject "dribbbleDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = DEBA57D01B95D5A200B4DC66; productRefGroup = DEBA57DA1B95D5A200B4DC66 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( DEBA57D81B95D5A200B4DC66 /* dribbbleDemo */, DEBA57F11B95D5A300B4DC66 /* dribbbleDemoTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ DEBA57D71B95D5A200B4DC66 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 36091A1C1CAAA2830012490F /* JSPatch.js in Resources */, DEBA57EA1B95D5A300B4DC66 /* Images.xcassets in Resources */, 36CE19221CB17D6A007D73AC /* dribbble in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; DEBA57F01B95D5A300B4DC66 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 379F843EA00F8D428B9036AE /* 📦 Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "📦 Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; 3E10562C003A078AFFFB76ED /* 📦 Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "📦 Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-dribbbleDemo/Pods-dribbbleDemo-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 5051F1B8E1BE3F57F4085EA8 /* 📦 Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "📦 Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-dribbbleDemo/Pods-dribbbleDemo-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ DEBA57D51B95D5A200B4DC66 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 36091A791CAB91990012490F /* JPLocker.m in Sources */, 36091A771CAB91990012490F /* JPCleaner.m in Sources */, 36091A1B1CAAA2830012490F /* JPEngine.m in Sources */, 36091A7B1CAB91990012490F /* JPSpecialInit.m in Sources */, DEBA57E21B95D5A300B4DC66 /* AppDelegate.m in Sources */, DEBA57DF1B95D5A200B4DC66 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DEBA57EE1B95D5A300B4DC66 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DEBA57F91B95D5A300B4DC66 /* dribbbleDemoTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ DEBA57F41B95D5A300B4DC66 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DEBA57D81B95D5A200B4DC66 /* dribbbleDemo */; targetProxy = DEBA57F31B95D5A300B4DC66 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ DEBA57FA1B95D5A300B4DC66 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.4; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; DEBA57FB1B95D5A300B4DC66 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.4; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; DEBA57FD1B95D5A300B4DC66 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 4E9FF79023501B4C7B8780E6 /* Pods-dribbbleDemo.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = dribbbleDemo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; DEBA57FE1B95D5A300B4DC66 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = C74009A42925FAD86E7D36C0 /* Pods-dribbbleDemo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = dribbbleDemo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; DEBA58001B95D5A300B4DC66 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = dribbbleDemoTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/dribbbleDemo.app/dribbbleDemo"; }; name = Debug; }; DEBA58011B95D5A300B4DC66 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = dribbbleDemoTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/dribbbleDemo.app/dribbbleDemo"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ DEBA57D41B95D5A200B4DC66 /* Build configuration list for PBXProject "dribbbleDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( DEBA57FA1B95D5A300B4DC66 /* Debug */, DEBA57FB1B95D5A300B4DC66 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DEBA57FC1B95D5A300B4DC66 /* Build configuration list for PBXNativeTarget "dribbbleDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( DEBA57FD1B95D5A300B4DC66 /* Debug */, DEBA57FE1B95D5A300B4DC66 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DEBA57FF1B95D5A300B4DC66 /* Build configuration list for PBXNativeTarget "dribbbleDemoTests" */ = { isa = XCConfigurationList; buildConfigurations = ( DEBA58001B95D5A300B4DC66 /* Debug */, DEBA58011B95D5A300B4DC66 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = DEBA57D11B95D5A200B4DC66 /* Project object */; } ================================================ FILE: Demo/DribbbleDemo/dribbbleDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/DribbbleDemo/dribbbleDemoTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier com.jspatch..$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Demo/DribbbleDemo/dribbbleDemoTests/dribbbleDemoTests.m ================================================ // // dribbbleDemoTests.m // dribbbleDemoTests // // Created by bang on 15/9/1. // Copyright (c) 2015年 bang. All rights reserved. // #import #import @interface dribbbleDemoTests : XCTestCase @end @implementation dribbbleDemoTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. XCTAssert(YES, @"Pass"); } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end ================================================ FILE: Demo/OSXDemo/JSPatchOSXDemo/AppDelegate.h ================================================ // // AppDelegate.h // JSPatchOSXDemo // // Created by Felix Deimel on 26.05.15. // Copyright (c) 2015 Lemon Mojo. All rights reserved. // #import @interface AppDelegate : NSObject @property (nonatomic, readwrite) int clickCount; @property (weak) IBOutlet NSTableView *tableView; @end ================================================ FILE: Demo/OSXDemo/JSPatchOSXDemo/AppDelegate.m ================================================ // // AppDelegate.m // JSPatchOSXDemo // // Created by Felix Deimel on 26.05.15. // Copyright (c) 2015 Lemon Mojo. All rights reserved. // #import "AppDelegate.h" #import "JPEngine.h" @interface AppDelegate () @property (weak) IBOutlet NSWindow *window; @end @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [JPEngine startEngine]; NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"]; NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; } // Implemented in demo.js - (IBAction)buttonJavaScriptTestAction:(id)sender { } - (IBAction)buttonObjectiveCTestAction:(id)sender { self.clickCount++; [(NSButton*)sender setTitle:[NSString stringWithFormat:@"Clicked %i times", self.clickCount]]; [self.tableView reloadData]; } // Implemented in demo.js - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { return 0; } // Implemented in demo.js - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { return nil; } @end ================================================ FILE: Demo/OSXDemo/JSPatchOSXDemo/Base.lproj/MainMenu.xib ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: Demo/OSXDemo/JSPatchOSXDemo/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier com.lemonmojo.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2015 Lemon Mojo. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass NSApplication ================================================ FILE: Demo/OSXDemo/JSPatchOSXDemo/demo.js ================================================ defineClass('AppDelegate', { buttonJavaScriptTestAction: function(sender) { self.setClickCount(self.clickCount() + 1); sender.setTitle("Clicked " + self.clickCount() + " times"); self.tableView().reloadData(); }, numberOfRowsInTableView: function(tableView) { return self.clickCount(); }, tableView_viewForTableColumn_row: function(tableView, tableColumn, row) { var view = tableView.makeViewWithIdentifier_owner("TABLEVIEW_CELL", self); view.textField().setStringValue("Clicked " + (row + 1) + " times"); return view; } }); ================================================ FILE: Demo/OSXDemo/JSPatchOSXDemo/main.m ================================================ // // main.m // JSPatchOSXDemo // // Created by Felix Deimel on 26.05.15. // Copyright (c) 2015 Lemon Mojo. All rights reserved. // #import int main(int argc, const char * argv[]) { return NSApplicationMain(argc, argv); } ================================================ FILE: Demo/OSXDemo/JSPatchOSXDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 3613C3941C632A3E00E915CB /* JPEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3921C632A3E00E915CB /* JPEngine.m */; }; 3613C3951C632A3E00E915CB /* JSPatch.js in Resources */ = {isa = PBXBuildFile; fileRef = 3613C3931C632A3E00E915CB /* JSPatch.js */; }; E7E413DB1B14853E008E10DC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E7E413DA1B14853E008E10DC /* AppDelegate.m */; }; E7E413DD1B14853E008E10DC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E7E413DC1B14853E008E10DC /* main.m */; }; E7E413E21B14853E008E10DC /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = E7E413E01B14853E008E10DC /* MainMenu.xib */; }; E7E413FE1B1486AD008E10DC /* demo.js in Resources */ = {isa = PBXBuildFile; fileRef = E7E413FD1B1486AD008E10DC /* demo.js */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 3613C3911C632A3E00E915CB /* JPEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPEngine.h; sourceTree = ""; }; 3613C3921C632A3E00E915CB /* JPEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPEngine.m; sourceTree = ""; }; 3613C3931C632A3E00E915CB /* JSPatch.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSPatch.js; sourceTree = ""; }; E7E413D41B14853E008E10DC /* JSPatchOSXDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSPatchOSXDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; E7E413D81B14853E008E10DC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E7E413D91B14853E008E10DC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; E7E413DA1B14853E008E10DC /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; E7E413DC1B14853E008E10DC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; E7E413E11B14853E008E10DC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; E7E413FD1B1486AD008E10DC /* demo.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = demo.js; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ E7E413D11B14853E008E10DC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 3613C3901C632A3E00E915CB /* JSPatch */ = { isa = PBXGroup; children = ( 3613C3911C632A3E00E915CB /* JPEngine.h */, 3613C3921C632A3E00E915CB /* JPEngine.m */, 3613C3931C632A3E00E915CB /* JSPatch.js */, ); name = JSPatch; path = ../../../JSPatch; sourceTree = ""; }; E7E413CB1B14853E008E10DC = { isa = PBXGroup; children = ( E7E413D61B14853E008E10DC /* JSPatchOSXDemo */, E7E413D51B14853E008E10DC /* Products */, ); sourceTree = ""; }; E7E413D51B14853E008E10DC /* Products */ = { isa = PBXGroup; children = ( E7E413D41B14853E008E10DC /* JSPatchOSXDemo.app */, ); name = Products; sourceTree = ""; }; E7E413D61B14853E008E10DC /* JSPatchOSXDemo */ = { isa = PBXGroup; children = ( 3613C3901C632A3E00E915CB /* JSPatch */, E7E413D91B14853E008E10DC /* AppDelegate.h */, E7E413DA1B14853E008E10DC /* AppDelegate.m */, E7E413FD1B1486AD008E10DC /* demo.js */, E7E413E01B14853E008E10DC /* MainMenu.xib */, E7E413D71B14853E008E10DC /* Supporting Files */, ); path = JSPatchOSXDemo; sourceTree = ""; }; E7E413D71B14853E008E10DC /* Supporting Files */ = { isa = PBXGroup; children = ( E7E413D81B14853E008E10DC /* Info.plist */, E7E413DC1B14853E008E10DC /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ E7E413D31B14853E008E10DC /* JSPatchOSXDemo */ = { isa = PBXNativeTarget; buildConfigurationList = E7E413F11B14853E008E10DC /* Build configuration list for PBXNativeTarget "JSPatchOSXDemo" */; buildPhases = ( E7E413D01B14853E008E10DC /* Sources */, E7E413D11B14853E008E10DC /* Frameworks */, E7E413D21B14853E008E10DC /* Resources */, ); buildRules = ( ); dependencies = ( ); name = JSPatchOSXDemo; productName = JSPatchOSXDemo; productReference = E7E413D41B14853E008E10DC /* JSPatchOSXDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ E7E413CC1B14853E008E10DC /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0630; ORGANIZATIONNAME = "Lemon Mojo"; TargetAttributes = { E7E413D31B14853E008E10DC = { CreatedOnToolsVersion = 6.3.2; }; }; }; buildConfigurationList = E7E413CF1B14853E008E10DC /* Build configuration list for PBXProject "JSPatchOSXDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = E7E413CB1B14853E008E10DC; productRefGroup = E7E413D51B14853E008E10DC /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( E7E413D31B14853E008E10DC /* JSPatchOSXDemo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ E7E413D21B14853E008E10DC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 3613C3951C632A3E00E915CB /* JSPatch.js in Resources */, E7E413E21B14853E008E10DC /* MainMenu.xib in Resources */, E7E413FE1B1486AD008E10DC /* demo.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ E7E413D01B14853E008E10DC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3613C3941C632A3E00E915CB /* JPEngine.m in Sources */, E7E413DD1B14853E008E10DC /* main.m in Sources */, E7E413DB1B14853E008E10DC /* AppDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ E7E413E01B14853E008E10DC /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( E7E413E11B14853E008E10DC /* Base */, ); name = MainMenu.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ E7E413EF1B14853E008E10DC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; E7E413F01B14853E008E10DC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; }; name = Release; }; E7E413F21B14853E008E10DC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = JSPatchOSXDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; E7E413F31B14853E008E10DC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = JSPatchOSXDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ E7E413CF1B14853E008E10DC /* Build configuration list for PBXProject "JSPatchOSXDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( E7E413EF1B14853E008E10DC /* Debug */, E7E413F01B14853E008E10DC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E7E413F11B14853E008E10DC /* Build configuration list for PBXNativeTarget "JSPatchOSXDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( E7E413F21B14853E008E10DC /* Debug */, E7E413F31B14853E008E10DC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = E7E413CC1B14853E008E10DC /* Project object */; } ================================================ FILE: Demo/OSXDemo/JSPatchOSXDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/SwiftDemo/SwiftDemo/AppDelegate.swift ================================================ // // AppDelegate.swift // SwiftDemo // // Created by jspatch on 16/2/3. // Copyright © 2016年 Arlen. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. let aClass: AnyClass? = NSClassFromString("SwiftDemo.ViewController") if (aClass != nil) { let clsName = NSStringFromClass(aClass!) print(clsName) } else { print("error ViewController not found") } let bClass: AnyClass? = NSClassFromString("SwiftDemo.TestObject") if (bClass != nil) { let clsName = NSStringFromClass(bClass!) print(clsName) } else { print("error TestObject not found") } let path = Bundle.main.path(forResource: "demo", ofType: "js") do { let patch = try String(contentsOfFile: path!) JPEngine.start() JPEngine.evaluateScript(patch) } catch {} return true } func applicationWillResignActive(_ application: UIApplication) { // 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. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } func applicationDidEnterBackground(_ application: UIApplication) { // 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. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(_ application: UIApplication) { // 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. } func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } } ================================================ FILE: Demo/SwiftDemo/SwiftDemo/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/SwiftDemo/SwiftDemo/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Demo/SwiftDemo/SwiftDemo/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Demo/SwiftDemo/SwiftDemo/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Demo/SwiftDemo/SwiftDemo/SwiftDemo-Bridging-Header.h ================================================ // // SwiftDemo-Bridging-Header.h // SwiftDemo // // Created by bang on 2/4/16. // Copyright © 2016 Arlen. All rights reserved. // #ifndef SwiftDemo_Bridging_Header_h #define SwiftDemo_Bridging_Header_h #import "JPEngine.h" #endif /* SwiftDemo_Bridging_Header_h */ ================================================ FILE: Demo/SwiftDemo/SwiftDemo/TestObject.swift ================================================ // // TestObject.swift // SwiftDemo // // Created by jspatch on 16/2/3. // Copyright © 2016年 Arlen. All rights reserved. // import Foundation /** After XCode 7.0(could be Swift 2.2), the Swift Class can not be marked using @objc, and it can't be use in objc rumtime directly. So if you want to use JSPatch in your project, you should declare all your Swift Classes inherited from NSObject https://forums.developer.apple.com/thread/11867 */ open class TestObject: NSObject { /** if your patch doesn't take effect, you should consider adding the dynamic attribute to the function http://stackoverflow.com/questions/25651081/method-swizzling-in-swift In production environment, I advise you to add the dynamic attribute to all your Custom Functions. But you must know, this operation will reduce efficiency. */ dynamic func testLog() { print("TestObject orig testLog") } } ================================================ FILE: Demo/SwiftDemo/SwiftDemo/ViewController.swift ================================================ // // ViewController.swift // SwiftDemo // // Created by jspatch on 16/2/3. // Copyright © 2016年 Arlen. All rights reserved. // import UIKit //@objc(ViewController) class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell") let testObject = TestObject() testObject.testLog() self.testLog() } /** if your patch doesn't take effect, you should consider adding the dynamic attribute to the function http://stackoverflow.com/questions/25651081/method-swizzling-in-swift In production environment, I advise you to add the dynamic attribute to all your Custom Functions. But you must know, this operation will reduce efficiency. */ dynamic func testLog() { print("ViewController orig testLog") } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 5 } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 60 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) cell.textLabel?.text = NSString(format: "cell%d", indexPath.row) as String; return cell } } ================================================ FILE: Demo/SwiftDemo/SwiftDemo/demo.js ================================================ defineClass('SwiftDemo.ViewController', { viewDidLoad: function() { console.log('js viewDidLoad begin') self.ORIGviewDidLoad() console.log('js viewDidLoad end') }, testLog: function() { console.log('js ViewController testlog') }, tableView_numberOfRowsInSection: function(tableView, section) { return 10 } }) defineClass('SwiftDemo.TestObject', { testLog: function() { console.log('js TestObject testlog') } }) ================================================ FILE: Demo/SwiftDemo/SwiftDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 3613C39A1C632AB400E915CB /* JPEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3981C632AB400E915CB /* JPEngine.m */; }; 3613C39B1C632AB400E915CB /* JSPatch.js in Resources */ = {isa = PBXBuildFile; fileRef = 3613C3991C632AB400E915CB /* JSPatch.js */; }; 3613C39E1C63387900E915CB /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3613C39D1C63387900E915CB /* JavaScriptCore.framework */; }; DC5FA8C31C61F242007F1AA0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC5FA8C21C61F242007F1AA0 /* AppDelegate.swift */; }; DC5FA8C51C61F242007F1AA0 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC5FA8C41C61F242007F1AA0 /* ViewController.swift */; }; DC5FA8C81C61F242007F1AA0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DC5FA8C61C61F242007F1AA0 /* Main.storyboard */; }; DC5FA8CA1C61F242007F1AA0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC5FA8C91C61F242007F1AA0 /* Assets.xcassets */; }; DC5FA8CD1C61F242007F1AA0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DC5FA8CB1C61F242007F1AA0 /* LaunchScreen.storyboard */; }; DC5FA8D51C61F732007F1AA0 /* demo.js in Resources */ = {isa = PBXBuildFile; fileRef = DC5FA8D41C61F732007F1AA0 /* demo.js */; }; DC5FA8D71C61FD74007F1AA0 /* TestObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC5FA8D61C61FD74007F1AA0 /* TestObject.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 3613C3971C632AB400E915CB /* JPEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPEngine.h; sourceTree = ""; }; 3613C3981C632AB400E915CB /* JPEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPEngine.m; sourceTree = ""; }; 3613C3991C632AB400E915CB /* JSPatch.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSPatch.js; sourceTree = ""; }; 3613C39C1C63344D00E915CB /* SwiftDemo-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SwiftDemo-Bridging-Header.h"; sourceTree = ""; }; 3613C39D1C63387900E915CB /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; DC5FA8BF1C61F242007F1AA0 /* SwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; DC5FA8C21C61F242007F1AA0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DC5FA8C41C61F242007F1AA0 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; DC5FA8C71C61F242007F1AA0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; DC5FA8C91C61F242007F1AA0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DC5FA8CC1C61F242007F1AA0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; DC5FA8CE1C61F242007F1AA0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DC5FA8D41C61F732007F1AA0 /* demo.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = demo.js; sourceTree = ""; }; DC5FA8D61C61FD74007F1AA0 /* TestObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestObject.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ DC5FA8BC1C61F242007F1AA0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 3613C39E1C63387900E915CB /* JavaScriptCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 1559087F26CA089030BE8522 /* Frameworks */ = { isa = PBXGroup; children = ( 3613C39D1C63387900E915CB /* JavaScriptCore.framework */, ); name = Frameworks; sourceTree = ""; }; 3613C3961C632AB400E915CB /* JSPatch */ = { isa = PBXGroup; children = ( 3613C3971C632AB400E915CB /* JPEngine.h */, 3613C3981C632AB400E915CB /* JPEngine.m */, 3613C3991C632AB400E915CB /* JSPatch.js */, ); name = JSPatch; path = ../../../JSPatch; sourceTree = ""; }; DC5FA8B61C61F242007F1AA0 = { isa = PBXGroup; children = ( DC5FA8C11C61F242007F1AA0 /* SwiftDemo */, DC5FA8C01C61F242007F1AA0 /* Products */, 1559087F26CA089030BE8522 /* Frameworks */, ); sourceTree = ""; }; DC5FA8C01C61F242007F1AA0 /* Products */ = { isa = PBXGroup; children = ( DC5FA8BF1C61F242007F1AA0 /* SwiftDemo.app */, ); name = Products; sourceTree = ""; }; DC5FA8C11C61F242007F1AA0 /* SwiftDemo */ = { isa = PBXGroup; children = ( 3613C3961C632AB400E915CB /* JSPatch */, DC5FA8C21C61F242007F1AA0 /* AppDelegate.swift */, DC5FA8C41C61F242007F1AA0 /* ViewController.swift */, DC5FA8C61C61F242007F1AA0 /* Main.storyboard */, DC5FA8C91C61F242007F1AA0 /* Assets.xcassets */, DC5FA8CB1C61F242007F1AA0 /* LaunchScreen.storyboard */, DC5FA8CE1C61F242007F1AA0 /* Info.plist */, DC5FA8D41C61F732007F1AA0 /* demo.js */, DC5FA8D61C61FD74007F1AA0 /* TestObject.swift */, 3613C39C1C63344D00E915CB /* SwiftDemo-Bridging-Header.h */, ); path = SwiftDemo; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ DC5FA8BE1C61F242007F1AA0 /* SwiftDemo */ = { isa = PBXNativeTarget; buildConfigurationList = DC5FA8D11C61F242007F1AA0 /* Build configuration list for PBXNativeTarget "SwiftDemo" */; buildPhases = ( DC5FA8BB1C61F242007F1AA0 /* Sources */, DC5FA8BC1C61F242007F1AA0 /* Frameworks */, DC5FA8BD1C61F242007F1AA0 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = SwiftDemo; productName = SwiftDemo; productReference = DC5FA8BF1C61F242007F1AA0 /* SwiftDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ DC5FA8B71C61F242007F1AA0 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; LastUpgradeCheck = 0720; ORGANIZATIONNAME = Arlen; TargetAttributes = { DC5FA8BE1C61F242007F1AA0 = { CreatedOnToolsVersion = 7.2.1; LastSwiftMigration = 0820; }; }; }; buildConfigurationList = DC5FA8BA1C61F242007F1AA0 /* Build configuration list for PBXProject "SwiftDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = DC5FA8B61C61F242007F1AA0; productRefGroup = DC5FA8C01C61F242007F1AA0 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( DC5FA8BE1C61F242007F1AA0 /* SwiftDemo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ DC5FA8BD1C61F242007F1AA0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( DC5FA8CD1C61F242007F1AA0 /* LaunchScreen.storyboard in Resources */, 3613C39B1C632AB400E915CB /* JSPatch.js in Resources */, DC5FA8CA1C61F242007F1AA0 /* Assets.xcassets in Resources */, DC5FA8C81C61F242007F1AA0 /* Main.storyboard in Resources */, DC5FA8D51C61F732007F1AA0 /* demo.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ DC5FA8BB1C61F242007F1AA0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DC5FA8D71C61FD74007F1AA0 /* TestObject.swift in Sources */, 3613C39A1C632AB400E915CB /* JPEngine.m in Sources */, DC5FA8C51C61F242007F1AA0 /* ViewController.swift in Sources */, DC5FA8C31C61F242007F1AA0 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ DC5FA8C61C61F242007F1AA0 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( DC5FA8C71C61F242007F1AA0 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; DC5FA8CB1C61F242007F1AA0 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( DC5FA8CC1C61F242007F1AA0 /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ DC5FA8CF1C61F242007F1AA0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; DC5FA8D01C61F242007F1AA0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; DC5FA8D21C61F242007F1AA0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = SwiftDemo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.jspatch.SwiftDemo; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "SwiftDemo/SwiftDemo-Bridging-Header.h"; SWIFT_VERSION = 3.0; }; name = Debug; }; DC5FA8D31C61F242007F1AA0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = SwiftDemo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.jspatch.SwiftDemo; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "SwiftDemo/SwiftDemo-Bridging-Header.h"; SWIFT_VERSION = 3.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ DC5FA8BA1C61F242007F1AA0 /* Build configuration list for PBXProject "SwiftDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( DC5FA8CF1C61F242007F1AA0 /* Debug */, DC5FA8D01C61F242007F1AA0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DC5FA8D11C61F242007F1AA0 /* Build configuration list for PBXNativeTarget "SwiftDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( DC5FA8D21C61F242007F1AA0 /* Debug */, DC5FA8D31C61F242007F1AA0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = DC5FA8B71C61F242007F1AA0 /* Project object */; } ================================================ FILE: Demo/SwiftDemo/SwiftDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/iOSDemo/JSPatchDemo/AppDelegate.h ================================================ // // AppDelegate.h // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015年 bang. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Demo/iOSDemo/JSPatchDemo/AppDelegate.m ================================================ // // AppDelegate.m // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015年 bang. All rights reserved. // #import "AppDelegate.h" #import "JPEngine.h" #import "JPViewController.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [JPEngine startEngine]; NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"]; NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; JPViewController *rootViewController = [[JPViewController alloc] init]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController]; self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; [[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsCompact]; return YES; } @end ================================================ FILE: Demo/iOSDemo/JSPatchDemo/JPViewController.h ================================================ // // JPViewController.h // JSPatch // // Created by bang on 15/5/2. // Copyright (c) 2015年 bang. All rights reserved. // #import @interface JPViewController : UIViewController @end ================================================ FILE: Demo/iOSDemo/JSPatchDemo/JPViewController.m ================================================ // // JPViewController.m // JSPatch // // Created by bang on 15/5/2. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPViewController.h" @implementation JPViewController - (void)viewDidLoad { [super viewDidLoad]; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, 50)]; [btn setTitle:@"Push JPTableViewController" forState:UIControlStateNormal]; [btn addTarget:self action:@selector(handleBtn:) forControlEvents:UIControlEventTouchUpInside]; [btn setBackgroundColor:[UIColor grayColor]]; [self.view addSubview:btn]; } - (void)handleBtn:(id)sender { } @end ================================================ FILE: Demo/iOSDemo/JSPatchDemo/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/iOSDemo/JSPatchDemo/Supporting Files/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier net.cnbang.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Demo/iOSDemo/JSPatchDemo/Supporting Files/main.m ================================================ // // main.m // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015年 bang. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Demo/iOSDemo/JSPatchDemo/demo.js ================================================ defineClass('JPViewController', { handleBtn: function(sender) { var tableViewCtrl = JPTableViewController.alloc().init() self.navigationController().pushViewController_animated(tableViewCtrl, YES) } }) defineClass('JPTableViewController : UITableViewController ', ['data'], { dataSource: function() { var data = self.data(); if (data) return data; var data = []; for (var i = 0; i < 20; i ++) { data.push("cell from js " + i); } self.setData(data) return data; }, numberOfSectionsInTableView: function(tableView) { return 1; }, tableView_numberOfRowsInSection: function(tableView, section) { return self.dataSource().length; }, tableView_cellForRowAtIndexPath: function(tableView, indexPath) { var cell = tableView.dequeueReusableCellWithIdentifier("cell") if (!cell) { cell = require('UITableViewCell').alloc().initWithStyle_reuseIdentifier(0, "cell") } cell.textLabel().setText(self.dataSource()[indexPath.row()]) return cell }, tableView_heightForRowAtIndexPath: function(tableView, indexPath) { return 60 }, tableView_didSelectRowAtIndexPath: function(tableView, indexPath) { var alertView = require('UIAlertView').alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles("Alert",self.dataSource()[indexPath.row()], self, "OK", null); alertView.show() }, alertView_willDismissWithButtonIndex: function(alertView, idx) { console.log('click btn ' + alertView.buttonTitleAtIndex(idx).toJS()) } }) ================================================ FILE: Demo/iOSDemo/JSPatchDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 2D0DF7071B22F75C005695DA /* inheritTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 2D0DF7061B22F75C005695DA /* inheritTest.js */; }; 2D5D89211B0B8BFF009382EC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D5D89181B0B8BFF009382EC /* AppDelegate.m */; }; 2D5D89251B0B8BFF009382EC /* JPViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D5D891E1B0B8BFF009382EC /* JPViewController.m */; }; 2D6D12FD1B0B8CF20095A435 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2D6D12FA1B0B8CF20095A435 /* Images.xcassets */; }; 2D6D12FF1B0B8CF20095A435 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D6D12FC1B0B8CF20095A435 /* main.m */; }; 2D6D13011B0B8CFF0095A435 /* demo.js in Resources */ = {isa = PBXBuildFile; fileRef = 2D6D13001B0B8CFF0095A435 /* demo.js */; }; 2DA3C42B206A1892005877CB /* newBlockTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DA3C42A206A1892005877CB /* newBlockTest.m */; }; 2DA3C434206B5569005877CB /* newBlockTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 2DA3C433206B5569005877CB /* newBlockTest.js */; }; 360BCF4E1D82DCFC00202977 /* JPDispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = 360BCF4D1D82DCFC00202977 /* JPDispatch.m */; }; 360BCF541D82EFCD00202977 /* JPProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 360BCF531D82EFCD00202977 /* JPProtocol.m */; }; 3613C3861C6329F300E915CB /* JPEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3611C6329F300E915CB /* JPEngine.m */; }; 3613C3871C6329F300E915CB /* JSPatch.js in Resources */ = {isa = PBXBuildFile; fileRef = 3613C3621C6329F300E915CB /* JSPatch.js */; }; 3613C3881C6329F300E915CB /* JPLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3651C6329F300E915CB /* JPLoader.m */; }; 3613C3891C6329F300E915CB /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3691C6329F300E915CB /* ioapi.c */; }; 3613C38A1C6329F300E915CB /* mztools.c in Sources */ = {isa = PBXBuildFile; fileRef = 3613C36B1C6329F300E915CB /* mztools.c */; }; 3613C38B1C6329F300E915CB /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 3613C36D1C6329F300E915CB /* unzip.c */; }; 3613C38C1C6329F300E915CB /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 3613C36F1C6329F300E915CB /* zip.c */; }; 3613C38D1C6329F300E915CB /* RSA.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3721C6329F300E915CB /* RSA.m */; }; 3613C38E1C6329F300E915CB /* ZipArchive.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3741C6329F300E915CB /* ZipArchive.m */; }; 3613C38F1C6329F300E915CB /* packer.php in Resources */ = {isa = PBXBuildFile; fileRef = 3613C3761C6329F300E915CB /* packer.php */; }; 3613C3AF1C6346F500E915CB /* JPCleaner.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3AE1C6346F500E915CB /* JPCleaner.m */; }; 3646F8B41CA0F89C00E10774 /* JPLocker.m in Sources */ = {isa = PBXBuildFile; fileRef = 3646F8B31CA0F89C00E10774 /* JPLocker.m */; }; 3660BC2D1E2634C900DB3765 /* JPBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 3660BC2C1E2634C900DB3765 /* JPBlock.m */; }; 367650481E2CC3BD00828E12 /* JPBlockWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 367650471E2CC3BD00828E12 /* JPBlockWrapper.m */; }; 3694925F1CFEFE42003F44CA /* JPCFunctionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3694925D1CFEFE42003F44CA /* JPCFunctionTest.m */; }; 369492601CFEFE42003F44CA /* jsCFunctionTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 3694925E1CFEFE42003F44CA /* jsCFunctionTest.js */; }; 369EC2971C9925A400334A64 /* JPSpecialInit.m in Sources */ = {isa = PBXBuildFile; fileRef = 369EC2961C9925A400334A64 /* JPSpecialInit.m */; }; 36B3252D1E290D0C006945DF /* JPMethodSignature.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B3252C1E290D0C006945DF /* JPMethodSignature.m */; }; 36C59D611E4B517B00A40835 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 36C59D601E4B517B00A40835 /* libffi.a */; }; 36CC3A4B1CFEE6A80001465B /* JPCFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A151CFEE6A80001465B /* JPCFunction.m */; }; 36CC3A4C1CFEE6A80001465B /* JPMemory.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A171CFEE6A80001465B /* JPMemory.m */; }; 36CC3A4D1CFEE6A80001465B /* JPStructPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A191CFEE6A80001465B /* JPStructPointer.m */; }; 36CC3A4F1CFEE6A80001465B /* JPCGBitmapContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A331CFEE6A80001465B /* JPCGBitmapContext.m */; }; 36CC3A501CFEE6A80001465B /* JPCGColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A351CFEE6A80001465B /* JPCGColor.m */; }; 36CC3A511CFEE6A80001465B /* JPCGContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A371CFEE6A80001465B /* JPCGContext.m */; }; 36CC3A521CFEE6A80001465B /* JPCGGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A391CFEE6A80001465B /* JPCGGeometry.m */; }; 36CC3A531CFEE6A80001465B /* JPCGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A3B1CFEE6A80001465B /* JPCGImage.m */; }; 36CC3A541CFEE6A80001465B /* JPCGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A3D1CFEE6A80001465B /* JPCGPath.m */; }; 36CC3A551CFEE6A80001465B /* JPCGTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A3F1CFEE6A80001465B /* JPCGTransform.m */; }; 36CC3A561CFEE6A80001465B /* JPCoreGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A411CFEE6A80001465B /* JPCoreGraphics.m */; }; 36CC3A571CFEE6A80001465B /* JPUIGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A441CFEE6A80001465B /* JPUIGeometry.m */; }; 36CC3A581CFEE6A80001465B /* JPUIGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A461CFEE6A80001465B /* JPUIGraphics.m */; }; 36CC3A591CFEE6A80001465B /* JPUIImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A481CFEE6A80001465B /* JPUIImage.m */; }; 36CC3A5A1CFEE6A80001465B /* JPUIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CC3A4A1CFEE6A80001465B /* JPUIKit.m */; }; 36CE191B1CAEA179007D73AC /* jsClassTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 36CE191A1CAEA179007D73AC /* jsClassTest.js */; }; 36CE191E1CAEA1DE007D73AC /* JPJSClassTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CE191D1CAEA1DE007D73AC /* JPJSClassTest.m */; }; 36CE19251CB3E709007D73AC /* JPPerformanceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 36CE19241CB3E709007D73AC /* JPPerformanceTest.m */; }; 36CE19271CB3E72B007D73AC /* performanceTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 36CE19261CB3E72B007D73AC /* performanceTest.js */; }; 36F0DCC61BFAF41C0090EA4A /* libz.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 36F0DCC51BFAF41C0090EA4A /* libz.1.dylib */; }; 4F9EBFC51D50745200EC72C1 /* JPNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F9EBFC41D50745200EC72C1 /* JPNumber.m */; }; 4F9EBFC91D50749200EC72C1 /* JPNumberTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F9EBFC71D50749200EC72C1 /* JPNumberTest.m */; }; 4F9EBFCA1D50749200EC72C1 /* jsNumberTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 4F9EBFC81D50749200EC72C1 /* jsNumberTest.js */; }; 6C6CAC741C5F0BCA00444348 /* superTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 6C6CAC721C5F0BCA00444348 /* superTest.js */; }; 6C6CAC751C5F0BCA00444348 /* JPSuperTestObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C6CAC731C5F0BCA00444348 /* JPSuperTestObject.m */; }; 6C72B7961C352BA80086C98D /* newProtocolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C72B7951C352BA80086C98D /* newProtocolTest.m */; }; 6C9C0EE41C25A7C700FCAAC5 /* newProtocolTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 6C9C0EE31C25A7C700FCAAC5 /* newProtocolTest.js */; }; 6C9C0EE51C25A7DA00FCAAC5 /* newProtocolTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 6C9C0EE31C25A7C700FCAAC5 /* newProtocolTest.js */; }; DE58B6481B7C312800F64C63 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE58B6471B7C312800F64C63 /* JavaScriptCore.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; DE6FFF031B42B01C0005EE83 /* protocolTest.js in Resources */ = {isa = PBXBuildFile; fileRef = DE6FFF021B42B01C0005EE83 /* protocolTest.js */; }; DE6FFF051B42C25D0005EE83 /* protocolTest.js in Resources */ = {isa = PBXBuildFile; fileRef = DE6FFF021B42B01C0005EE83 /* protocolTest.js */; }; DE94AE2B1AF246C000E461D4 /* JSPatchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE94AE2A1AF246C000E461D4 /* JSPatchTests.m */; }; DE94AE461AF2480000E461D4 /* JPTestObject.m in Sources */ = {isa = PBXBuildFile; fileRef = DE94AE441AF2480000E461D4 /* JPTestObject.m */; }; DE94AE471AF2480000E461D4 /* test.js in Resources */ = {isa = PBXBuildFile; fileRef = DE94AE451AF2480000E461D4 /* test.js */; }; E1B89EA01B203482000645C2 /* JPMultithreadTestObject.m in Sources */ = {isa = PBXBuildFile; fileRef = E1B89E9F1B203482000645C2 /* JPMultithreadTestObject.m */; }; E1B89EA31B218986000645C2 /* JPInheritanceTestObjects.m in Sources */ = {isa = PBXBuildFile; fileRef = E1B89EA21B218986000645C2 /* JPInheritanceTestObjects.m */; }; E1B89EAE1B228818000645C2 /* multithreadTest.js in Resources */ = {isa = PBXBuildFile; fileRef = E1B89EAD1B228818000645C2 /* multithreadTest.js */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ DE94AE251AF246C000E461D4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DE94AE031AF246BF00E461D4 /* Project object */; proxyType = 1; remoteGlobalIDString = DE94AE0A1AF246BF00E461D4; remoteInfo = JSPatch; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 2D0DF7061B22F75C005695DA /* inheritTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = inheritTest.js; sourceTree = ""; }; 2D5D89171B0B8BFF009382EC /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 2D5D89181B0B8BFF009382EC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 2D5D891D1B0B8BFF009382EC /* JPViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPViewController.h; sourceTree = ""; }; 2D5D891E1B0B8BFF009382EC /* JPViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPViewController.m; sourceTree = ""; }; 2D6D12FA1B0B8CF20095A435 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 2D6D12FB1B0B8CF20095A435 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2D6D12FC1B0B8CF20095A435 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2D6D13001B0B8CFF0095A435 /* demo.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = demo.js; sourceTree = ""; }; 2DA3C429206A1892005877CB /* newBlockTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = newBlockTest.h; sourceTree = ""; }; 2DA3C42A206A1892005877CB /* newBlockTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = newBlockTest.m; sourceTree = ""; }; 2DA3C433206B5569005877CB /* newBlockTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newBlockTest.js; sourceTree = ""; }; 360BCF4C1D82DCFC00202977 /* JPDispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPDispatch.h; sourceTree = ""; }; 360BCF4D1D82DCFC00202977 /* JPDispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPDispatch.m; sourceTree = ""; }; 360BCF521D82EFCD00202977 /* JPProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPProtocol.h; sourceTree = ""; }; 360BCF531D82EFCD00202977 /* JPProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPProtocol.m; sourceTree = ""; }; 3613C3601C6329F300E915CB /* JPEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPEngine.h; sourceTree = ""; }; 3613C3611C6329F300E915CB /* JPEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPEngine.m; sourceTree = ""; }; 3613C3621C6329F300E915CB /* JSPatch.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSPatch.js; sourceTree = ""; }; 3613C3641C6329F300E915CB /* JPLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPLoader.h; sourceTree = ""; }; 3613C3651C6329F300E915CB /* JPLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPLoader.m; sourceTree = ""; }; 3613C3681C6329F300E915CB /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = ""; }; 3613C3691C6329F300E915CB /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = ""; }; 3613C36A1C6329F300E915CB /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = ""; }; 3613C36B1C6329F300E915CB /* mztools.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mztools.c; sourceTree = ""; }; 3613C36C1C6329F300E915CB /* mztools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mztools.h; sourceTree = ""; }; 3613C36D1C6329F300E915CB /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = ""; }; 3613C36E1C6329F300E915CB /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = ""; }; 3613C36F1C6329F300E915CB /* zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip.c; sourceTree = ""; }; 3613C3701C6329F300E915CB /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; 3613C3711C6329F300E915CB /* RSA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSA.h; sourceTree = ""; }; 3613C3721C6329F300E915CB /* RSA.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSA.m; sourceTree = ""; }; 3613C3731C6329F300E915CB /* ZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZipArchive.h; sourceTree = ""; }; 3613C3741C6329F300E915CB /* ZipArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZipArchive.m; sourceTree = ""; }; 3613C3761C6329F300E915CB /* packer.php */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.php; path = packer.php; sourceTree = ""; }; 3613C3AD1C6346F500E915CB /* JPCleaner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCleaner.h; sourceTree = ""; }; 3613C3AE1C6346F500E915CB /* JPCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCleaner.m; sourceTree = ""; }; 3646F8B21CA0F89C00E10774 /* JPLocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPLocker.h; sourceTree = ""; }; 3646F8B31CA0F89C00E10774 /* JPLocker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPLocker.m; sourceTree = ""; }; 3660BC2B1E2634C900DB3765 /* JPBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPBlock.h; sourceTree = ""; }; 3660BC2C1E2634C900DB3765 /* JPBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPBlock.m; sourceTree = ""; }; 367650461E2CC3BD00828E12 /* JPBlockWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPBlockWrapper.h; sourceTree = ""; }; 367650471E2CC3BD00828E12 /* JPBlockWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPBlockWrapper.m; sourceTree = ""; }; 3694925C1CFEFE42003F44CA /* JPCFunctionTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCFunctionTest.h; sourceTree = ""; }; 3694925D1CFEFE42003F44CA /* JPCFunctionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCFunctionTest.m; sourceTree = ""; }; 3694925E1CFEFE42003F44CA /* jsCFunctionTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsCFunctionTest.js; sourceTree = ""; }; 369EC2951C9925A400334A64 /* JPSpecialInit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPSpecialInit.h; sourceTree = ""; }; 369EC2961C9925A400334A64 /* JPSpecialInit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPSpecialInit.m; sourceTree = ""; }; 36B3252B1E290D0C006945DF /* JPMethodSignature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPMethodSignature.h; sourceTree = ""; }; 36B3252C1E290D0C006945DF /* JPMethodSignature.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPMethodSignature.m; sourceTree = ""; }; 36C59D561E4B517B00A40835 /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = ""; }; 36C59D571E4B517B00A40835 /* ffi_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_arm.h; sourceTree = ""; }; 36C59D581E4B517B00A40835 /* ffi_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_arm64.h; sourceTree = ""; }; 36C59D591E4B517B00A40835 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = ""; }; 36C59D5A1E4B517B00A40835 /* ffi_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_x86_64.h; sourceTree = ""; }; 36C59D5B1E4B517B00A40835 /* ffitarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget.h; sourceTree = ""; }; 36C59D5C1E4B517B00A40835 /* ffitarget_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_arm.h; sourceTree = ""; }; 36C59D5D1E4B517B00A40835 /* ffitarget_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_arm64.h; sourceTree = ""; }; 36C59D5E1E4B517B00A40835 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = ""; }; 36C59D5F1E4B517B00A40835 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = ""; }; 36C59D601E4B517B00A40835 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 36CC3A141CFEE6A80001465B /* JPCFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCFunction.h; sourceTree = ""; }; 36CC3A151CFEE6A80001465B /* JPCFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCFunction.m; sourceTree = ""; }; 36CC3A161CFEE6A80001465B /* JPMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPMemory.h; sourceTree = ""; }; 36CC3A171CFEE6A80001465B /* JPMemory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPMemory.m; sourceTree = ""; }; 36CC3A181CFEE6A80001465B /* JPStructPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPStructPointer.h; sourceTree = ""; }; 36CC3A191CFEE6A80001465B /* JPStructPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPStructPointer.m; sourceTree = ""; }; 36CC3A321CFEE6A80001465B /* JPCGBitmapContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGBitmapContext.h; sourceTree = ""; }; 36CC3A331CFEE6A80001465B /* JPCGBitmapContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGBitmapContext.m; sourceTree = ""; }; 36CC3A341CFEE6A80001465B /* JPCGColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGColor.h; sourceTree = ""; }; 36CC3A351CFEE6A80001465B /* JPCGColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGColor.m; sourceTree = ""; }; 36CC3A361CFEE6A80001465B /* JPCGContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGContext.h; sourceTree = ""; }; 36CC3A371CFEE6A80001465B /* JPCGContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGContext.m; sourceTree = ""; }; 36CC3A381CFEE6A80001465B /* JPCGGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGGeometry.h; sourceTree = ""; }; 36CC3A391CFEE6A80001465B /* JPCGGeometry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGGeometry.m; sourceTree = ""; }; 36CC3A3A1CFEE6A80001465B /* JPCGImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGImage.h; sourceTree = ""; }; 36CC3A3B1CFEE6A80001465B /* JPCGImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGImage.m; sourceTree = ""; }; 36CC3A3C1CFEE6A80001465B /* JPCGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGPath.h; sourceTree = ""; }; 36CC3A3D1CFEE6A80001465B /* JPCGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGPath.m; sourceTree = ""; }; 36CC3A3E1CFEE6A80001465B /* JPCGTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGTransform.h; sourceTree = ""; }; 36CC3A3F1CFEE6A80001465B /* JPCGTransform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGTransform.m; sourceTree = ""; }; 36CC3A401CFEE6A80001465B /* JPCoreGraphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCoreGraphics.h; sourceTree = ""; }; 36CC3A411CFEE6A80001465B /* JPCoreGraphics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCoreGraphics.m; sourceTree = ""; }; 36CC3A431CFEE6A80001465B /* JPUIGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIGeometry.h; sourceTree = ""; }; 36CC3A441CFEE6A80001465B /* JPUIGeometry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIGeometry.m; sourceTree = ""; }; 36CC3A451CFEE6A80001465B /* JPUIGraphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIGraphics.h; sourceTree = ""; }; 36CC3A461CFEE6A80001465B /* JPUIGraphics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIGraphics.m; sourceTree = ""; }; 36CC3A471CFEE6A80001465B /* JPUIImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIImage.h; sourceTree = ""; }; 36CC3A481CFEE6A80001465B /* JPUIImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIImage.m; sourceTree = ""; }; 36CC3A491CFEE6A80001465B /* JPUIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIKit.h; sourceTree = ""; }; 36CC3A4A1CFEE6A80001465B /* JPUIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIKit.m; sourceTree = ""; }; 36CE191A1CAEA179007D73AC /* jsClassTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsClassTest.js; sourceTree = ""; }; 36CE191C1CAEA1DE007D73AC /* JPJSClassTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPJSClassTest.h; sourceTree = ""; }; 36CE191D1CAEA1DE007D73AC /* JPJSClassTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPJSClassTest.m; sourceTree = ""; }; 36CE19231CB3E709007D73AC /* JPPerformanceTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPPerformanceTest.h; sourceTree = ""; }; 36CE19241CB3E709007D73AC /* JPPerformanceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPPerformanceTest.m; sourceTree = ""; }; 36CE19261CB3E72B007D73AC /* performanceTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = performanceTest.js; sourceTree = ""; }; 36F0DCC51BFAF41C0090EA4A /* libz.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.dylib; path = ../../../../../../usr/lib/libz.1.dylib; sourceTree = ""; }; 4F9EBFC31D50745200EC72C1 /* JPNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPNumber.h; sourceTree = ""; }; 4F9EBFC41D50745200EC72C1 /* JPNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPNumber.m; sourceTree = ""; }; 4F9EBFC61D50749200EC72C1 /* JPNumberTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPNumberTest.h; sourceTree = ""; }; 4F9EBFC71D50749200EC72C1 /* JPNumberTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPNumberTest.m; sourceTree = ""; }; 4F9EBFC81D50749200EC72C1 /* jsNumberTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jsNumberTest.js; sourceTree = ""; }; 6C6CAC711C5F0BCA00444348 /* JPSuperTestObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPSuperTestObject.h; sourceTree = ""; }; 6C6CAC721C5F0BCA00444348 /* superTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = superTest.js; sourceTree = ""; }; 6C6CAC731C5F0BCA00444348 /* JPSuperTestObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPSuperTestObject.m; sourceTree = ""; }; 6C72B7941C352BA80086C98D /* newProtocolTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = newProtocolTest.h; sourceTree = ""; }; 6C72B7951C352BA80086C98D /* newProtocolTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = newProtocolTest.m; sourceTree = ""; }; 6C9C0EE31C25A7C700FCAAC5 /* newProtocolTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newProtocolTest.js; sourceTree = ""; }; DE58B6471B7C312800F64C63 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; DE6FFF021B42B01C0005EE83 /* protocolTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = protocolTest.js; sourceTree = ""; }; DE94AE0B1AF246BF00E461D4 /* JSPatchDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSPatchDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; DE94AE241AF246C000E461D4 /* JSPatchDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JSPatchDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DE94AE291AF246C000E461D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DE94AE2A1AF246C000E461D4 /* JSPatchTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JSPatchTests.m; sourceTree = ""; }; DE94AE431AF2480000E461D4 /* JPTestObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPTestObject.h; sourceTree = ""; }; DE94AE441AF2480000E461D4 /* JPTestObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPTestObject.m; sourceTree = ""; }; DE94AE451AF2480000E461D4 /* test.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = test.js; sourceTree = ""; }; E1B89E9E1B203482000645C2 /* JPMultithreadTestObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPMultithreadTestObject.h; sourceTree = ""; }; E1B89E9F1B203482000645C2 /* JPMultithreadTestObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPMultithreadTestObject.m; sourceTree = ""; }; E1B89EA11B218986000645C2 /* JPInheritanceTestObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPInheritanceTestObjects.h; sourceTree = ""; }; E1B89EA21B218986000645C2 /* JPInheritanceTestObjects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPInheritanceTestObjects.m; sourceTree = ""; }; E1B89EAD1B228818000645C2 /* multithreadTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = multithreadTest.js; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ DE94AE081AF246BF00E461D4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 36F0DCC61BFAF41C0090EA4A /* libz.1.dylib in Frameworks */, 36C59D611E4B517B00A40835 /* libffi.a in Frameworks */, DE58B6481B7C312800F64C63 /* JavaScriptCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; DE94AE211AF246C000E461D4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 2D5D89161B0B8BFF009382EC /* JSPatchDemo */ = { isa = PBXGroup; children = ( 3613C33E1C6329F300E915CB /* Extensions */, 3613C35F1C6329F300E915CB /* JSPatch */, 3613C3631C6329F300E915CB /* Loader */, 2D6D12F91B0B8CF20095A435 /* Supporting Files */, 2D5D89171B0B8BFF009382EC /* AppDelegate.h */, 2D5D89181B0B8BFF009382EC /* AppDelegate.m */, 2D5D891D1B0B8BFF009382EC /* JPViewController.h */, 2D5D891E1B0B8BFF009382EC /* JPViewController.m */, 2D6D13001B0B8CFF0095A435 /* demo.js */, ); path = JSPatchDemo; sourceTree = ""; }; 2D6D12F91B0B8CF20095A435 /* Supporting Files */ = { isa = PBXGroup; children = ( 2D6D12FA1B0B8CF20095A435 /* Images.xcassets */, 2D6D12FB1B0B8CF20095A435 /* Info.plist */, 2D6D12FC1B0B8CF20095A435 /* main.m */, ); path = "Supporting Files"; sourceTree = ""; }; 3613C33E1C6329F300E915CB /* Extensions */ = { isa = PBXGroup; children = ( 36B324F51E290CF3006945DF /* JPLibffi */, 3660BC171E26327800DB3765 /* JPBlock */, 36CC3A131CFEE6A80001465B /* JPCFunction */, 36CC3A301CFEE6A80001465B /* JPCFunctionBinder */, 369EC2951C9925A400334A64 /* JPSpecialInit.h */, 369EC2961C9925A400334A64 /* JPSpecialInit.m */, 3613C3AD1C6346F500E915CB /* JPCleaner.h */, 3613C3AE1C6346F500E915CB /* JPCleaner.m */, 3646F8B21CA0F89C00E10774 /* JPLocker.h */, 3646F8B31CA0F89C00E10774 /* JPLocker.m */, 4F9EBFC31D50745200EC72C1 /* JPNumber.h */, 4F9EBFC41D50745200EC72C1 /* JPNumber.m */, 360BCF4C1D82DCFC00202977 /* JPDispatch.h */, 360BCF4D1D82DCFC00202977 /* JPDispatch.m */, 360BCF521D82EFCD00202977 /* JPProtocol.h */, 360BCF531D82EFCD00202977 /* JPProtocol.m */, ); name = Extensions; path = ../../../Extensions; sourceTree = ""; }; 3613C35F1C6329F300E915CB /* JSPatch */ = { isa = PBXGroup; children = ( 3613C3601C6329F300E915CB /* JPEngine.h */, 3613C3611C6329F300E915CB /* JPEngine.m */, 3613C3621C6329F300E915CB /* JSPatch.js */, ); name = JSPatch; path = ../../../JSPatch; sourceTree = ""; }; 3613C3631C6329F300E915CB /* Loader */ = { isa = PBXGroup; children = ( 3613C3641C6329F300E915CB /* JPLoader.h */, 3613C3651C6329F300E915CB /* JPLoader.m */, 3613C3661C6329F300E915CB /* libs */, 3613C3751C6329F300E915CB /* tools */, ); name = Loader; path = ../../../Loader; sourceTree = ""; }; 3613C3661C6329F300E915CB /* libs */ = { isa = PBXGroup; children = ( 3613C3671C6329F300E915CB /* minizip */, 3613C3711C6329F300E915CB /* RSA.h */, 3613C3721C6329F300E915CB /* RSA.m */, 3613C3731C6329F300E915CB /* ZipArchive.h */, 3613C3741C6329F300E915CB /* ZipArchive.m */, ); path = libs; sourceTree = ""; }; 3613C3671C6329F300E915CB /* minizip */ = { isa = PBXGroup; children = ( 3613C3681C6329F300E915CB /* crypt.h */, 3613C3691C6329F300E915CB /* ioapi.c */, 3613C36A1C6329F300E915CB /* ioapi.h */, 3613C36B1C6329F300E915CB /* mztools.c */, 3613C36C1C6329F300E915CB /* mztools.h */, 3613C36D1C6329F300E915CB /* unzip.c */, 3613C36E1C6329F300E915CB /* unzip.h */, 3613C36F1C6329F300E915CB /* zip.c */, 3613C3701C6329F300E915CB /* zip.h */, ); path = minizip; sourceTree = ""; }; 3613C3751C6329F300E915CB /* tools */ = { isa = PBXGroup; children = ( 3613C3761C6329F300E915CB /* packer.php */, ); path = tools; sourceTree = ""; }; 3660BC171E26327800DB3765 /* JPBlock */ = { isa = PBXGroup; children = ( 3660BC2B1E2634C900DB3765 /* JPBlock.h */, 3660BC2C1E2634C900DB3765 /* JPBlock.m */, 367650461E2CC3BD00828E12 /* JPBlockWrapper.h */, 367650471E2CC3BD00828E12 /* JPBlockWrapper.m */, ); path = JPBlock; sourceTree = ""; }; 36B324F51E290CF3006945DF /* JPLibffi */ = { isa = PBXGroup; children = ( 36C59D551E4B517B00A40835 /* libffi */, 36B3252B1E290D0C006945DF /* JPMethodSignature.h */, 36B3252C1E290D0C006945DF /* JPMethodSignature.m */, ); path = JPLibffi; sourceTree = ""; }; 36C59D551E4B517B00A40835 /* libffi */ = { isa = PBXGroup; children = ( 36C59D561E4B517B00A40835 /* ffi.h */, 36C59D571E4B517B00A40835 /* ffi_arm.h */, 36C59D581E4B517B00A40835 /* ffi_arm64.h */, 36C59D591E4B517B00A40835 /* ffi_i386.h */, 36C59D5A1E4B517B00A40835 /* ffi_x86_64.h */, 36C59D5B1E4B517B00A40835 /* ffitarget.h */, 36C59D5C1E4B517B00A40835 /* ffitarget_arm.h */, 36C59D5D1E4B517B00A40835 /* ffitarget_arm64.h */, 36C59D5E1E4B517B00A40835 /* ffitarget_i386.h */, 36C59D5F1E4B517B00A40835 /* ffitarget_x86_64.h */, 36C59D601E4B517B00A40835 /* libffi.a */, ); path = libffi; sourceTree = ""; }; 36CC3A131CFEE6A80001465B /* JPCFunction */ = { isa = PBXGroup; children = ( 36CC3A141CFEE6A80001465B /* JPCFunction.h */, 36CC3A151CFEE6A80001465B /* JPCFunction.m */, 36CC3A161CFEE6A80001465B /* JPMemory.h */, 36CC3A171CFEE6A80001465B /* JPMemory.m */, 36CC3A181CFEE6A80001465B /* JPStructPointer.h */, 36CC3A191CFEE6A80001465B /* JPStructPointer.m */, ); path = JPCFunction; sourceTree = ""; }; 36CC3A301CFEE6A80001465B /* JPCFunctionBinder */ = { isa = PBXGroup; children = ( 36CC3A311CFEE6A80001465B /* CoreGraphics */, 36CC3A421CFEE6A80001465B /* UIKit */, ); path = JPCFunctionBinder; sourceTree = ""; }; 36CC3A311CFEE6A80001465B /* CoreGraphics */ = { isa = PBXGroup; children = ( 36CC3A321CFEE6A80001465B /* JPCGBitmapContext.h */, 36CC3A331CFEE6A80001465B /* JPCGBitmapContext.m */, 36CC3A341CFEE6A80001465B /* JPCGColor.h */, 36CC3A351CFEE6A80001465B /* JPCGColor.m */, 36CC3A361CFEE6A80001465B /* JPCGContext.h */, 36CC3A371CFEE6A80001465B /* JPCGContext.m */, 36CC3A381CFEE6A80001465B /* JPCGGeometry.h */, 36CC3A391CFEE6A80001465B /* JPCGGeometry.m */, 36CC3A3A1CFEE6A80001465B /* JPCGImage.h */, 36CC3A3B1CFEE6A80001465B /* JPCGImage.m */, 36CC3A3C1CFEE6A80001465B /* JPCGPath.h */, 36CC3A3D1CFEE6A80001465B /* JPCGPath.m */, 36CC3A3E1CFEE6A80001465B /* JPCGTransform.h */, 36CC3A3F1CFEE6A80001465B /* JPCGTransform.m */, 36CC3A401CFEE6A80001465B /* JPCoreGraphics.h */, 36CC3A411CFEE6A80001465B /* JPCoreGraphics.m */, ); path = CoreGraphics; sourceTree = ""; }; 36CC3A421CFEE6A80001465B /* UIKit */ = { isa = PBXGroup; children = ( 36CC3A431CFEE6A80001465B /* JPUIGeometry.h */, 36CC3A441CFEE6A80001465B /* JPUIGeometry.m */, 36CC3A451CFEE6A80001465B /* JPUIGraphics.h */, 36CC3A461CFEE6A80001465B /* JPUIGraphics.m */, 36CC3A471CFEE6A80001465B /* JPUIImage.h */, 36CC3A481CFEE6A80001465B /* JPUIImage.m */, 36CC3A491CFEE6A80001465B /* JPUIKit.h */, 36CC3A4A1CFEE6A80001465B /* JPUIKit.m */, ); path = UIKit; sourceTree = ""; }; DE94AE021AF246BE00E461D4 = { isa = PBXGroup; children = ( 36F0DCC51BFAF41C0090EA4A /* libz.1.dylib */, DE58B6471B7C312800F64C63 /* JavaScriptCore.framework */, 2D5D89161B0B8BFF009382EC /* JSPatchDemo */, DE94AE271AF246C000E461D4 /* JSPatchTests */, DE94AE0C1AF246BF00E461D4 /* Products */, ); sourceTree = ""; }; DE94AE0C1AF246BF00E461D4 /* Products */ = { isa = PBXGroup; children = ( DE94AE0B1AF246BF00E461D4 /* JSPatchDemo.app */, DE94AE241AF246C000E461D4 /* JSPatchDemoTests.xctest */, ); name = Products; sourceTree = ""; }; DE94AE271AF246C000E461D4 /* JSPatchTests */ = { isa = PBXGroup; children = ( 4F9EBFC61D50749200EC72C1 /* JPNumberTest.h */, 4F9EBFC71D50749200EC72C1 /* JPNumberTest.m */, 4F9EBFC81D50749200EC72C1 /* jsNumberTest.js */, 3694925C1CFEFE42003F44CA /* JPCFunctionTest.h */, 3694925D1CFEFE42003F44CA /* JPCFunctionTest.m */, 3694925E1CFEFE42003F44CA /* jsCFunctionTest.js */, 36CE191C1CAEA1DE007D73AC /* JPJSClassTest.h */, 36CE191D1CAEA1DE007D73AC /* JPJSClassTest.m */, 36CE191A1CAEA179007D73AC /* jsClassTest.js */, 6C6CAC711C5F0BCA00444348 /* JPSuperTestObject.h */, 6C6CAC731C5F0BCA00444348 /* JPSuperTestObject.m */, 6C6CAC721C5F0BCA00444348 /* superTest.js */, 36CE19231CB3E709007D73AC /* JPPerformanceTest.h */, 36CE19241CB3E709007D73AC /* JPPerformanceTest.m */, 36CE19261CB3E72B007D73AC /* performanceTest.js */, 2DA3C429206A1892005877CB /* newBlockTest.h */, 2DA3C42A206A1892005877CB /* newBlockTest.m */, 2DA3C433206B5569005877CB /* newBlockTest.js */, 6C72B7941C352BA80086C98D /* newProtocolTest.h */, 6C72B7951C352BA80086C98D /* newProtocolTest.m */, 6C9C0EE31C25A7C700FCAAC5 /* newProtocolTest.js */, E1B89E9E1B203482000645C2 /* JPMultithreadTestObject.h */, E1B89E9F1B203482000645C2 /* JPMultithreadTestObject.m */, DE94AE431AF2480000E461D4 /* JPTestObject.h */, DE94AE441AF2480000E461D4 /* JPTestObject.m */, E1B89EA11B218986000645C2 /* JPInheritanceTestObjects.h */, E1B89EA21B218986000645C2 /* JPInheritanceTestObjects.m */, DE6FFF021B42B01C0005EE83 /* protocolTest.js */, 2D0DF7061B22F75C005695DA /* inheritTest.js */, DE94AE451AF2480000E461D4 /* test.js */, E1B89EAD1B228818000645C2 /* multithreadTest.js */, DE94AE2A1AF246C000E461D4 /* JSPatchTests.m */, DE94AE281AF246C000E461D4 /* Supporting Files */, ); path = JSPatchTests; sourceTree = ""; }; DE94AE281AF246C000E461D4 /* Supporting Files */ = { isa = PBXGroup; children = ( DE94AE291AF246C000E461D4 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ DE94AE0A1AF246BF00E461D4 /* JSPatchDemo */ = { isa = PBXNativeTarget; buildConfigurationList = DE94AE2E1AF246C000E461D4 /* Build configuration list for PBXNativeTarget "JSPatchDemo" */; buildPhases = ( DE94AE071AF246BF00E461D4 /* Sources */, DE94AE081AF246BF00E461D4 /* Frameworks */, DE94AE091AF246BF00E461D4 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = JSPatchDemo; productName = JSPatch; productReference = DE94AE0B1AF246BF00E461D4 /* JSPatchDemo.app */; productType = "com.apple.product-type.application"; }; DE94AE231AF246C000E461D4 /* JSPatchTests */ = { isa = PBXNativeTarget; buildConfigurationList = DE94AE311AF246C000E461D4 /* Build configuration list for PBXNativeTarget "JSPatchTests" */; buildPhases = ( DE94AE201AF246C000E461D4 /* Sources */, DE94AE211AF246C000E461D4 /* Frameworks */, DE94AE221AF246C000E461D4 /* Resources */, ); buildRules = ( ); dependencies = ( DE94AE261AF246C000E461D4 /* PBXTargetDependency */, ); name = JSPatchTests; productName = JSPatchTests; productReference = DE94AE241AF246C000E461D4 /* JSPatchDemoTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ DE94AE031AF246BF00E461D4 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0620; ORGANIZATIONNAME = bang; TargetAttributes = { DE94AE0A1AF246BF00E461D4 = { CreatedOnToolsVersion = 6.2; }; DE94AE231AF246C000E461D4 = { CreatedOnToolsVersion = 6.2; TestTargetID = DE94AE0A1AF246BF00E461D4; }; }; }; buildConfigurationList = DE94AE061AF246BF00E461D4 /* Build configuration list for PBXProject "JSPatchDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = DE94AE021AF246BE00E461D4; productRefGroup = DE94AE0C1AF246BF00E461D4 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( DE94AE0A1AF246BF00E461D4 /* JSPatchDemo */, DE94AE231AF246C000E461D4 /* JSPatchTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ DE94AE091AF246BF00E461D4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 6C9C0EE51C25A7DA00FCAAC5 /* newProtocolTest.js in Resources */, 3613C3871C6329F300E915CB /* JSPatch.js in Resources */, 3613C38F1C6329F300E915CB /* packer.php in Resources */, DE6FFF051B42C25D0005EE83 /* protocolTest.js in Resources */, 2D6D12FD1B0B8CF20095A435 /* Images.xcassets in Resources */, 2D6D13011B0B8CFF0095A435 /* demo.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; DE94AE221AF246C000E461D4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( DE6FFF031B42B01C0005EE83 /* protocolTest.js in Resources */, 2D0DF7071B22F75C005695DA /* inheritTest.js in Resources */, 6C6CAC741C5F0BCA00444348 /* superTest.js in Resources */, DE94AE471AF2480000E461D4 /* test.js in Resources */, 36CE191B1CAEA179007D73AC /* jsClassTest.js in Resources */, 6C9C0EE41C25A7C700FCAAC5 /* newProtocolTest.js in Resources */, 4F9EBFCA1D50749200EC72C1 /* jsNumberTest.js in Resources */, E1B89EAE1B228818000645C2 /* multithreadTest.js in Resources */, 369492601CFEFE42003F44CA /* jsCFunctionTest.js in Resources */, 36CE19271CB3E72B007D73AC /* performanceTest.js in Resources */, 2DA3C434206B5569005877CB /* newBlockTest.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ DE94AE071AF246BF00E461D4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 36CC3A591CFEE6A80001465B /* JPUIImage.m in Sources */, 360BCF4E1D82DCFC00202977 /* JPDispatch.m in Sources */, 3613C3AF1C6346F500E915CB /* JPCleaner.m in Sources */, 2D5D89211B0B8BFF009382EC /* AppDelegate.m in Sources */, 36CC3A511CFEE6A80001465B /* JPCGContext.m in Sources */, 3613C38E1C6329F300E915CB /* ZipArchive.m in Sources */, 3613C3861C6329F300E915CB /* JPEngine.m in Sources */, 36CC3A531CFEE6A80001465B /* JPCGImage.m in Sources */, 36CC3A541CFEE6A80001465B /* JPCGPath.m in Sources */, 3613C3881C6329F300E915CB /* JPLoader.m in Sources */, 36CC3A501CFEE6A80001465B /* JPCGColor.m in Sources */, 4F9EBFC51D50745200EC72C1 /* JPNumber.m in Sources */, 36CC3A521CFEE6A80001465B /* JPCGGeometry.m in Sources */, 360BCF541D82EFCD00202977 /* JPProtocol.m in Sources */, E1B89EA01B203482000645C2 /* JPMultithreadTestObject.m in Sources */, 3660BC2D1E2634C900DB3765 /* JPBlock.m in Sources */, 3613C38B1C6329F300E915CB /* unzip.c in Sources */, 36CC3A4C1CFEE6A80001465B /* JPMemory.m in Sources */, 36CC3A5A1CFEE6A80001465B /* JPUIKit.m in Sources */, 36CC3A4D1CFEE6A80001465B /* JPStructPointer.m in Sources */, 36CC3A571CFEE6A80001465B /* JPUIGeometry.m in Sources */, 36CC3A551CFEE6A80001465B /* JPCGTransform.m in Sources */, 36CC3A561CFEE6A80001465B /* JPCoreGraphics.m in Sources */, 3613C38D1C6329F300E915CB /* RSA.m in Sources */, 3613C3891C6329F300E915CB /* ioapi.c in Sources */, 36CC3A4F1CFEE6A80001465B /* JPCGBitmapContext.m in Sources */, 2D5D89251B0B8BFF009382EC /* JPViewController.m in Sources */, 3613C38A1C6329F300E915CB /* mztools.c in Sources */, 36CC3A581CFEE6A80001465B /* JPUIGraphics.m in Sources */, 36CC3A4B1CFEE6A80001465B /* JPCFunction.m in Sources */, 36B3252D1E290D0C006945DF /* JPMethodSignature.m in Sources */, 3613C38C1C6329F300E915CB /* zip.c in Sources */, 2D6D12FF1B0B8CF20095A435 /* main.m in Sources */, 3646F8B41CA0F89C00E10774 /* JPLocker.m in Sources */, 367650481E2CC3BD00828E12 /* JPBlockWrapper.m in Sources */, 369EC2971C9925A400334A64 /* JPSpecialInit.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DE94AE201AF246C000E461D4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 6C6CAC751C5F0BCA00444348 /* JPSuperTestObject.m in Sources */, 6C72B7961C352BA80086C98D /* newProtocolTest.m in Sources */, DE94AE461AF2480000E461D4 /* JPTestObject.m in Sources */, 36CE191E1CAEA1DE007D73AC /* JPJSClassTest.m in Sources */, 36CE19251CB3E709007D73AC /* JPPerformanceTest.m in Sources */, E1B89EA31B218986000645C2 /* JPInheritanceTestObjects.m in Sources */, 4F9EBFC91D50749200EC72C1 /* JPNumberTest.m in Sources */, DE94AE2B1AF246C000E461D4 /* JSPatchTests.m in Sources */, 2DA3C42B206A1892005877CB /* newBlockTest.m in Sources */, 3694925F1CFEFE42003F44CA /* JPCFunctionTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ DE94AE261AF246C000E461D4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DE94AE0A1AF246BF00E461D4 /* JSPatchDemo */; targetProxy = DE94AE251AF246C000E461D4 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ DE94AE2C1AF246C000E461D4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; DE94AE2D1AF246C000E461D4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; DE94AE2F1AF246C000E461D4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; INFOPLIST_FILE = "$(SRCROOT)/JSPatchDemo/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_GENERATE_MAP_FILE = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", "../../**", ); ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = ""; PRODUCT_NAME = JSPatchDemo; }; name = Debug; }; DE94AE301AF246C000E461D4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "$(SRCROOT)/JSPatchDemo/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_GENERATE_MAP_FILE = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", "../../**", ); ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = ""; PRODUCT_NAME = JSPatchDemo; }; name = Release; }; DE94AE321AF246C000E461D4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = JSPatchTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = JSPatchDemoTests; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JSPatchDemo.app/JSPatchDemo"; }; name = Debug; }; DE94AE331AF246C000E461D4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = JSPatchTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = JSPatchDemoTests; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JSPatchDemo.app/JSPatchDemo"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ DE94AE061AF246BF00E461D4 /* Build configuration list for PBXProject "JSPatchDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( DE94AE2C1AF246C000E461D4 /* Debug */, DE94AE2D1AF246C000E461D4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DE94AE2E1AF246C000E461D4 /* Build configuration list for PBXNativeTarget "JSPatchDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( DE94AE2F1AF246C000E461D4 /* Debug */, DE94AE301AF246C000E461D4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DE94AE311AF246C000E461D4 /* Build configuration list for PBXNativeTarget "JSPatchTests" */ = { isa = XCConfigurationList; buildConfigurations = ( DE94AE321AF246C000E461D4 /* Debug */, DE94AE331AF246C000E461D4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = DE94AE031AF246BF00E461D4 /* Project object */; } ================================================ FILE: Demo/iOSDemo/JSPatchDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/iOSDemo/JSPatchDemo.xcodeproj/xcshareddata/xcschemes/JSPatchDemo.xcscheme ================================================ ================================================ FILE: Demo/iOSDemo/JSPatchTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier net.cnbang.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Demo/iOSDemo/JSPatchTests/InheritTest.js ================================================ var global = this; (function() { defineClass("JPInheritTest01ObjectB", { m1: function() { return "JP_01ObjB_m1"; } }); defineClass("JPInheritTest02ObjectB", { m1: function() { return "JP_02ObjB_m1"; } }); defineClass("JPInheritTest02ObjectC", { m2: function() { return "JP_02ObjC_m2"; } }); })(); (function(){ defineClass("JPInheritTest02ObjectB", { m1:function(){ return "JP_02ObjB_m1"; }, m3:function(){ return "JP_02ObjC_m3"; } }, {}); defineClass("JPInheritTest02ObjectC", { m2:function(){ return "JP_02ObjC_m2"; }, m3:function(){ return self.super().m3(); } }, {}); })(); (function(){ defineClass("JPInheritTest03ObjectB", { m1:function(){ return "JP_03ObjB_m1"; } }, {}); defineClass("JPInheritTest03ObjectC", { m2:function(){ return "JP_03ObjC_m2"; } }, {}); })(); ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPCFunctionTest.h ================================================ // // JPCFunctionTest.h // JSPatchDemo // // Created by bang on 6/1/16. // Copyright © 2016 bang. All rights reserved. // #import @interface JPCFunctionTest : NSObject + (BOOL)testCfuncWithCGSize; + (BOOL)testCfuncWithCGRect; + (BOOL)testCfuncWithId; + (BOOL)testCfuncWithInt; + (BOOL)testCfuncWithCGFloat; + (BOOL)testCfuncReturnPointer; + (BOOL)testCFunctionReturnClass; + (BOOL)testCFunctionVoid; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPCFunctionTest.m ================================================ // // JPCFunctionTest.m // JSPatchDemo // // Created by bang on 6/1/16. // Copyright © 2016 bang. All rights reserved. // #import "JPCFunctionTest.h" #import #import "JPEngine.h" static bool voidFuncRet = false; CGSize cfuncWithCGSize(CGSize size){ return size; } CGRect cfuncWithCGRect(CGRect rect){ return rect; } id cfuncWithId(NSString *str){ return str; } int cfuncWithInt(int num) { return num; } CGFloat cfuncWithCGFloat(CGFloat num) { return num; } void *cfuncReturnPointer() { char *a = "abc"; return a; } bool cfuncWithPointerIsEqual(char *a) { return a[0] == 'a'; } void cfuncVoid() { NSLog(@"dsssdfsdf"); } @implementation JPCFunctionTest + (BOOL)testCfuncWithCGSize{ return NO; } + (BOOL)testCfuncWithCGRect{ return NO; } + (BOOL)testCfuncWithId{ return NO; }; + (BOOL)testCfuncWithInt{ return NO; }; + (BOOL)testCfuncWithCGFloat{ return NO; }; + (BOOL)testCfuncReturnPointer{ return NO; }; + (BOOL)testCFunctionReturnClass{ return NO; }; + (BOOL)testCFunctionVoid{ return voidFuncRet; }; + (void)setupCFunctionVoidSucc{ voidFuncRet = true; } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPInheritanceTestObjects.h ================================================ // // JPInheritanceTestObjects.h // JSPatchDemo // // Created by Qiu WeiJia on 6/5/15. // Copyright (c) 2015 bang. All rights reserved. // #import @interface JPInheritTest01ObjectA : NSObject - (NSString*)m1; - (NSString*)m2; @end @interface JPInheritTest01ObjectB : JPInheritTest01ObjectA - (NSString*)m1; @end @interface JPInheritTest02ObjectA : NSObject - (NSString*)m1; - (NSString*)m2; - (NSString*)m3; @end @interface JPInheritTest02ObjectB : JPInheritTest02ObjectA - (NSString*)m1; - (NSString*)m3; @end @interface JPInheritTest02ObjectC : JPInheritTest02ObjectB - (NSString*)m2; @end @interface JPInheritTest03ObjectA : NSObject - (NSString*)m1; - (NSString*)m2; @end @interface JPInheritTest03ObjectB : JPInheritTest03ObjectA - (NSString*)m1; @end @interface JPInheritTest03ObjectC : JPInheritTest03ObjectA - (NSString*)m2; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPInheritanceTestObjects.m ================================================ // // JPInheritanceTestObjects.m // JSPatchDemo // // Created by Qiu WeiJia on 6/5/15. // Copyright (c) 2015 bang. All rights reserved. // #import "JPInheritanceTestObjects.h" @implementation JPInheritTest01ObjectA - (NSString*)m1 { return @"01ObjA_m1"; } - (NSString*)m2 { return @"01ObjA_m2"; } @end @implementation JPInheritTest01ObjectB - (NSString*)m1 { return @"01ObjB_m1"; } @end @implementation JPInheritTest02ObjectA - (NSString*)m1 { return @"02ObjA_m1"; } - (NSString*)m2 { return @"02ObjA_m2"; } - (NSString*)m3 { return @"02ObjA_m3"; } @end @implementation JPInheritTest02ObjectB - (NSString*)m1 { return @"02ObjB_m1"; } - (NSString*)m3 { return @"02ObjB_m3"; } @end @implementation JPInheritTest02ObjectC - (NSString*)m2 { return @"02ObjC_m2"; } @end @implementation JPInheritTest03ObjectA - (NSString*)m1 { return @"03ObjA_m1"; } - (NSString*)m2 { return @"03ObjA_m2"; } @end @implementation JPInheritTest03ObjectB - (NSString*)m1 { return @"03ObjB_m1"; } @end @implementation JPInheritTest03ObjectC - (NSString*)m2 { return @"03ObjC_m2"; } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPJSClassTest.h ================================================ // // JPJSClassTest.h // JSPatchDemo // // Created by bang on 4/1/16. // Copyright © 2016 bang. All rights reserved. // #import @interface JPJSClassTest : NSObject + (BOOL)isPassA; + (BOOL)isPassB; + (BOOL)isPassC; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPJSClassTest.m ================================================ // // JPJSClassTest.m // JSPatchDemo // // Created by bang on 4/1/16. // Copyright © 2016 bang. All rights reserved. // #import "JPJSClassTest.h" @implementation JPJSClassTest + (BOOL)isPassA { return NO; } + (BOOL)isPassB { return NO; } + (BOOL)isPassC { return NO; } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPMultithreadTestObject.h ================================================ // // MultithreadTestObject.h // JSPatchDemo // // Created by Qiu WeiJia on 15/6/4. // Copyright (c) 2015年 bang. All rights reserved. // #import @interface JPMultithreadTestObject : NSObject { NSMutableArray *_values; } @property int objectId; - (instancetype)init; - (void)addValueJS:(NSNumber*)number; - (void)addValue:(NSNumber*)number; - (void)addValueNoPatch:(NSNumber*)number; - (BOOL)checkAllValues; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPMultithreadTestObject.m ================================================ // // MultithreadTestObject.m // JSPatchDemo // // Created by Qiu WeiJia on 15/6/4. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPMultithreadTestObject.h" @implementation JPMultithreadTestObject - (instancetype)init { self = [super init]; if (self) { _values = [[NSMutableArray alloc] init]; [_values addObject:[NSNumber numberWithInt:-1]]; } return self; } - (void)addValueJS:(NSNumber*)number { } - (void)addValue:(NSNumber*)number { if ([_values count] > 0 && [[_values objectAtIndex:0] integerValue] < 0) { [_values removeAllObjects]; } [_values addObject:number]; } - (void)addValueNoPatch:(NSNumber*)number { [_values addObject:number]; } - (BOOL)checkAllValues { for (NSNumber *num in _values) { if ([num intValue] != self.objectId) { return FALSE; } } return TRUE; } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPNumberTest.h ================================================ // // JPNumberTest.h // JSPatchDemo // // Created by pucheng on 16/8/2. // Copyright © 2016年 bang. All rights reserved. // #import @interface JPNumberTest : NSObject + (BOOL)testJPNumNSNumber; + (BOOL)testJPNumNSDecimalNumber; + (BOOL)testJPNumToJS; + (BOOL)testJPNUmToOC; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPNumberTest.m ================================================ // // JPNumberTest.m // JSPatchDemo // // Created by pucheng on 16/8/2. // Copyright © 2016年 bang. All rights reserved. // #import "JPNumberTest.h" @implementation JPNumberTest + (BOOL)testJPNumNSNumber { return NO; } + (BOOL)testJPNumNSDecimalNumber { return NO; } + (BOOL)testJPNumToJS { return NO; } + (BOOL)testJPNUmToOC { return NO; } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h ================================================ // // JPPerformanceTest.h // JSPatchDemo // // Created by bang on 4/5/16. // Copyright © 2016 bang. All rights reserved. // #import @interface JPPerformanceTest : NSObject - (void)testJSCallOCEmptyMethod; - (void)testJSCallOCMethodWithParamObject; - (void)testJSCallOCMethodReturnObject; - (void)testJSCallJSEmptyMethod; - (void)testJSCallJSMethodWithLargeDictionaryParam; - (void)testJSCallJSMethodWithLargeDictionaryParamAutoConvert; - (void)testJSCallJSMethodWithParam; - (void)testOCCallEmptyMethod; - (void)testOCCallMethodWithParamObject; - (void)testOCCallMethodReturnObject; - (void)testJSCallMallocJPMemory; - (void)testJSCallMallocJPCFunction; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m ================================================ // // JPPerformanceTest.m // JSPatchDemo // // Created by bang on 4/5/16. // Copyright © 2016 bang. All rights reserved. // #import "JPPerformanceTest.h" #import @implementation JPPerformanceTest //overrided in JS - (void)testJSCallOCEmptyMethod {} - (void)testJSCallOCMethodWithParamObject{} - (void)testJSCallOCMethodReturnObject{} - (void)testJSCallJSEmptyMethod{} - (void)testJSCallJSMethodWithLargeDictionaryParam{} - (void)testJSCallJSMethodWithLargeDictionaryParamAutoConvert{} - (void)testJSCallJSMethodWithParam{} - (void)testOCCallEmptyMethod { for (int i = 0; i < 10000; i ++) { [self emptyMethodToOverride]; } } - (void)testOCCallMethodWithParamObject { NSObject *obj = [[NSObject alloc] init]; for (int i = 0; i < 10000; i ++) { [self methodWithParamObjectToOverride:obj]; } } - (void)testOCCallMethodReturnObject { id ret; for (int i = 0; i < 10000; i ++) { ret = [self methodReturnObjectToOverride]; } } - (void)testJSCallMallocJPMemory{} - (void)testJSCallMallocJPCFunction{} #pragma mark performance static NSObject *testPerformanceObj; - (void)initTestPerformanceObj { if (!testPerformanceObj) testPerformanceObj = [[NSObject alloc] init]; } - (void)emptyMethod { } - (void)methodWithParamObject:(NSObject *)obj { } - (NSObject *)methodReturnObject { return testPerformanceObj; } - (void)emptyMethodToOverride { } - (void)methodWithParamObjectToOverride:(NSObject *)obj { } - (NSObject *)methodReturnObjectToOverride { return nil; } - (void)allArgSumWithBlock:(double (^)(CGFloat arg0, CGPoint arg1, NSInteger arg2, id arg3))block { NSNumber *arg3 = [NSNumber numberWithDouble:3.3]; double sum = block(3.2, (CGPoint){1.1,1.2}, 10,arg3); NSLog(@"==== sum = %@",@(sum)); } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPSuperTestObject.h ================================================ // // JPSuperTestObject.h // JSPatchDemo // // Created by bang on 4/1/16. // Copyright © 2016 bang. All rights reserved. // #import @interface JPSuperTestA : NSObject @end @interface JPSuperTestB : NSObject @end @interface JPSuperTestB1 : JPSuperTestB @end @interface JPSuperTestC : NSObject @end @interface JPSuperTestC1 : JPSuperTestC @end @interface JPSuperTestC2 : JPSuperTestC1 @end @interface JPSuperTestResult : NSObject + (BOOL)isPassA; + (BOOL)isPassB; + (BOOL)isPassC; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPSuperTestObject.m ================================================ // // JPSuperTestObject.m // JSPatchDemo // // Created by bang on 4/1/16. // Copyright © 2016 bang. All rights reserved. // #import "JPSuperTestObject.h" @implementation JPSuperTestA - (NSString *)method { return @"A"; } @end @implementation JPSuperTestB - (NSString *)method { return @"B"; } @end @implementation JPSuperTestB1 - (NSString *)method { return [NSString stringWithFormat:@"%@%@", [super method], @"1"]; } @end @implementation JPSuperTestC - (NSString *)method { return @"C"; } @end @implementation JPSuperTestC1 - (NSString *)method { return [NSString stringWithFormat:@"%@%@", [super method], @"1"]; } @end @implementation JPSuperTestC2 - (NSString *)method { return [NSString stringWithFormat:@"%@%@", [super method], @"2"]; } @end @implementation JPSuperTestResult + (BOOL)isPassA { return NO; } + (BOOL)isPassB { return NO; } + (BOOL)isPassC { JPSuperTestC2 *c = [[JPSuperTestC2 alloc] init]; return [[c method] isEqualToString:@"C1C2"]; } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPTestObject.h ================================================ // // ISTestObject.h // InstaScript // // Created by bang on 15/4/30. // Copyright (c) 2015 bang. All rights reserved. // #import #import @interface JPTestObject : NSObject - (void)funcWithInt:(int)intValue; @property (nonatomic, assign) BOOL funcReturnVoidPassed; @property (nonatomic, assign) BOOL funcReturnStringPassed; @property (nonatomic, assign) BOOL funcReturnDoublePassed; @property (nonatomic, assign) BOOL funcReturnClassPassed; @property (nonatomic, assign) BOOL funcReturnViewWithFramePassed; @property (nonatomic, assign) BOOL funcWithViewAndReturnViewPassed; @property (nonatomic, assign) BOOL funcWithIntPassed; @property (nonatomic, assign) BOOL funcWithNilPassed; @property (nonatomic, assign) BOOL funcReturnNilPassed; @property (nonatomic, assign) BOOL funcWithNilAndOthersPassed; @property (nonatomic, assign) BOOL funcWithNullPassed; @property (nonatomic, assign) BOOL funcTestBoolPassed; @property (nonatomic, assign) BOOL funcTestNSNumberPassed; @property (nonatomic, assign) BOOL funcWithDictAndDoublePassed; @property (nonatomic, assign) BOOL funcWithRangeAndReturnRangePassed; @property (nonatomic, assign) BOOL funcWithRectAndReturnRectPassed; @property (nonatomic, assign) BOOL funcWithPointAndReturnPointPassed; @property (nonatomic, assign) BOOL funcWithSizeAndReturnSizePassed; @property (nonatomic, assign) BOOL funcWithClassAndReturnStringPassed; @property (nonatomic, assign) BOOL funcReturnDictStringIntPassed; @property (nonatomic, assign) BOOL funcReturnDictStringViewPassed; @property (nonatomic, assign) BOOL funcReturnArrayControllerViewStringPassed; @property (nonatomic, assign) BOOL funcReturnDictPassed; @property (nonatomic, assign) BOOL testBoxingObjPassed; @property (nonatomic, assign) BOOL funcReturnBlockPassed; @property (nonatomic, assign) BOOL funcReturnObjectBlockPassed; @property (nonatomic, assign) BOOL funcReturnObjectBlockReturnValuePassed; @property (nonatomic, assign) BOOL funcReturnJSBlockPassed; @property (nonatomic, assign) BOOL callBlockWithStringAndIntPassed; @property (nonatomic, assign) BOOL callBlockWithStringAndIntReturnValuePassed; @property (nonatomic, assign) BOOL callBlockWithArrayAndViewPassed; @property (nonatomic, assign) BOOL callBlockWithBoolAndBlockPassed; @property (nonatomic, assign) BOOL callBlockWithObjectAndBlockPassed; @property (nonatomic, assign) BOOL callBlockWithObjectAndBlockReturnValuePassed; @property (nonatomic, assign) BOOL callBlockWithDoubleAndReturnDoublePassed; @property (nonatomic, assign) BOOL funcToSwizzleWithStringViewIntPassed; @property (nonatomic, assign) BOOL funcToSwizzleViewPassed; @property (nonatomic, assign) BOOL funcToSwizzleViewCalledOriginalPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnViewPassed; @property (nonatomic, assign) BOOL funcToSwizzleParamNilPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnIntPassed; @property (nonatomic, assign) BOOL funcToSwizzleWithBlockPassed; @property (nonatomic, assign) BOOL funcToSwizzle_withUnderLine_Passed; @property (nonatomic, assign) BOOL funcToSwizzleReturnRectPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnPointPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnSizePassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnRangePassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnEdgeInsetsPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnRectJSPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnPointJSPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnSizeJSPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnRangeJSPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnEdgeInsetsJSPassed; @property (nonatomic, assign) BOOL funcToSwizzleTestGCDPassed; @property (nonatomic, assign) BOOL funcToSwizzleTestClassPassed; @property (nonatomic, assign) BOOL funcToSwizzleTestSelectorPassed; @property (nonatomic, assign) BOOL funcToSwizzleTestCharPassed; @property (nonatomic, assign) BOOL funcToSwizzleReturnClassPassed; @property (nonatomic, assign) BOOL funcTestCharPassed; @property (nonatomic, assign) BOOL funcToSwizzleTestPointerPassed; @property (nonatomic, assign) BOOL funcTestPointerPassed; @property (nonatomic, assign) BOOL funcTestSizeofPassed; @property (nonatomic, assign) BOOL funcTestGetPointerPassed; @property (nonatomic, assign) BOOL funcTestNSErrorPointerPassed; @property (nonatomic, assign) BOOL funcTestNilParametersInBlockPassed; @property (nonatomic, assign) BOOL classFuncToSwizzlePassed; @property (nonatomic, assign) BOOL classFuncToSwizzleReturnObjPassed; @property (nonatomic, assign) BOOL classFuncToSwizzleReturnObjCalledOriginalPassed; @property (nonatomic, assign) BOOL classFuncToSwizzleReturnIntPassed; @property (nonatomic, assign) BOOL classFuncToSwizzleReturnDoublePassed; @property (nonatomic, assign) BOOL funcCallSuperPassed; @property (nonatomic, assign) BOOL callForwardInvocationPassed; @property (nonatomic, strong) UIView *testView; @property (nonatomic, assign) BOOL propertySetFramePassed; @property (nonatomic, assign) BOOL propertySetViewPassed; @property (nonatomic, assign) BOOL newTestObjectReturnViewPassed; @property (nonatomic, assign) BOOL newTestObjectReturnBoolPassed; @property (nonatomic, assign) BOOL newTestObjectCustomFuncPassed; @property (nonatomic, assign) BOOL mutableArrayPassed; @property (nonatomic, assign) BOOL mutableStringPassed; @property (nonatomic, assign) BOOL mutableDictionaryPassed; @property (nonatomic, assign) BOOL funcWithTransformPassed; @property (nonatomic, assign) BOOL transformTranslatePassed; @property (nonatomic, assign) BOOL funcWithRectPointerPassed; @property (nonatomic, assign) BOOL funcWithTransformPointerPassed; @property (nonatomic, assign) BOOL consoleLogPassed; @property (nonatomic, assign) BOOL overrideParentMethodPassed; @property (nonatomic, assign) BOOL variableParameterMethodPassed; - (NSString*)funcOverrideParentMethod; - (void)funcToSwizzleTestGCD:(void(^)())block; - (NSDictionary *)funcToSwizzleReturnDictionary:(NSDictionary *)dict; - (NSDictionary *)funcToSwizzleReturnJSDictionary; - (NSArray *)funcToSwizzleReturnArray:(NSArray *)arr; - (NSString *)funcToSwizzleReturnString:(NSString *)str; @end @interface JPTestSubObject : JPTestObject @property (nonatomic, assign) BOOL funcCallSuperSubObjectPassed; @end @protocol JPTestProtocol - (double)protocolWithDouble:(double)num dict:(NSDictionary *)dictionary; + (NSString *)classProtocolWithString:(NSString *)string int:(NSInteger)num; @end @protocol JPTestProtocol2 @optional - (NSInteger)protocolWithInt:(NSInteger)num; @end @interface JPTestProtocolObject : NSObject - (BOOL)testProtocolMethods; @end @interface JPTestSwizzledForwardInvocationSuperObject : NSObject @property (nonatomic, assign) BOOL callSwizzledSuperForwardInvocationPassed; - (void)swizzleSuperForwoardInvocation; @end @interface JPTestSwizzledForwardInvocationSubObject : JPTestSwizzledForwardInvocationSuperObject - (void)callTestSwizzledSuperForwardInvocation; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JPTestObject.m ================================================ // // JPTestObject.m // InstaScript // // Created by bang on 15/4/30. // Copyright (c) 2015 bang. All rights reserved. // #import "JPTestObject.h" #import @implementation JPTestObject - (void)funcReturnVoid { self.funcReturnVoidPassed = YES; } - (NSString *)funcReturnString { return @"stringFromOC"; } + (NSString *)classFunCallReturnString { return @"classFunCallReturnString"; } - (Class)funcReturnClass { return [self class]; } - (Class)funcToSwizzleReturnClass { return nil; } - (double)funcReturnDouble { return 100.0; } - (CGRect)funcWithRectAndReturnRect:(CGRect)rect { return rect; } - (CGPoint)funcWithPointAndReturnPoint:(CGPoint)point { return point; } - (CGSize)funcWithSizeAndReturnSize:(CGSize)size { return size; } - (NSRange)funcWithRangeAndReturnRange:(NSRange)range { return range; } - (UIView *)funcReturnViewWithFrame:(CGRect)frame { UIView *view = [[UIView alloc] initWithFrame:frame]; return view; } - (UIView *)funcWithViewAndReturnView:(UIView *)view { return view; } - (NSString *)funcWithClassAndReturnString:(Class)cls { return NSStringFromClass(cls); } - (void)funcWithInt:(int)intValue { self.funcWithIntPassed = intValue == 42; } - (void)funcWithNil:(NSObject *)nilObj { self.funcWithNilPassed = nilObj == nil; } - (id)funcReturnNil { return nil; } - (BOOL)funcTestBool:(BOOL)b { return b; } - (NSNumber *)funcTestNSNumber:(NSNumber *)num { return num; } - (void)funcWithNil:(NSObject *)nilObj dict:(NSDictionary *)dict str:(NSString *)str num:(double)num { self.funcWithNilAndOthersPassed = nilObj == nil && [dict[@"k"] isEqualToString:@"JSPatch"] && [str isEqualToString:@"JSPatch"] && num - 4.2 < 0.001; } - (void)funcWithNull:(NSNull *)nullObj { self.funcWithNullPassed = [nullObj isKindOfClass:[NSNull class]]; } #pragma mark - NSDictionary / NSArray - (void)funcWithDict:(NSDictionary *)dict andDouble:(double)doubleValue { BOOL dictPass = [dict[@"test"] isEqualToString:@"test"]; BOOL doublePass = doubleValue - 4.2 < 0.001; self.funcWithDictAndDoublePassed = dictPass && doublePass; } - (NSDictionary *)funcReturnDict:(NSDictionary *)dict { return dict; } - (NSDictionary *)funcReturnDictStringInt { return @{@"str": @"stringFromOC", @"num": @(42)}; } - (NSDictionary *)funcReturnDictStringView { UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; return @{@"view": view, @"str": @"stringFromOC"}; } - (NSArray *)funcReturnArrayControllerViewString { UIViewController *controller = [[UIViewController alloc] init]; UIView *view = [[UIView alloc] init]; return @[controller, view, @"stringFromOC"]; } - (NSString *)getString { return @"JSPatch"; } - (NSArray *)getArray { return @[@"JSPatch", @(1)]; } - (NSDictionary *)getDictionary { return @{@"k": @"JSPatch"}; } - (void)funcTestBoxingObj:(NSArray *)data { NSString *str = data[0]; NSDictionary *dict = data[1]; NSArray *arr = data[2]; self.testBoxingObjPassed = [str isEqualToString:[self getString]] && [dict[@"k"] isEqualToString:[[self getDictionary] objectForKey:@"k"]] && [arr[0] isEqualToString:[[self getArray] objectAtIndex:0]]; } #pragma mark - block typedef void (^ISTestBlock)(NSString *str, int num); - (ISTestBlock)funcReturnBlock { ISTestBlock block = ^(NSString *str, int num) { self.funcReturnBlockPassed = [str isEqualToString:@"stringFromJS"] && num == 42; }; return block; } typedef id (^JPTestObjectBlock)(NSDictionary *dict, UIView *view); - (JPTestObjectBlock)funcReturnObjectBlock { JPTestObjectBlock block = ^(NSDictionary *dict, UIView *view) { self.funcReturnObjectBlockPassed = [dict[@"str"] isEqualToString:@"stringFromJS"] && [dict[@"view"] isKindOfClass:[UIView class]] && view.frame.size.width == 100; return @"succ"; }; return block; } - (ISTestBlock)funcReturnJSBlock:(ISTestBlock)jsblock { return jsblock; } - (void)callBlockWithStringAndInt:(id(^)(NSString *str, int num))block { id ret = block(@"stringFromOC", 42); self.callBlockWithStringAndIntReturnValuePassed = [ret isEqualToString:@"succ"]; } - (void)callBlockDelay:(id(^)(NSString *str, int num))block { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ id ret = block(@"stringFromOC", 42); self.callBlockWithStringAndIntReturnValuePassed = [ret isEqualToString:@"succ"]; }); } - (void)callBlockWithArrayAndView:(void(^)(NSArray *arr, UIView *view))block { UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; block(@[@"stringFromOC", view], view); } - (void)callBlockWithBoolAndBlock:(void(^)(BOOL b, ISTestBlock block))block { ISTestBlock cbBlock = ^(NSString *str, int num) { self.callBlockWithBoolAndBlockPassed = [str isEqualToString:@"stringFromJS"] && num == 42; }; block(YES, cbBlock); } - (void)callBlockWithObjectAndBlock:(void(^)(UIView *view, JPTestObjectBlock block))block { UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; JPTestObjectBlock cbBlock = ^id(NSDictionary *dict, UIView *view) { self.callBlockWithObjectAndBlockPassed = [dict[@"str"] isEqualToString:@"stringFromJS"] && [dict[@"view"] isKindOfClass:[UIView class]] && view.frame.size.width == 100; return @"succ"; }; block(view, cbBlock); } - (void)callBlockWithDouble:(double(^)(double num))block { double ret = block(4.2); self.callBlockWithDoubleAndReturnDoublePassed = fabs(ret - 8.4) < 0.1; } #pragma mark - swizzle typedef struct { char *name; int idx; }JPTestStruct; - (void)callSwizzleMethod { [self funcToSwizzleWithString:@"stringFromOC" view:[[UIView alloc] init] int:42]; [self funcToSwizzle:4.2 view:[[UIView alloc] init]]; UIView *view = [self funcToSwizzleReturnView:[[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]]; self.funcToSwizzleReturnViewPassed = view.frame.size.width == 100; UIView *nilView = [self funcToSwizzleReturnView:nil]; self.funcToSwizzleParamNilPassed = !nilView; int num = [self funcToSwizzleReturnInt:42]; self.funcToSwizzleReturnIntPassed = num == 42; [JPTestObject classFuncToSwizzle:self int:10]; id ret = [JPTestObject classFuncToSwizzleReturnObj:self]; if ([ret isKindOfClass:[JPTestObject class]]) { self.classFuncToSwizzleReturnObjPassed = YES; } int retI = [JPTestObject classFuncToSwizzleReturnInt:42]; if (retI == 42) { self.classFuncToSwizzleReturnIntPassed = YES; } double retD = [JPTestObject classFuncToSwizzleReturnDouble:100.0]; if (fabs(retD - 100.0) < FLT_EPSILON) { self.classFuncToSwizzleReturnDoublePassed = YES; } [self funcToSwizzleWithBlock:^(UIView *view, int num) { self.funcToSwizzleWithBlockPassed = view && num == 42; }]; [self funcToSwizzle_withUnderLine_:42]; CGRect rect = [self funcToSwizzleReturnRect:CGRectMake(0, 0, 100, 100)]; self.funcToSwizzleReturnRectPassed = rect.size.width == 100; CGPoint point = [self funcToSwizzleReturnPoint:CGPointMake(42, 42)]; self.funcToSwizzleReturnPointPassed = point.x == 42; CGSize size = [self funcToSwizzleReturnSize:CGSizeMake(42, 42)]; self.funcToSwizzleReturnSizePassed = size.width == 42; NSRange range = [self funcToSwizzleReturnRange:NSMakeRange(0, 42)]; self.funcToSwizzleReturnRangePassed = range.length == 42; UIEdgeInsets edgeInsets = [self funcToSwizzleReturnEdgeInsets:UIEdgeInsetsMake(42, 42, 0, 0)]; self.funcToSwizzleReturnEdgeInsetsPassed = edgeInsets.left == 42; SEL selector = [self funcToSwizzleTestSelector:@selector(funcToSwizzleTestSelector:)]; self.funcToSwizzleTestSelectorPassed = [NSStringFromSelector(selector) isEqualToString:@"funcToSwizzleTestSelector:"]; char *cStr = [self funcToSwizzleTestChar:"JSPatch"]; self.funcToSwizzleTestCharPassed = strcmp("JSPatch", cStr) == 0; Class myClass = [self funcToSwizzleReturnClass]; self.funcToSwizzleReturnClassPassed = [NSStringFromClass(myClass) isEqualToString:@"UIView"]; JPTestStruct *testStruct = (JPTestStruct*)malloc(sizeof(JPTestStruct)); testStruct->idx = 42; testStruct->name = "JSPatch"; JPTestStruct *testStructReturn = [self funcToSwizzleTestPointer:testStruct]; self.funcToSwizzleTestPointerPassed = testStructReturn->idx == 42 && strcmp(testStructReturn->name, "JSPatch") == 0; } - (void)funcToSwizzleWithString:(NSString *)str view:(UIView *)view int:(NSInteger)i { self.funcToSwizzleWithStringViewIntPassed = NO; } - (void)funcToSwizzle:(double)num view:(UIView *)view { self.funcToSwizzleViewCalledOriginalPassed = 4.2 - num< 0.01 && view; } - (UIView *)funcToSwizzleReturnView:(UIView *)view { return nil; } - (int)funcToSwizzleReturnInt:(int)num { return 0; } - (NSDictionary *)funcToSwizzleReturnDictionary:(NSDictionary *)dict { return nil; } - (NSDictionary *)funcToSwizzleReturnJSDictionary { return nil; } - (NSArray *)funcToSwizzleReturnArray:(NSArray *)arr { return nil; } - (NSString *)funcToSwizzleReturnString:(NSString *)str { return nil; } - (void)funcToSwizzleWithBlock:(void(^)(UIView *view, int num))block { } - (void)funcToSwizzle_withUnderLine_:(int)num { } - (CGRect)funcToSwizzleReturnRect:(CGRect)rect { return CGRectZero; } - (CGPoint)funcToSwizzleReturnPoint:(CGPoint)point { return CGPointZero; } - (CGSize)funcToSwizzleReturnSize:(CGSize)size { return CGSizeZero; } - (NSRange)funcToSwizzleReturnRange:(NSRange)range { return NSMakeRange(0, 0); } - (UIEdgeInsets)funcToSwizzleReturnEdgeInsets:(UIEdgeInsets)edgeInsets { return UIEdgeInsetsZero; } - (void)funcToSwizzleTestGCD:(void(^)())block { } - (Class)funcToSwizzleTestClass:(Class)cls { return nil; } - (SEL)funcToSwizzleTestSelector:(SEL)selector { return nil; } - (char *)funcToSwizzleTestChar:(char *)cStr { return NULL; } - (char *)funcReturnChar { return "JSPatch"; } - (void)funcTestChar:(char *)cStr { self.funcTestCharPassed = strcmp("JSPatch", cStr) == 0; } - (void *)funcToSwizzleTestPointer:(void *)pointer { return NULL; } - (BOOL)funcTestNSErrorPointer:(NSError **)error { NSError *tmp = [[NSError alloc]initWithDomain:@"com.albert43" code:43 userInfo:@{@"msg":@"test error"}]; if (error) *error = tmp; return NO; } - (void *)funcReturnPointer { JPTestStruct *testStruct = (JPTestStruct*)malloc(sizeof(JPTestStruct)); testStruct->idx = 42; testStruct->name = "JSPatch"; return testStruct; } - (void)funcTestPointer:(void *)pointer { JPTestStruct *testStruct = pointer; self.funcTestPointerPassed = testStruct->idx == 42 && strcmp(testStruct->name, "JSPatch") == 0; } - (BOOL)funcTestGetPointer1:(NSString *)str { if ([str isEqualToString:@"JSPatch"]) { return YES; } return NO; } - (BOOL)funcTestGetPointer2:(NSError *)error { if ([[[error userInfo] description] isEqualToString:[@{@"msg":@"test"} description]]) { return YES; } return NO; } - (BOOL)funcTestGetPointer3:(void *)arr { char *p = arr; for (int i = 0; i < 10; i++) { if (p[i] != 'A') { return false; } } return true; } typedef NSString * (^JSBlock)(NSError *); - (JSBlock)funcGenerateBlock { JSBlock block = ^(NSError *err) { if (err) { return [err description]; }else { return @"no error"; } }; return block; } - (NSString *)excuteBlockWithNilParameters:(JSBlock)blk { if (blk) { return blk(nil); } return nil; } + (void)classFuncToSwizzle:(JPTestObject *)testObject int:(NSInteger)i { } + (id)classFuncToSwizzleReturnObj:(JPTestObject *)obj { obj.classFuncToSwizzleReturnObjCalledOriginalPassed = YES; return nil; } + (int)classFuncToSwizzleReturnInt:(int)i { return 0; } + (double)classFuncToSwizzleReturnDouble:(double)d { return 0; } #pragma mark - super - (void)funcCallSuper { self.funcCallSuperPassed = YES; } #pragma mark - performance - (void)pFuncVoid { } - (int)pFuncReturnInt { return 42; } - (void)pFuncParamInt:(int)num { } - (id)pFuncReturnSelf { return self; } - (void)pFuncParamSelf:(id)obj { } #pragma mark - forward - (void)callTestForward { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" [self performSelector:@selector(testForward) withObject:nil]; #pragma clang diagnostic pop } - (void)funcToForward { self.callForwardInvocationPassed = YES; } - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([NSStringFromSelector(anInvocation.selector) isEqualToString:@"testForward"]) { [self funcToForward]; } } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { if ([NSStringFromSelector(aSelector) isEqualToString:@"funcToSwizzleRect:"]) { NSLog(@"ss"); } if ([NSStringFromSelector(aSelector) isEqualToString:@"testForward"]) { return [self methodSignatureForSelector:@selector(funcToForward)]; } return [super methodSignatureForSelector:aSelector]; } #pragma mark - - (NSString*)funcOverrideParentMethod { return @"orgi"; } #pragma mark CGAffineTransform - (CGAffineTransform)funcWithTransform:(CGAffineTransform)transform { return transform; } #pragma mark structPointer - (void)funcWithRectPointer:(CGRect *)rect { self.funcWithRectPointerPassed = rect->size.width == 100; rect->origin.x = 42; } - (void)funcWithTransformPointer:(CGAffineTransform *)transform { self.funcWithTransformPointerPassed = transform->a == 100; transform->tx = 42; } @end @implementation JPTestSubObject - (instancetype)init { self = [super init]; if (self) { self.funcCallSuperSubObjectPassed = YES; } return self; } - (void)funcCallSuper { self.funcCallSuperSubObjectPassed = NO; } @end #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wprotocol" @implementation JPTestProtocolObject - (BOOL)testProtocolMethods { double dNum = [self protocolWithDouble:4.2 dict:@{@"name": @"JSPatch"}]; NSInteger iNum = [self protocolWithInt:42]; NSString *str = [JPTestProtocolObject classProtocolWithString:@"JSPatch" int:42]; return dNum - 4.2 < 0.001 && iNum == 42 && [str isEqualToString:@"JSPatch"]; } #pragma clang diagnostic pop @end @implementation JPTestSwizzledForwardInvocationSuperObject - (void)swizzleSuperForwoardInvocation { class_replaceMethod([JPTestSwizzledForwardInvocationSuperObject class], @selector(forwardInvocation:), (IMP)SwizzledSuperForwardInvocation, "v@:@"); } static void SwizzledSuperForwardInvocation(__unsafe_unretained id assignSlf, SEL selector, NSInvocation *invocation) { if ([NSStringFromSelector(invocation.selector) isEqualToString:@"testSwizzledSuperForwardInvocation"]) { ((JPTestSwizzledForwardInvocationSuperObject *)assignSlf).callSwizzledSuperForwardInvocationPassed = YES; } } - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([NSStringFromSelector(anInvocation.selector) isEqualToString:@"testSwizzledSuperForwardInvocation"]) { self.callSwizzledSuperForwardInvocationPassed = NO; } } @end @implementation JPTestSwizzledForwardInvocationSubObject - (void)callTestSwizzledSuperForwardInvocation { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" [self performSelector:@selector(testSwizzledSuperForwardInvocation) withObject:nil]; #pragma clang diagnostic pop } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { if ([NSStringFromSelector(aSelector) isEqualToString:@"testSwizzledSuperForwardInvocation"]) { return [self methodSignatureForSelector:@selector(callTestSwizzledSuperForwardInvocation)]; } return [super methodSignatureForSelector:aSelector]; } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/JSPatchTests.m ================================================ // // InstaScriptTests.m // InstaScriptTests // // Created by bang on 15/4/30. // Copyright (c) 2015 bang. All rights reserved. // #import #import #import "JPEngine.h" #import "JPTestObject.h" #import "JPInheritanceTestObjects.h" #import "JPMultithreadTestObject.h" #import "newProtocolTest.h" #import "JPSuperTestObject.h" #import "JPJSClassTest.h" #import "JPMemory.h" #import "JPPerformanceTest.h" #import "JPCFunctionTest.h" #import "JPNumberTest.h" #import "newBlockTest.h" @interface JSPatchTests : XCTestCase @end @implementation JSPatchTests - (void)loadPatch:(NSString *)patchName { NSString *jsPath = [[NSBundle bundleForClass:[self class]] pathForResource:patchName ofType:@"js"]; [JPEngine evaluateScriptWithPath:jsPath]; } - (void)setUp { [super setUp]; [JPEngine startEngine]; [JPEngine addExtensions:@[@"JPMemory", @"JPStructPointer", @"JPCoreGraphics", @"JPUIKit"]]; } - (void)tearDown { [super tearDown]; } - (void)testEngine { [self loadPatch:@"test"]; JSValue *objValue = [JPEngine context][@"ocObj"]; JPTestObject *obj = [objValue toObjectOfClass:[JPTestObject class]]; JSValue *subObjValue = [JPEngine context][@"subObj"]; JPTestSubObject *subObj = [subObjValue toObjectOfClass:[JPTestSubObject class]]; XCTAssert(obj.funcReturnVoidPassed, @"funcReturnVoidPassed"); XCTAssert(obj.funcReturnStringPassed, @"funcReturnStringPassed"); XCTAssert(obj.funcReturnClassPassed, @"funcReturnClassPassed"); // Test for functions which return double/float, cause there's a fatal bug in NSInvocation on iOS7.0 // This case shall fail if you comment line 957~959 in JPEngine.m on iOS7.0. XCTAssert(obj.funcReturnDoublePassed, @"funcReturnDoublePassed"); XCTAssert(obj.funcWithIntPassed, @"funcWithIntPassed"); XCTAssert(obj.funcWithNilPassed, @"funcWithNilPassed"); XCTAssert(obj.funcReturnNilPassed, @"funcReturnNilPassed"); XCTAssert(obj.funcWithNilAndOthersPassed, @"funcWithNilAndOthersPassed"); XCTAssert(obj.funcWithNullPassed, @"funcWithNullPassed"); XCTAssert(obj.funcTestBoolPassed, @"funcTestBoolPassed"); XCTAssert(obj.funcTestNSNumberPassed, @"funcTestNSNumberPassed"); XCTAssert(obj.funcWithDictAndDoublePassed, @"funcWithDictAndDoublePassed"); XCTAssert(obj.funcWithRectAndReturnRectPassed, @"funcWithRectAndReturnRectPassed"); XCTAssert(obj.funcWithSizeAndReturnSizePassed, @"funcWithSizeAndReturnSizePassed"); XCTAssert(obj.funcWithPointAndReturnPointPassed, @"funcWithPointAndReturnPointPassed"); XCTAssert(obj.funcWithRangeAndReturnRangePassed, @"funcWithRangeAndReturnRangePassed"); XCTAssert(obj.funcWithClassAndReturnStringPassed, @"funcWithClassAndReturnInstancePassed"); XCTAssert(obj.funcReturnViewWithFramePassed, @"funcReturnViewWithFramePassed"); XCTAssert(obj.funcWithViewAndReturnViewPassed, @"funcWithViewAndReturnViewPassed"); XCTAssert(obj.funcReturnDictStringViewPassed, @"funcReturnDictStringViewPassed"); XCTAssert(obj.funcReturnDictStringIntPassed, @"funcReturnDictStringIntPassed"); XCTAssert(obj.funcReturnArrayControllerViewStringPassed, @"funcReturnArrayControllerViewStringPassed"); XCTAssert(obj.funcReturnDictPassed, @"funcReturnDictPassed"); XCTAssert(obj.funcReturnDictPassed, @"testBoxingObjPassed"); XCTAssert(obj.funcReturnBlockPassed, @"funcReturnBlockPassed"); XCTAssert(obj.funcReturnObjectBlockPassed, @"funcReturnObjectBlockPassed"); XCTAssert(obj.funcReturnObjectBlockReturnValuePassed, @"funcReturnObjectBlockReturnValuePassed"); XCTAssert(obj.funcReturnJSBlockPassed, @"funcReturnBlockPassed"); XCTAssert(obj.callBlockWithStringAndIntPassed, @"callBlockWithStringAndIntPassed"); XCTAssert(obj.callBlockWithStringAndIntReturnValuePassed, @"callBlockWithStringAndIntReturnValuePassed"); XCTAssert(obj.callBlockWithArrayAndViewPassed, @"callBlockWithArrayAndViewPassed"); XCTAssert(obj.callBlockWithBoolAndBlockPassed, @"callBlockWithBoolAndBlockPassed"); XCTAssert(obj.callBlockWithObjectAndBlockPassed, @"callBlockWithObjectAndBlockPassed"); XCTAssert(obj.callBlockWithObjectAndBlockReturnValuePassed, @"callBlockWithObjectAndBlockReturnValuePassed"); XCTAssert(obj.callBlockWithDoubleAndReturnDoublePassed, @"callBlockWithDoubleAndReturnDoublePassed"); XCTAssert(obj.funcToSwizzleWithStringViewIntPassed, @"funcToSwizzleWithStringViewIntPassed"); XCTAssert(obj.funcToSwizzleViewPassed, @"funcToSwizzleViewPassed"); XCTAssert(obj.funcToSwizzleViewCalledOriginalPassed, @"funcToSwizzleViewCalledOriginalPassed"); XCTAssert(obj.funcToSwizzleReturnViewPassed, @"funcToSwizzleReturnViewPassed"); XCTAssert(obj.funcToSwizzleParamNilPassed, @"funcToSwizzleParamNilPassed"); XCTAssert(obj.funcToSwizzleReturnIntPassed, @"funcToSwizzleReturnIntPassed"); XCTAssert(obj.funcToSwizzleWithBlockPassed, @"funcToSwizzleWithBlockPassed"); XCTAssert(obj.funcToSwizzle_withUnderLine_Passed, @"funcToSwizzle_withUnderLine_Passed"); XCTAssert(obj.funcToSwizzleReturnRectPassed, @"funcToSwizzleReturnRectPassed"); XCTAssert(obj.funcToSwizzleReturnPointPassed, @"funcToSwizzleReturnPointPassed"); XCTAssert(obj.funcToSwizzleReturnSizePassed, @"funcToSwizzleReturnSizePassed"); XCTAssert(obj.funcToSwizzleReturnRangePassed, @"funcToSwizzleReturnRangePassed"); XCTAssert(obj.funcToSwizzleReturnEdgeInsetsPassed, @"funcToSwizzleReturnEdgeInsetsPassed"); XCTAssert(obj.funcToSwizzleReturnRectJSPassed, @"funcToSwizzleReturnRectJSPassed"); XCTAssert(obj.funcToSwizzleReturnPointJSPassed, @"funcToSwizzleReturnPointJSPassed"); XCTAssert(obj.funcToSwizzleReturnSizeJSPassed, @"funcToSwizzleReturnSizeJSPassed"); XCTAssert(obj.funcToSwizzleReturnRangeJSPassed, @"funcToSwizzleReturnRangeJSPassed"); XCTAssert(obj.funcToSwizzleReturnEdgeInsetsJSPassed, @"funcToSwizzleReturnEdgeInsetsJSPassed"); XCTAssert(obj.funcToSwizzleTestClassPassed, @"funcToSwizzleTestClassPassed"); XCTAssert(obj.funcToSwizzleTestSelectorPassed, @"funcToSwizzleTestSelectorPassed"); XCTAssert(obj.funcToSwizzleTestCharPassed, @"funcToSwizzleTestCharPassed"); XCTAssert(obj.funcToSwizzleTestClassPassed,@"funcToSwizzleTestClassPassed"); XCTAssert(obj.funcTestCharPassed, @"funcTestCharPassed"); XCTAssert(obj.funcToSwizzleTestPointerPassed, @"funcToSwizzleTestPointerPassed"); XCTAssert(obj.funcTestPointerPassed, @"funcTestPointerPassed"); XCTAssert(obj.funcTestSizeofPassed,@"funcSizeofPassed"); XCTAssert(obj.funcTestGetPointerPassed, @"funcGetPointerPassed"); XCTAssert(obj.funcTestNSErrorPointerPassed, @"funcTestNSErrorPointerPassed"); XCTAssert(obj.funcTestNilParametersInBlockPassed, @"funcTestNilParametersInBlockPassed"); NSDictionary *originalDict = @{@"k": @"v"}; NSDictionary *dict = [obj funcToSwizzleReturnDictionary:originalDict]; XCTAssert(originalDict == dict, @"funcToSwizzleReturnDictionary"); dict = [obj funcToSwizzleReturnJSDictionary]; XCTAssertEqualObjects(dict[@"str"], @"js_string", @"funcToSwizzleReturnJSDictionary"); NSArray *originalArr = @[@"js", @"patch"]; NSArray *arr = [obj funcToSwizzleReturnArray:originalArr]; XCTAssert(originalArr == arr, @"funcToSwizzleReturnArray"); NSString *originalStr = @"JSPatch"; NSString *str = [obj funcToSwizzleReturnString:originalStr]; XCTAssert(originalStr == str, @"funcToSwizzleReturnString"); XCTAssert(obj.classFuncToSwizzlePassed, @"classFuncToSwizzlePassed"); XCTAssert(obj.classFuncToSwizzleReturnObjPassed, @"classFuncToSwizzleReturnObjPassed"); XCTAssert(obj.classFuncToSwizzleReturnObjCalledOriginalPassed, @"classFuncToSwizzleReturnObjCalledOriginalPassed"); XCTAssert(obj.classFuncToSwizzleReturnIntPassed, @"classFuncToSwizzleReturnIntPassed"); // Test for functions which return double/float, cause there's a fatal bug in NSInvocation on iOS7.0 // This case shall fail if you comment line 1050~1052 in JPEngine.m on iOS7.0. XCTAssert(obj.classFuncToSwizzleReturnDoublePassed, @"classFuncToSwizzleReturnDoublePassed"); XCTAssert(subObj.funcCallSuperSubObjectPassed, @"funcCallSuperSubObjectPassed"); XCTAssert(subObj.funcCallSuperPassed, @"funcCallSuperPassed"); XCTAssert(obj.callForwardInvocationPassed, @"callForwardInvocationPassed"); JPTestSwizzledForwardInvocationSubObject *tmp = [[JPTestSwizzledForwardInvocationSubObject alloc] init]; [tmp callTestSwizzledSuperForwardInvocation]; XCTAssert(!tmp.callSwizzledSuperForwardInvocationPassed); [tmp swizzleSuperForwoardInvocation]; [tmp callTestSwizzledSuperForwardInvocation]; XCTAssert(tmp.callSwizzledSuperForwardInvocationPassed); XCTAssert(obj.propertySetFramePassed, @"propertySetFramePassed"); XCTAssert(obj.propertySetViewPassed, @"propertySetViewPassed"); XCTAssert(obj.newTestObjectReturnViewPassed, @"newTestObjectReturnViewPassed"); XCTAssert(obj.newTestObjectReturnBoolPassed, @"newTestObjectReturnBoolPassed"); XCTAssert(obj.mutableArrayPassed, @"mutableArrayPassed"); XCTAssert(obj.mutableDictionaryPassed, @"mutableDictionaryPassed"); XCTAssert(obj.mutableStringPassed, @"mutableStringPassed"); XCTAssert(obj.funcWithTransformPassed, @"funcWithTransformPassed"); XCTAssert(obj.transformTranslatePassed, @"funcWithTransformPassed"); XCTAssert(obj.funcWithRectPointerPassed, @"funcWithRectPointerPassed"); XCTAssert(obj.funcWithTransformPointerPassed, @"funcWithTransformPointerPassed"); XCTAssertEqualObjects(@"overrided",[subObj funcOverrideParentMethod]); XCTAssert(obj.variableParameterMethodPassed, @"variableParameterMethodPassed"); JPTestProtocolObject *testProtocolObj = [[JPTestProtocolObject alloc] init]; XCTAssert([testProtocolObj testProtocolMethods], @"testProtocolMethodsPassed"); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [obj funcToSwizzleTestGCD:^{ XCTAssert(obj.funcToSwizzleTestGCDPassed, @"funcToSwizzleTestGCDPassed"); dispatch_semaphore_signal(semaphore); }]; while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; } - (void)testJSClass { [self loadPatch:@"jsClassTest"]; XCTAssert([JPJSClassTest isPassA]); XCTAssert([JPJSClassTest isPassB]); XCTAssert([JPJSClassTest isPassC]); } - (void)testSuperClass { [self loadPatch:@"superTest"]; XCTAssert([JPSuperTestResult isPassA]); XCTAssert([JPSuperTestResult isPassB]); XCTAssert([JPSuperTestResult isPassC]); } - (void)testInheritance { /*get values before patch*/ id t1objB = [[JPInheritTest01ObjectB alloc] init]; NSString* t1m1Return = [t1objB m1]; NSString* t1m2Return = [t1objB m2]; id t2objA = [[JPInheritTest02ObjectA alloc] init]; id t2objB = [[JPInheritTest02ObjectB alloc] init]; id t2objC = [[JPInheritTest02ObjectC alloc] init]; NSString* t2m1Return = [t2objA m1]; NSString* t2m2Return = [t2objA m2]; NSString* t2Bm1Return = [t2objB m1]; NSString* t2Bm2Return = [t2objB m2]; NSString* t2Cm1Return = [t2objC m1]; NSString* t2Cm2Return = [t2objC m2]; id t3objA = [[JPInheritTest03ObjectA alloc] init]; id t3objB = [[JPInheritTest03ObjectB alloc] init]; id t3objC = [[JPInheritTest03ObjectC alloc] init]; NSString* t3m1Return = [t3objA m1]; NSString* t3m2Return = [t3objA m2]; NSString* t3Bm1Return = [t3objB m1]; NSString* t3Bm2Return = [t3objB m2]; NSString* t3Cm1Return = [t3objC m1]; NSString* t3Cm2Return = [t3objC m2]; [self loadPatch:@"inheritTest"]; /*Test 1*/ XCTAssertNotEqualObjects(t1m1Return, [t1objB m1]); XCTAssertEqualObjects(@"JP_01ObjB_m1", [t1objB m1]); XCTAssertEqualObjects(t1m2Return,[t1objB m2]); /*Test 2*/ XCTAssertEqualObjects(t2m1Return,[t2objA m1]); XCTAssertEqualObjects(t2m2Return,[t2objA m2]); XCTAssertNotEqualObjects(t2Bm1Return,[t2objB m1]); XCTAssertEqualObjects(@"JP_02ObjB_m1",[t2objB m1]); XCTAssertEqualObjects(t2Bm2Return,[t2objB m2]); XCTAssertNotEqualObjects(t2Cm1Return,[t2objC m1]); XCTAssertEqualObjects(@"JP_02ObjB_m1",[t2objC m1]); XCTAssertNotEqualObjects(t2Cm2Return,[t2objC m2]); XCTAssertEqualObjects(@"JP_02ObjC_m2",[t2objC m2]); XCTAssertEqualObjects(@"JP_02ObjC_m3", [t2objC m3]); /*Test 3*/ XCTAssertEqualObjects(t3m1Return,[t3objA m1]); XCTAssertEqualObjects(t3m2Return,[t3objA m2]); XCTAssertNotEqualObjects(t3Bm1Return,[t3objB m1]); XCTAssertEqualObjects(@"JP_03ObjB_m1",[t3objB m1]); XCTAssertEqualObjects(t3Bm2Return,[t3objB m2]); XCTAssertEqualObjects(t3Cm1Return,[t3objC m1]); XCTAssertNotEqualObjects(t3Cm2Return,[t3objC m2]); XCTAssertEqualObjects(@"JP_03ObjC_m2",[t3objC m2]); } - (void)testCFunction { [self loadPatch:@"jsCFunctionTest"]; XCTAssert([JPCFunctionTest testCfuncWithCGSize], @"testCfuncWithCGSize"); XCTAssert([JPCFunctionTest testCfuncWithCGRect], @"testCfuncWithCGRect"); XCTAssert([JPCFunctionTest testCfuncWithId], @"testCfuncWithId"); XCTAssert([JPCFunctionTest testCfuncWithInt], @"testCfuncWithInt"); XCTAssert([JPCFunctionTest testCfuncWithCGFloat], @"testCfuncWithCGFloat"); XCTAssert([JPCFunctionTest testCfuncReturnPointer], @"testCfuncReturnPointer"); XCTAssert([JPCFunctionTest testCFunctionReturnClass], @"testCFunctionReturnClass"); XCTAssert([JPCFunctionTest testCFunctionVoid], @"testCFunctionVoid"); } #pragma mark - jsNumberTest - (void)testJPNumber { [self loadPatch:@"jsNumberTest"]; XCTAssert([JPNumberTest testJPNumNSNumber], @"testJPNumNSNumber"); XCTAssert([JPNumberTest testJPNumNSDecimalNumber], @"testJPNumNSDecimalNumber"); XCTAssert([JPNumberTest testJPNumToJS], @"testJPNumToJS"); XCTAssert([JPNumberTest testJPNUmToOC], @"testJPNumToOC"); } #pragma mark - multithreadTest dispatch_semaphore_t sem; int finishcount = 0; bool success = false; #define LOOPCOUNT 100 void thread(void* context); - (void)testDispatchQueue { [self loadPatch:@"multithreadTest"]; success = false; NSMutableArray *objs = [[NSMutableArray alloc] init]; for (int i = 0; i < LOOPCOUNT; i++) { JPMultithreadTestObject *obj = [[JPMultithreadTestObject alloc] init]; obj.objectId = i; [objs addObject:obj]; } dispatch_queue_t q1 = dispatch_queue_create("serial queue", DISPATCH_QUEUE_SERIAL); for (int i = 0; i < LOOPCOUNT; i++) { dispatch_async_f(q1, (__bridge void*)[objs objectAtIndex:i], thread); } sem = dispatch_semaphore_create(0); dispatch_semaphore_wait(sem,DISPATCH_TIME_FOREVER); XCTAssertTrue(success,@"serial queue test failed"); success = false; dispatch_queue_t q2 = dispatch_queue_create("concurrent queue", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < LOOPCOUNT; i++) { dispatch_async_f(q2, (__bridge void*)[objs objectAtIndex:i], thread); } sem = dispatch_semaphore_create(0); dispatch_semaphore_wait(sem,DISPATCH_TIME_FOREVER); XCTAssertTrue(success,@"concurrent queue test failed"); } void thread(void* context) { JPMultithreadTestObject *obj = (__bridge JPMultithreadTestObject*)context; for (int i = 0; i < LOOPCOUNT; i++) { [obj addValue:[NSNumber numberWithInt:obj.objectId]]; } finishcount++; if (![obj checkAllValues]) { NSLog(@"found wrong data in object %d", obj.objectId); dispatch_semaphore_signal(sem); return; } if (finishcount == LOOPCOUNT) { finishcount = 0; success = true; dispatch_semaphore_signal(sem); } } #pragma mark - performance - (void)testJSCallEmptyMethodPerformance { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallOCEmptyMethod]; }]; } - (void)testJSCallMethodWithParamObjectPerformance { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallOCMethodWithParamObject]; }]; } - (void)testJSCallMethodReturnObjectPerformance { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallOCMethodReturnObject]; }]; } - (void)testOCCallJSEmptyMethodPerformance { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testOCCallEmptyMethod]; }]; } - (void)testOCCallJSMethodWithParamObjectPerformance { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testOCCallMethodWithParamObject]; }]; } - (void)testOCCallJSMethodReturnObjectPerformance { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testOCCallMethodReturnObject]; }]; } - (void)testJSCallJSEmptyMethod { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallJSEmptyMethod]; }]; } - (void)testJSCallJSMethodWithParam { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallJSMethodWithParam]; }]; } - (void)testJSCallJSMethodWithLargeDictionaryParam { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallJSMethodWithLargeDictionaryParam]; }]; } - (void)testJSCallJSMethodWithLargeDictionaryParamAutoConvert { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallJSMethodWithLargeDictionaryParamAutoConvert]; }]; } - (void)testJSCallMallocJPMemory { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallMallocJPMemory]; }]; } - (void)testJSCallMallocJPCFunction { [self loadPatch:@"performanceTest"]; JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; [self measureBlock:^{ [obj testJSCallMallocJPCFunction]; }]; } - (void)testNewBlock { [self loadPatch:@"newBlockTest"]; newBlockTest *obj = [[newBlockTest alloc] init]; [obj removeJPBlock]; [obj testJSBlockToOCCall]; XCTAssert(obj.success, @"testJSBlockToOCCall"); } - (void)testNewProtocol{ [self loadPatch:@"newProtocolTest"]; //Protocol baseTest baseTestProtocolObject *baseTest = [baseTestProtocolObject new]; int retBaseTest1 = [baseTest testProtocol:YES]; XCTAssertEqual(retBaseTest1, 1); [baseTest test2Protocol:2]; [baseTest test3Protocol:NO withB:0.2f withC:3.4f]; NSLog(@"new protocol base test end"); //Protocol structTest structTestProtocolObject *structTest = [structTestProtocolObject new]; int retStructTest1 = [structTest testProtocol:CGRectZero]; XCTAssertEqual(retStructTest1, 1); CGPoint retStructTest2 = [structTest test2Protocol:CGSizeZero]; XCTAssertTrue(CGPointEqualToPoint(retStructTest2, CGPointMake(100, 100))); CGSize retStructTest3 = [structTest test3Protocol:CGRectZero withB:3.1f withC:4]; XCTAssertTrue(CGSizeEqualToSize(retStructTest3, CGSizeMake(100, 100))); NSLog(@"new protocol struct test end"); //Protocol objectTest objectTestProtocolObject *objectTest = [objectTestProtocolObject new]; int retObjectTest1 = [objectTest testProtocol:@"teststring"]; XCTAssertEqual(retObjectTest1, 1); int retObjectTest2 = [objectTest test2Protocol:@"teststring"]; XCTAssertEqual(retObjectTest2, 1); CGSize retObjectTest3 = [objectTest test3Protocol:@[@1,@2] withB:@"teststring" withC:2]; XCTAssertTrue(CGSizeEqualToSize(retObjectTest3, CGSizeMake(100, 100))); NSLog(@"new protocol object test end"); //Protocol sepcialTest specialTestProtocolObject *specialTest = [specialTestProtocolObject new]; [specialTest testProtocol:@selector(viewDidLoad)]; [specialTest test2Protocol:^{ NSLog(@"11"); }]; [specialTest test3Protocol:0.5f withB:^{ NSLog(@"11"); } withC:@selector(viewDidLoad)]; NSLog(@"new protocol special test end"); //Protocol typeEncodeTest typeEncodeTestProtocolObject *encodeTest = [typeEncodeTestProtocolObject new]; [encodeTest testProtocol:@"teststring"]; NSString* retEncodeTest2 = [encodeTest test2Protocol:@[@1,@2] withB:@"testtest"]; XCTAssertTrue([retEncodeTest2 isEqualToString:@"string"]); NSLog(@"new protocol encode test end"); //Protocol classTest int retClassTest1 = [classTestProtocolObject testProtocol:@"teststring"]; XCTAssertEqual(retClassTest1, 1); int retClassTest2 = [classTestProtocolObject test2Protocol:@"teststring"]; XCTAssertEqual(retClassTest2, 1); CGSize retClassTest3 = [classTestProtocolObject test3Protocol:@[@1,@2] withB:@"teststring" withC:2]; XCTAssertTrue(CGSizeEqualToSize(retClassTest3, CGSizeMake(100, 100))); NSLog(@"new protocol object test end"); } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/jsCFunctionTest.js ================================================ require('JPEngine').addExtensions(['JPCFunction']) require('JPEngine').defineStruct({ "name": "CGSize", "types": "FF", "keys": ["width", "height"] }); require('JPEngine').defineStruct({ "name": "CGPoint", "types": "FF", "keys": ["x", "y"] }); require('JPEngine').defineStruct({ "name": "CGRect", "types": "{CGPoint}{CGSize}", "keys": ["origin", "size"] }); defineClass('JPCFunctionTest', {}, { testCfuncWithCGSize: function() { defineCFunction("cfuncWithCGSize", "{CGSize}, {CGSize}") var ret = cfuncWithCGSize({width:1, height:2}); return ret.width == 1 && ret.height == 2; }, testCfuncWithCGRect: function() { defineCFunction("cfuncWithCGRect", "{CGRect}, {CGRect}") var ret = cfuncWithCGRect({origin:{x:1,y:2},size:{width:3, height:4}}); console.log("testCfuncWithCGRect", JSON.stringify(ret), ret.origin, ret.origin.x); return ret.origin.x == 1 && ret.origin.y == 2 && ret.size.width == 3 && ret.size.height == 4; }, testCfuncWithId: function() { defineCFunction("cfuncWithId", "id, NSString *") var ret = cfuncWithId("JSPatch"); return ret.toJS() == "JSPatch"; }, testCfuncWithInt: function() { defineCFunction("cfuncWithInt", "int, int") return cfuncWithInt(42) == 42 }, testCfuncWithCGFloat: function() { defineCFunction("cfuncWithCGFloat", "CGFloat, CGFloat") return cfuncWithCGFloat(42.2) - 42.2 < 0.1 }, testCfuncReturnPointer: function() { defineCFunction("cfuncReturnPointer", "void*") defineCFunction("cfuncWithPointerIsEqual", "bool, void*") var ptr = cfuncReturnPointer() return cfuncWithPointerIsEqual(ptr) }, testCFunctionReturnClass: function() { defineCFunction("NSClassFromString", "Class, NSString *") var viewCls = NSClassFromString("UIView") var view = require('UIView').alloc().init() return view.isKindOfClass(viewCls); }, testCFunctionVoid: function() { defineCFunction("cfuncVoid", "void") self.setupCFunctionVoidSucc(); return self.ORIGtestCFunctionVoid(); }, }) ================================================ FILE: Demo/iOSDemo/JSPatchTests/jsClassTest.js ================================================ defineClass('JSClsA', ['prop1', 'prop2'], { init: function(){ self = self.super().init(); self.setProp1('1'); self.setProp2('2'); return self; }, _privateMethod: function() { return 'P'; }, method: function() { return 'A' + self.prop1() + self.prop2(); }, }, { clsMethod: function() { return 'A' }, }) defineClass('JSSuperTestA', { method: function(){ return 'A' } }) defineClass('JSSuperTestA1: JSSuperTestA', { method: function(){ return self.super().method() + '1' } }) defineClass('JSSuperTestA2: JSSuperTestA1', { method: function(){ return self.super().method() + '2' } }) defineJSClass('JSClassA', { init: function() { this.prop1 = 'A' return this }, method: function() { return this.prop1 } }, { clsMethod: function() { return '1' } }) defineJSClass('JSClassA1: JSClassA', { method: function() { return this.super().method() + '1'; //should be 'A1' } }) defineJSClass('JSClassA2: JSClassA1', { method: function() { return this.super().method() + '2'; //should be 'A12' } }) defineClass('JPJSClassTest', {}, { isPassA: function() { var o = JSClsA.alloc().init(); return o.method() == 'A12' && o._privateMethod() == 'P' && JSClsA.clsMethod() == 'A'; }, isPassB: function() { var o = JSSuperTestA2.alloc().init(); return o.method() == 'A12'; }, isPassC: function() { var o = JSClassA2.alloc().init(); return o.method() == 'A12' && JSClassA.clsMethod() == '1'; } }) ================================================ FILE: Demo/iOSDemo/JSPatchTests/jsNumberTest.js ================================================ require('JPEngine').addExtensions(['JPNumber']) defineClass('JPNumberTest', {}, { testJPNumNSNumber: function() { var oc_n = OCNumber("NSNumber", "numberWithInt:", [233]) return oc_n.compare(233) == 0 }, testJPNumNSDecimalNumber: function() { var oc_n = OCNumber("NSDecimalNumber", "decimalNumberWithMantissa:exponent:isNegative:", [10, 2, 0]) return oc_n.compare(1000) == 0 }, testJPNumToJS: function() { var oc_n = OCNumber("NSNumber", "numberWithFloat:", [0.14]) var js_n = toJSNumber(oc_n) return js_n + 3 - 3.14 < 0.0001 }, testJPNUmToOC: function() { var oc_n = toOCNumber(2.14) return oc_n.compare(2.14) == 0 } }) ================================================ FILE: Demo/iOSDemo/JSPatchTests/multithreadTest.js ================================================ var global = this; (function() { defineClass('JPMultithreadTestObject', { addValueJS: function(num) { self.addValue(num); }, addValue: function(num) { self.ORIGaddValue(num); } }); })(); ================================================ FILE: Demo/iOSDemo/JSPatchTests/newBlockTest.h ================================================ // // newBlockTest.h // JSPatchTests // // Created by WELCommand on 2018/3/27. // Copyright © 2018年 bang. All rights reserved. // #import #import @interface newBlockTest : NSObject @property (nonatomic, assign) BOOL success; - (void)removeJPBlock; - (void)testJSBlockToOCCall; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/newBlockTest.js ================================================ defineClass("newBlockTest", { testJSBlockToOCCall: function() { self.performBlock(block("CGFloat, int, CGPoint, double, CGFloat, NSNumber*, NSString*, NSInteger", function(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg1 + arg2.x + arg2.y + arg3 + arg4 + arg5 + arg6.doubleValue() + arg7; })); } }, {}); ================================================ FILE: Demo/iOSDemo/JSPatchTests/newBlockTest.m ================================================ // // newBlockTest.m // JSPatchTests // // Created by WELCommand on 2018/3/27. // Copyright © 2018年 bang. All rights reserved. // #import "newBlockTest.h" #import #import "JPEngine.h" @implementation newBlockTest - (void)testJSBlockToOCCall {} + (void)main:(JSContext *)context { context[@"__genBlock"] = nil; } - (void)removeJPBlock { [JPEngine addExtensions:@[@"newBlockTest"]]; } - (void)performBlock:(CGFloat (^)(int arg1, CGPoint arg2, double arg3, CGFloat arg4, NSNumber *arg5, NSString *arg6, NSInteger arg7))block { _success = (block(1, (CGPoint){3.3, 3.3}, 1.1, 1.1, @(11), @"4.4", 17) == (CGFloat)(1 + 3.3 + 3.3 + 1.1 + 1.1 + 11 + 4.4 + 17)) && (block(1, (CGPoint){3.3, 3.3}, 1.1, 1.1, @(11), @"4.4", 17) == (CGFloat)(1 + 3.3 + 3.3 + 1.1 + 1.1 + 11 + 4.4 + 17)); } @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/newProtocolTest.h ================================================ // // newProrotcolTest.h // JSPatchDemo // // Created by Awhisper on 15/12/27. // Copyright © 2015年 bang. All rights reserved. // #import #import @interface baseTestProtocolObject : NSObject -(int)testProtocol:(BOOL)arg; -(void)test2Protocol:(NSInteger)arg; -(void)test3Protocol:(BOOL)arg1 withB:(float)arg2 withC:(CGFloat)arg3; @end @interface structTestProtocolObject : NSObject -(int)testProtocol:(CGRect)arg; -(CGPoint)test2Protocol:(CGSize)arg; -(CGSize)test3Protocol:(CGRect)arg1 withB:(float)arg2 withC:(NSInteger)arg3; @end @interface objectTestProtocolObject : NSObject -(int)testProtocol:(NSString*)arg; -(int)test2Protocol:(NSString*)arg; -(CGSize)test3Protocol:(NSArray*)arg1 withB:(NSString*)arg2 withC:(NSInteger)arg3; @end //typedef void(^name)(void); @interface specialTestProtocolObject : NSObject -(void)testProtocol:(SEL)arg; -(void)test2Protocol:(void(^)(void))arg; -(void)test3Protocol:(float)arg1 withB:(void(^)(void))arg2 withC:(SEL)arg3; @end @interface typeEncodeTestProtocolObject : NSObject -(void)testProtocol:(id)arg; -(NSString*)test2Protocol:(NSArray*)arg1 withB:(NSString*)arg2; @end @interface classTestProtocolObject : NSObject +(int)testProtocol:(NSString*)arg; +(int)test2Protocol:(NSString*)arg; +(CGSize)test3Protocol:(NSArray*)arg1 withB:(NSString*)arg2 withC:(NSInteger)arg3; @end ================================================ FILE: Demo/iOSDemo/JSPatchTests/newProtocolTest.js ================================================ defineProtocol("baseTestProtocol",{ //argument type can be bool BOOL int NSInterger float CGFloat ... any base type //one argument BOOL return int testProtocol:{ paramsType:"BOOL", returnType:"int", }, //one argument NSInterger return void test2Protocol:{ paramsType:"BOOL", //returnType:"void",//option no returnType mean void }, //multiArguments seperated by "," test3Protocol_withB_withC:{ paramsType:"BOOL , float , CGFloat", //returnType:"void",//option no returnType mean void }, }) //with new protocol you can add basetype args method defineClass('baseTestProtocolObject : NSObject ' , { testProtocol:function(arg1){ console.log(arg1); return 1; }, test2Protocol: function(arg1) { console.log(arg1); }, test3Protocol_withB_withC:function(arg1,arg2,arg3){ console.log(arg1); }, }) defineProtocol("structTestProtocol",{ //argument type can be CGRect CGSize CGPoint ... many systemstruct //only support system struct //custom struct see encodeTypeTest //one argument CGRect return int testProtocol:{ paramsType:"CGRect", returnType:"int", }, //one argument CGSize return CGPoint test2Protocol:{ paramsType:"CGSize", returnType:"CGPoint", }, //multiArguments seperated by "," struct & baseType mix test3Protocol_withB_withC:{ paramsType:"CGRect , float , NSInteger", returnType:"CGSize", }, }) //with new protocol you can add struct type args method defineClass('structTestProtocolObject : NSObject ' , { testProtocol:function(arg1){ console.log(arg1); return 1; }, test2Protocol: function(arg1) { console.log(arg1); var point = {x:100,y:100}; return point; }, test3Protocol_withB_withC:function(arg1,arg2,arg3){ console.log(arg1); var size = {width:100,height:100}; return size; }, }) defineProtocol("objectTestProtocol",{ //argument type can be any NSObject //one argument NSString , return int //you can turn NSString to id testProtocol:{ paramsType:"id", returnType:"int", }, //you can use NSString is All ok test2Protocol:{ paramsType:"NSString", returnType:"int", }, //multiArguments seperated by "," object & baseType mix test3Protocol_withB_withC:{ paramsType:"id , NSString , NSInteger", returnType:"CGSize", }, }) //with new protocol you can add mix type args method defineClass('objectTestProtocolObject : NSObject ' , { testProtocol:function(arg1){ console.log(arg1); return 1; }, test2Protocol: function(arg1) { console.log(arg1); return 1; }, test3Protocol_withB_withC:function(arg1,arg2,arg3){ console.log(arg1); var size = {width:100,height:100}; return size; }, }) defineProtocol("specialTestProtocol",{ //argument type can be selector and block //one argument Selctor must use "SEL" testProtocol:{ paramsType:"SEL", //returnType:"int",//option no returnType mean void }, //one argument bloc must use "block" test2Protocol:{ paramsType:"block", // returnType:"CGPoint",//option no returnType mean void }, //multiArguments seperated by "," struct & baseType mix test3Protocol_withB_withC:{ paramsType:"CGFloat , block , SEL", // returnType:"CGSize",//option no returnType mean void }, }) //with new protocol you can add mix type args method defineClass('specialTestProtocolObject : NSObject ' , { testProtocol:function(arg1){ console.log(arg1); }, test2Protocol: function(arg1) { console.log(arg1); arg1(); }, test3Protocol_withB_withC:function(arg1,arg2,arg3){ console.log(arg1); arg2(); }, }) defineProtocol("encodeTestProtocol",{ //use typeEncode to define complex method //you can write typeEncode by using runtime //you can input any string //makesure the number of args is right testProtocol:{ paramsType:"unknown", returnType:"something", typeEncode:"v12@0:4@8", }, //you can write typeEncode by yourself //you can input any string //makesure the number of args is right testProtocol_withB:{ paramsType:"idontknown , mygod", returnType:"wooo", typeEncode:"@@:@@", }, //if your paramsType or returnType is complex //youcan input any string just make sure number is right //write the whole typeEncode or use runtime to generate typeEncode }) //with new protocol you can add encodetype method defineClass('typeEncodeTestProtocolObject : NSObject ' , { testProtocol:function(arg1){ console.log(arg1); }, test2Protocol_withB: function(arg1,arg2) { console.log(arg1); var ret = "string"; return ret; }, }) defineProtocol("classTestProtocol",{},{ //argument type can be any NSObject //one argument NSString , return int //you can turn NSString to id testProtocol:{ paramsType:"id", returnType:"int", }, //you can use NSString is All ok test2Protocol:{ paramsType:"NSString", returnType:"int", }, //multiArguments seperated by "," object & baseType mix test3Protocol_withB_withC:{ paramsType:"id , NSString , NSInteger", returnType:"CGSize", }, }) //with new protocol you can add class method defineClass('classTestProtocolObject : NSObject ' ,{}, { testProtocol:function(arg1){ console.log(arg1); return 1; }, test2Protocol: function(arg1) { console.log(arg1); return 1; }, test3Protocol_withB_withC:function(arg1,arg2,arg3){ console.log(arg1); var size = {width:100,height:100}; return size; }, }) ================================================ FILE: Demo/iOSDemo/JSPatchTests/newProtocolTest.m ================================================ // // newProrotcolTest.m // JSPatchDemo // // Created by Awhisper on 15/12/27. // Copyright © 2015年 bang. All rights reserved. // #import "newProtocolTest.h" #import "JPEngine.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincomplete-implementation" @implementation baseTestProtocolObject // no method definition // no crash means addProtocol success @end @implementation structTestProtocolObject // no method definition // no crash means addProtocol success @end @implementation objectTestProtocolObject // no method definition // no crash means addProtocol success @end @implementation specialTestProtocolObject // no method definition // no crash means addProtocol success @end @implementation typeEncodeTestProtocolObject // no method definition // no crash means addProtocol success @end @implementation classTestProtocolObject // no method definition // no crash means addProtocol success @end #pragma clang diagnostic pop ================================================ FILE: Demo/iOSDemo/JSPatchTests/performanceTest.js ================================================ var performanceTestObj = require('NSObject').alloc().init(); var largeDict = { "id": 2619381, "title": "Seaborn Oyster Co.", "description": null, "width": 400, "height": 300, "images": { "hidpi": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher.jpg", "normal": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_1x.jpg", "teaser": "https://d13yacurqjgara.cloudfront.net/users/52758/screenshots/2619381/seaborn_oyster_co_j_fletcher_teaser.jpg" }, "views_count": 2166, "likes_count": 235, "comments_count": 2, "attachments_count": 0, "rebounds_count": 0, "buckets_count": 11, "created_at": "2016-03-29T17:12:41Z", "updated_at": "2016-03-29T17:12:53Z", "html_url": "https://dribbble.com/shots/2619381-Seaborn-Oyster-Co", "attachments_url": "https://api.dribbble.com/v1/shots/2619381/attachments", "buckets_url": "https://api.dribbble.com/v1/shots/2619381/buckets", "comments_url": "https://api.dribbble.com/v1/shots/2619381/comments", "likes_url": "https://api.dribbble.com/v1/shots/2619381/likes", "projects_url": "https://api.dribbble.com/v1/shots/2619381/projects", "rebounds_url": "https://api.dribbble.com/v1/shots/2619381/rebounds", "animated": false, "tags": [ "charleston", "company", "ocean", "oyster", "sea", "wave" ], "user": { "id": 52758, "name": "Jay Fletcher", "username": "jfletcherdesign", "html_url": "https://dribbble.com/jfletcherdesign", "avatar_url": "https://d13yacurqjgara.cloudfront.net/users/52758/avatars/normal/J_FLETCHER_DESIGN_LOGO-01.jpg?1401983283", "bio": "", "location": "Charleston, SC", "links": { "web": "http://www.jfletcherdesign.com", "twitter": "https://twitter.com/jfletcherdesign" }, "buckets_count": 0, "comments_received_count": 5239, "followers_count": 13803, "followings_count": 558, "likes_count": 6531, "likes_received_count": 104895, "projects_count": 10, "rebounds_received_count": 325, "shots_count": 481, "teams_count": 0, "can_upload_shot": true, "type": "Player", "pro": true, "buckets_url": "https://api.dribbble.com/v1/users/52758/buckets", "followers_url": "https://api.dribbble.com/v1/users/52758/followers", "following_url": "https://api.dribbble.com/v1/users/52758/following", "likes_url": "https://api.dribbble.com/v1/users/52758/likes", "projects_url": "https://api.dribbble.com/v1/users/52758/projects", "shots_url": "https://api.dribbble.com/v1/users/52758/shots", "teams_url": "https://api.dribbble.com/v1/users/52758/teams", "created_at": "2011-08-13T23:30:38Z", "updated_at": "2016-03-29T17:12:53Z" }, "team": null }; defineClass('JPPerformanceTest', { testJSCallOCEmptyMethod: function() { var slf = self for (var i = 0; i < 10000; i ++) { slf.emptyMethod(); } }, testJSCallOCMethodWithParamObject: function() { var slf = self for (var i = 0; i < 10000; i ++) { slf.methodWithParamObject(performanceTestObj); } }, testJSCallOCMethodReturnObject: function() { var slf = self for (var i = 0; i < 10000; i ++) { slf.methodReturnObject(); } }, testJSCallJSEmptyMethod: function() { var slf = self for (var i = 0; i < 10000; i ++) { slf.newJSEmptyMethod(); } }, testJSCallJSMethodWithParam: function() { var slf = self for (var i = 0; i < 10000; i ++) { slf.newJSMethodWithParam(performanceTestObj); } }, testJSCallJSMethodWithLargeDictionaryParam: function() { var slf = self for (var i = 0; i < 1000; i ++) { slf.newJSMethodWithLargeDictionaryParam(largeDict); } }, testJSCallJSMethodWithLargeDictionaryParamAutoConvert: function() { var slf = self autoConvertOCType(1); for (var i = 0; i < 1000; i ++) { slf.newJSMethodWithLargeDictionaryParam(largeDict); } autoConvertOCType(0); }, emptyMethodToOverride: function() { }, methodWithParamObjectToOverride: function(obj) { }, methodReturnObjectToOverride: function() { return performanceTestObj; }, newJSEmptyMethod: function() { }, newJSMethodWithParam: function(param) { }, newJSMethodWithLargeDictionaryParam: function(dict) { }, testJSCallMallocJPMemory: function() { require('JPEngine').addExtensions(['JPMemory']) for (var i = 0; i < 100000; i ++) { var p = malloc(10) } }, testJSCallMallocJPCFunction: function() { require('JPEngine').addExtensions(['JPCFunction']) for (var i = 0; i < 100000; i ++) { defineCFunction("malloc", "void *, size_t") var p = malloc(10) } } }) ================================================ FILE: Demo/iOSDemo/JSPatchTests/protocolTest.js ================================================ var global = this; (function() { defineClass("JPTestProtocolObject : NSObject ", { protocolWithDouble_dict: function(num, dict) { if (dict.objectForKey("name").toJS() == "JSPatch" && num - 4.2 < 0.001) { return num } return 0 }, protocolWithInt: function(num) { return num } }, { classProtocolWithString_int: function(str, num) { if (num == 42) return str return null } }) })(); ================================================ FILE: Demo/iOSDemo/JSPatchTests/superTest.js ================================================ defineClass('JPJSSuperTestA1 : JPSuperTestA', { method: function() { var str = self.super().method().toJS(); return str + '1'; } }) defineClass('JPJSSuperTestA2 : JPJSSuperTestA1', { method: function() { var str = self.super().method(); return str + '2'; } }) defineClass('JPJSSuperTestB2 : JPSuperTestB1', { method: function() { var str = self.super().method().toJS(); return str + '2'; } }) defineClass('JPJSSuperTestB3 : JPJSSuperTestB2', { method: function() { var str = self.super().method(); return str + '3'; } }) defineClass('JPSuperTestC1', { method: function() { var ret = self.ORIGmethod().toJS(); //should be C1 console.log("ttttt: " + ret + self.super().method().toJS()) return ret + self.super().method().toJS(); //should be C1C } }) defineClass('JPSuperTestResult', {}, { isPassA: function() { var o = JPJSSuperTestA2.alloc().init(); return o.method() == 'A12'; }, isPassB: function (){ var o2 = JPJSSuperTestB2.alloc().init(); var o3 = JPJSSuperTestB3.alloc().init(); return o2.method() == 'B12' && o3.method() == 'B123'; } }) ================================================ FILE: Demo/iOSDemo/JSPatchTests/test.js ================================================ include('protocolTest.js') include('newProtocolTest.js') var global = this; require('JPEngine').defineStruct({ "name": "UIEdgeInsets", "types": "FFFF", "keys": ["top", "left", "bottom", "right"] }); (function() { defineClass("JPTestObject", { funcToSwizzle_view: function(num, view) { self.ORIGfuncToSwizzle_view(num, view) self.setFuncToSwizzleViewPassed(view && 4.2 - num < 0.01) }, funcToSwizzleWithString_view_int: function(str, view, i) { self.setFuncToSwizzleWithStringViewIntPassed(str.toJS() == "stringFromOC" && view && i == 42) }, funcToSwizzleReturnView: function(view) { return view }, funcToSwizzleReturnInt: function(num) { return num }, funcToSwizzleReturnDictionary: function(dict) { return dict }, funcToSwizzleReturnJSDictionary: function() { return {"str" : "js_string"}; }, funcToSwizzleReturnArray: function(arr) { return arr }, funcToSwizzleReturnString: function(str) { return str }, funcToSwizzleWithBlock: function(blk) { blk(UIView.alloc().init(), 42) }, funcToSwizzle__withUnderLine__: function(num) { self.setFuncToSwizzle__withUnderLine__Passed(num == 42) }, funcOverrideParentMethod:function(){ return "overrided"; }, funcToSwizzleReturnRect: function(rect) { self.setFuncToSwizzleReturnRectJSPassed(rect.width == 100) return rect; }, funcToSwizzleReturnSize: function(size) { self.setFuncToSwizzleReturnSizeJSPassed(size.width == 42) return size; }, funcToSwizzleReturnPoint: function(point) { self.setFuncToSwizzleReturnPointJSPassed(point.x == 42) return point; }, funcToSwizzleReturnRange: function(range) { self.setFuncToSwizzleReturnRangeJSPassed(range.length == 42) return range; }, funcToSwizzleReturnEdgeInsets: function(edge) { self.setFuncToSwizzleReturnEdgeInsetsJSPassed(edge.top == 42) return edge; }, funcToSwizzleTestGCD: function(completeBlock) { var execCount = 0 var slf = self var dispatchExecBlock = function() { if (++execCount >= 4) { slf.setFuncToSwizzleTestGCDPassed(1) completeBlock() } } dispatch_async_main(dispatchExecBlock); dispatch_async_global_queue(dispatchExecBlock); dispatch_sync_main(dispatchExecBlock); dispatch_after(1, dispatchExecBlock); }, funcToSwizzleTestClass: function(cls) { return cls }, funcToSwizzleTestSelector: function(sel) { return sel }, funcToSwizzleTestChar: function(cStr) { return cStr }, funcToSwizzleTestPointer: function(pointer) { return pointer }, funcToSwizzleReturnClass:function(){ return require('JPTestObject').class() } }, { classFuncToSwizzle_int: function(o, num) { o.setClassFuncToSwizzlePassed(num == 10) }, classFuncToSwizzleReturnObj: function(o) { self.ORIGclassFuncToSwizzleReturnObj(o) return o }, classFuncToSwizzleReturnInt: function(i) { return i }, ///////Test for function which return double/float, cause there's a fatal bug in NSInvocation on iOS7.0 classFuncToSwizzleReturnDouble: function(d) { return d } }) defineClass("JPTestSwizzledForwardInvocationSubObject",{ stubMethod: function() {} }) var JPTestObject = require("JPTestObject") var UIView = require("UIView") var obj = JPTestObject.alloc().init() global.ocObj = obj.__obj; ////////Swizzle obj.callSwizzleMethod() var cls = obj.funcToSwizzleTestClass(JPTestObject.class()) obj.setFuncToSwizzleTestClassPassed(obj.isKindOfClass(cls)) obj.funcTestChar(obj.funcReturnChar()) var pointer = obj.funcReturnPointer() ////////Base obj.funcReturnVoid(); var testReturnString = obj.funcReturnString().toJS(); obj.setFuncReturnStringPassed(testReturnString == "stringFromOC") ////////Test Class function call testReturnString = obj.funcReturnClass().classFunCallReturnString().toJS(); testReturnString2 = obj.funcToSwizzleReturnClass().classFunCallReturnString().toJS(); obj.setFuncReturnClassPassed(testReturnString == "classFunCallReturnString" && testReturnString2 == "classFunCallReturnString") ////////Test Parameter Class return String var instanceString = obj.funcWithClassAndReturnString(JPTestObject.class()).toJS() var instanceString2 = obj.funcWithClassAndReturnString(obj.funcToSwizzleReturnClass()).toJS() var instanceString3 = obj.funcWithClassAndReturnString(obj.funcReturnClass()).toJS() var instanceString4 = obj.funcWithClassAndReturnString(require('JPTestObject')).toJS() obj.setFuncWithClassAndReturnStringPassed( instanceString == "JPTestObject" && instanceString2 == "JPTestObject" && instanceString3 == "JPTestObject" && instanceString4 == "JPTestObject" ) ///////Test for functions which return double/float, cause there's a fatal bug in NSInvocation on iOS7.0 var testReturnDouble = obj.funcReturnDouble() console.log(testReturnDouble == 100) obj.setFuncReturnDoublePassed(testReturnDouble == 100) obj.funcWithInt(42); obj.funcWithDict_andDouble({test: "test"}, 4.2) //////nil / NSNull obj.funcWithNil_dict_str_num(null, {k: "JSPatch"}, "JSPatch", 4.2) obj.funcWithNull(nsnull) var o = obj.funcReturnNil() obj.funcWithNil(o) obj.setFuncReturnNilPassed(!o) o.callAnyMethod().willNotCrash() var bTrue = obj.funcTestBool(true) var bFalse = obj.funcTestBool(false) var bFalseNum = obj.funcTestBool(0) obj.setFuncTestBoolPassed(bTrue && !bFalse && !bFalseNum) var num0 = obj.funcTestNSNumber(0) var num1 = obj.funcTestNSNumber(1) obj.setFuncTestNSNumberPassed(num0 === 0 && num1 === 1) ///////UIView/NSObject var view = obj.funcReturnViewWithFrame({ x: 0, y: 0, width: 100, height: 100 }); var viewFrame = view.frame() obj.setFuncReturnViewWithFramePassed(viewFrame.width == 100 && viewFrame.height == 100) var newView = UIView.alloc().initWithFrame({ x: 10, y: 10, width: 20, height: 20 }) var returnedView = obj.funcWithViewAndReturnView(newView); var returnedViewFrame = returnedView.frame() obj.setFuncWithViewAndReturnViewPassed(returnedViewFrame.width == 20 && returnedViewFrame.x == 10) //////CGRect/CGPoint/CGSize/NSRange var rect = obj.funcWithRectAndReturnRect({ x: 10, y: 10, width: 4.2, height: 4.2 }); obj.setFuncWithRectAndReturnRectPassed(rect.x == 10 && rect.y == 10 && rect.width - 4.2 < 0.01 && rect.height - 4.2 < 0.01) var point = obj.funcWithPointAndReturnPoint({ x: 10, y: 10 }); obj.setFuncWithPointAndReturnPointPassed(point.x == 10 && point.y == 10) var size = obj.funcWithSizeAndReturnSize({ width: 10, height: 10 }); obj.setFuncWithSizeAndReturnSizePassed(size.width == 10 && size.height == 10) var range = obj.funcWithRangeAndReturnRange({ location: 0, length: 100 }); obj.setFuncWithRangeAndReturnRangePassed(range.location == 0 && range.length == 100) /////Dictionary/Array var dict = obj.funcReturnDictStringInt().toJS() obj.setFuncReturnDictStringIntPassed(dict["str"] == "stringFromOC" && dict["num"] == 42) var dict = obj.funcReturnDictStringView().toJS(); var dictViewFrame = dict["view"].frame() obj.setFuncReturnDictStringViewPassed(dict.str == "stringFromOC" && dictViewFrame.width == 100) var arr = obj.funcReturnArrayControllerViewString().toJS() obj.setFuncReturnArrayControllerViewStringPassed(arr[0] && arr[1] && arr[2] == "stringFromOC") var dict = obj.funcReturnDict({name: "JSPatch"}).toJS() obj.setFuncReturnDictPassed(dict.name == "JSPatch") //////property var view = UIView.alloc().init(); view.setFrame({ x: 10, y: 10, width: 100, height: 100 }) obj.setPropertySetFramePassed(view.frame().width == 100 && view.bounds().height == 100) obj.testView = view obj.setPropertySetViewPassed(obj.testView.frame().x == 10) /////Block require('JPEngine').addExtensions(['JPBlock']); var blk = obj.funcReturnBlock(); blk("stringFromJS", 42); var blk = obj.funcReturnObjectBlock(); var view = UIView.alloc().initWithFrame({ x: 10, y: 10, width: 100, height: 100 }) var blkRet = blk({ str: "stringFromJS", view: view }, view) obj.setFuncReturnObjectBlockReturnValuePassed(blkRet.toJS() == "succ") var jsBlkRet = obj.funcReturnJSBlock(block("id, NSString *, int", function(str, num) { obj.setFuncReturnJSBlockPassed(str.toJS() == 'stringFromJS' && num == 42) })) jsBlkRet('stringFromJS', 42); obj.callBlockWithStringAndInt(block("id, NSString *, int", function(str, num) { obj.setCallBlockWithStringAndIntPassed(str.toJS() == "stringFromOC" && num == 42) return "succ" })) obj.callBlockDelay(block("id, NSString *, int", function(str, num) { obj.setCallBlockWithStringAndIntPassed(str.toJS() == "stringFromOC" && num == 42) return "succ" })) // request big memory to trigger JSContext gc // make sure the above argument function(str, num) not freed before calling. require('JPEngine').addExtensions(['JPCFunction']) for (var i = 0; i < 100000; i ++) { defineCFunction("malloc", "void *, size_t") var p = malloc(10) } obj.callBlockWithArrayAndView(block("id, NSArray *, UIView *", function(arr, view) { var viewFrame = view.frame() arr = arr.toJS() obj.setCallBlockWithArrayAndViewPassed(arr[0] == "stringFromOC" && arr[1] && viewFrame.width == 100) })) obj.callBlockWithBoolAndBlock(block("id, BOOL, NSBlock *", function(b, blk) { blk("stringFromJS", b ? 42 : 0); })) obj.callBlockWithObjectAndBlock(block("id, UIView *, NSBlock *", function(view, blk) { var viewFrame = view.frame() var ret = blk((viewFrame.width == 100 ? { "str": "stringFromJS", "view": view }: {}), view) obj.setCallBlockWithObjectAndBlockReturnValuePassed(ret.toJS() == "succ") })) obj.callBlockWithDouble(block("double, double", function(num) { return num + 4.2; })); //////super var subObj = require("JPTestSubObject").alloc().init() global.subObj = subObj.__obj; subObj.super().funcCallSuper() //////forwardInvocation obj.callTestForward() //////new class var JPNewTestObject = defineClass("JPNewTestObject", { funcReturnView: function(x) { var view = UIView.alloc().initWithFrame({ x: x, y: 10, width: 20, height: 20 }) return view } }, { funcReturnBool: function(view, num) { return view && num == 42 } }) var newTestObj = JPNewTestObject.alloc().init() var view = newTestObj.funcReturnView(42) obj.setNewTestObjectReturnViewPassed(view.frame().x == 42) obj.setNewTestObjectReturnBoolPassed(JPNewTestObject.funcReturnBool(view, 42)) //mutable var arr = require('NSMutableArray').alloc().init() arr.addObject("ctn") obj.setMutableArrayPassed(arr.objectAtIndex(0).toJS() == "ctn") var dict = require('NSMutableDictionary').alloc().init() dict.setObject_forKey("ctn", "k") obj.setMutableDictionaryPassed(dict.objectForKey("k").toJS() == "ctn") var str = require('NSMutableString').alloc().init() str.appendString("JS") str.appendString("Patch") obj.setMutableStringPassed(str.toJS() == "JSPatch") var arr = [] arr.push(obj.getString(), obj.getDictionary(), obj.getArray()) obj.funcTestBoxingObj(arr) obj.setConsoleLogPassed(console.log != undefined) //extension var transform = obj.funcWithTransform({tx: 100, ty: 100, a: 1, b: 0, c: 0, d: 1}) obj.setFuncWithTransformPassed(transform.tx == 100 && transform.ty == 100 && transform.a == 1) var translated = CGAffineTransformTranslate(transform, 10, 10); obj.setTransformTranslatePassed(translated.tx == 110 && translated.ty == 110) obj.funcTestPointer(pointer) free(pointer) //sizeof var rectSize = sizeof("CGRect") var pointSize = sizeof("CGPoint") var sizeSize = sizeof("CGSize") var vectorSize = sizeof("CGVector") var edgeInsetsSize = sizeof("UIEdgeInsets") var transformSize = sizeof("CGAffineTransform") var rangeSize = sizeof("NSRange") obj.setFuncTestSizeofPassed(rectSize > 0 && pointSize > 0 && sizeSize > 0 && vectorSize > 0 && edgeInsetsSize > 0 && transformSize > 0 && rangeSize > 0) //getPointerTest1 - Test Object in JPBoxing var sig = require('JPTestObject').instanceMethodSignatureForSelector("funcTestGetPointer1:"); var invocation = require('NSInvocation').invocationWithMethodSignature(sig) var str = require('NSString').stringWithString('JSPatch') invocation.setTarget(obj) invocation.setSelector("funcTestGetPointer1:") invocation.setArgument_atIndex(getPointer(str), 2) invocation.invoke() var ret1 = malloc(1) invocation.getReturnValue(ret1) var bool1 = pvalBool(ret1) //getPointerTest2 - Test Normal Object var sig = require('JPTestObject').instanceMethodSignatureForSelector("funcTestGetPointer2:"); var invocation = require('NSInvocation').invocationWithMethodSignature(sig) var err = require('NSError').errorWithDomain_code_userInfo("com.albert43",45,{msg:"test"}); invocation.setTarget(obj) invocation.setSelector("funcTestGetPointer2:") invocation.setArgument_atIndex(getPointer(err), 2) invocation.invoke() var ret2 = malloc(1) invocation.getReturnValue(ret2); var bool2 = pvalBool(ret2) //getPointerTest3 - Test Pointer var ptr = malloc(10) memset(ptr, 65, 10) var sig = require('JPTestObject').instanceMethodSignatureForSelector("funcTestGetPointer3:"); var invocation = require('NSInvocation').invocationWithMethodSignature(sig) invocation.setTarget(obj) invocation.setSelector("funcTestGetPointer3:") invocation.setArgument_atIndex(getPointer(ptr), 2) invocation.invoke() var ret3 = malloc(1) invocation.getReturnValue(ret3); var bool3 = pvalBool(ret3) obj.setFuncTestGetPointerPassed(bool1 && bool2 && bool3) free(ret1) free(ret2) free(ret3) free(ptr) //funcTestNSErrorPointer var p_error = malloc(8) obj.funcTestNSErrorPointer(p_error) var error = pval(p_error) if (!error) { obj.setFuncTestNSErrorPointerPassed(false) } else { var code = error.code() obj.setFuncTestNSErrorPointerPassed(code==43) } releaseTmpObj(p_error) free(p_error) //funcTestNilParametersInBlock var blk = obj.funcGenerateBlock() var str1 = blk(obj.funcReturnNil()) var str2 = blk(null) var str3 = obj.excuteBlockWithNilParameters(block("NSError *", blk)) if (str1.toJS() == "no error" && str2.toJS() == "no error" && str3.toJS() == "no error") { obj.setFuncTestNilParametersInBlockPassed(true) } //newStruct var pRect = newStruct('CGRect', {x:0, y:0, width:100, height:100}); obj.funcWithRectPointer(pRect); var rect = pvalStruct('CGRect', pRect); obj.setFuncWithRectPointerPassed(obj.funcWithRectPointerPassed() && rect.x == 42) free(pRect); var pTransform = newStruct('CGAffineTransform', {tx:0, ty:0, a:100, b:100, c:0, d:0}); obj.funcWithTransformPointer(pTransform); var transform = pvalStruct('CGAffineTransform', pTransform); obj.setFuncWithTransformPointerPassed(obj.funcWithTransformPointerPassed() && transform.tx == 42) free(pTransform); //variable parameter method var strWithFormat = require('NSString').stringWithFormat("%@ %@", "a", "b"); obj.setVariableParameterMethodPassed(strWithFormat.toJS() == "a b"); })(); ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/AppDelegate.h ================================================ // // AppDelegate.h // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/AppDelegate.m ================================================ // // AppDelegate.m // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import "AppDelegate.h" #import "JPRootViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; JPRootViewController *rootViewController = [[JPRootViewController alloc] init]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController]; self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // 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. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // 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. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // 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. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/Assets.xcassets/Brand Assets.launchimage/Contents.json ================================================ { "images" : [ { "orientation" : "portrait", "idiom" : "iphone", "minimum-system-version" : "7.0", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "minimum-system-version" : "7.0", "subtype" : "retina4", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/Assets.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "736h", "filename" : "Default-576@2x.png", "minimum-system-version" : "8.0", "orientation" : "portrait", "scale" : "3x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "736h", "filename" : "Default-736@3x.png", "minimum-system-version" : "8.0", "orientation" : "landscape", "scale" : "3x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "667h", "filename" : "Default-667@2x.png", "minimum-system-version" : "8.0", "orientation" : "portrait", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "Default@2x.png", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "retina4", "filename" : "Default-568h@2x.png", "minimum-system-version" : "7.0", "orientation" : "portrait", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "1x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS projectPath $(SRCROOT)/$(TARGET_NAME) UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/JPErrorMsgViewController.h ================================================ // // JPErrorMsgViewController.h // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import @interface JPErrorMsgViewController : UIViewController - (instancetype)initWithMsg:(NSString *)msg; @end ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/JPErrorMsgViewController.m ================================================ // // JPErrorMsgViewController.m // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import "JPErrorMsgViewController.h" @interface JPErrorMsgViewController () @property (nonatomic) NSString *msg; @end @implementation JPErrorMsgViewController - (instancetype)initWithMsg:(NSString *)msg { self = [super init]; if (self) { self.msg = msg; } return self; } - (void)viewDidLoad { [super viewDidLoad]; UITextView *textView = [[UITextView alloc] initWithFrame:[UIScreen mainScreen].bounds]; textView.scrollEnabled = YES; textView.text = self.msg; [self.view addSubview:textView]; self.title = @"JSPatch Error"; [self.navigationItem setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStyleDone target:self action:@selector(handleBack)]]; } - (void)handleBack { [self.navigationController dismissViewControllerAnimated:YES completion:nil]; } @end ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/JPRootViewController.h ================================================ // // ViewController.h // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import @interface JPRootViewController : UIViewController @end ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/JPRootViewController.m ================================================ // // ViewController.m // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import "JPRootViewController.h" #import "JPEngine.h" #import "SGDirWatchdog.h" #import "JPCleaner.h" #import "JPErrorMsgViewController.h" @interface JPRootViewController () @property (nonatomic) NSMutableArray *watchDogs; @property (nonatomic) UIWindow *errorWindow; @property (nonatomic) NSString *errMsg; @end @implementation JPRootViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; #if TARGET_IPHONE_SIMULATOR NSString *rootPath = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"projectPath"]; #else NSString *rootPath = [[NSBundle mainBundle] bundlePath]; #endif [JPEngine handleException:^(NSString *msg) { if (!self.errorWindow) { self.errorWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 20)]; self.errorWindow.windowLevel = UIWindowLevelStatusBar + 1.0f; self.errorWindow.backgroundColor = [UIColor blackColor]; UIButton *errBtn = [[UIButton alloc] initWithFrame:CGRectMake(5, 0, [UIScreen mainScreen].bounds.size.width - 10, 20)]; errBtn.titleLabel.font = [UIFont systemFontOfSize:10]; [errBtn setTitle:msg forState:UIControlStateNormal]; [errBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; errBtn.tag = 100; [errBtn addTarget:self action:@selector(handleTapErrorBtn) forControlEvents:UIControlEventTouchDown]; [self.errorWindow addSubview:errBtn]; [self.errorWindow makeKeyAndVisible]; } else { UIButton *errBtn = [self.errorWindow viewWithTag:100]; [errBtn setTitle:msg forState:UIControlStateNormal]; } self.errMsg = msg; self.errorWindow.hidden = NO; }]; NSString *scriptRootPath = [rootPath stringByAppendingPathComponent:@"src"]; NSString *mainScriptPath = [NSString stringWithFormat:@"%@/%@", scriptRootPath, @"/main.js"]; [JPEngine evaluateScriptWithPath:mainScriptPath]; self.watchDogs = [[NSMutableArray alloc] init]; NSArray *contentOfFolder = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:scriptRootPath error:NULL]; [self watchFolder:scriptRootPath mainScriptPath:mainScriptPath]; for (NSString *aPath in contentOfFolder) { NSString * fullPath = [scriptRootPath stringByAppendingPathComponent:aPath]; BOOL isDir; if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDir] && isDir) { [self watchFolder:fullPath mainScriptPath:mainScriptPath]; } } [self showController]; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, 50)]; [btn setTitle:@"Push Playground" forState:UIControlStateNormal]; [btn addTarget:self action:@selector(showController) forControlEvents:UIControlEventTouchUpInside]; [btn setBackgroundColor:[UIColor grayColor]]; [self.view addSubview:btn]; } - (void)handleTapErrorBtn { JPErrorMsgViewController *errorMsgVC = [[JPErrorMsgViewController alloc] initWithMsg:self.errMsg]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:errorMsgVC]; [self.navigationController presentViewController:navigationController animated:YES completion:nil]; } - (void)watchFolder:(NSString *)folderPath mainScriptPath:(NSString *)mainScriptPath { SGDirWatchdog *watchDog = [[SGDirWatchdog alloc] initWithPath:folderPath update:^{ self.errorWindow.hidden = YES; [JPCleaner cleanAll]; [JPEngine evaluateScriptWithPath:mainScriptPath]; [self.navigationController popToRootViewControllerAnimated:NO]; [self showController]; }]; [watchDog start]; [self.watchDogs addObject:watchDog]; } - (void)showController { //override in JSPatch } @end ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/libs/SGDirWatchdog.h ================================================ // // SGDirObserver.h // DirectoryObserver // // Copyright (c) 2011 Simon Grätzer. // #import @interface SGDirWatchdog : NSObject @property (readonly, nonatomic) NSString *path; @property (copy, nonatomic) void (^update)(void); + (NSString *)documentsPath; + (id)watchtdogOnDocumentsDir:(void (^)(void))update; - (id)initWithPath:(NSString *)path update:(void (^)(void))update; - (void)start; - (void)stop; @end ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/libs/SGDirWatchdog.m ================================================ // // SGDirObserver.m // DirectoryObserver // // Copyright (c) 2011 Simon Grätzer. // #import "SGDirWatchdog.h" #import #import #import @interface SGDirWatchdog () @property (nonatomic, readonly) CFFileDescriptorRef kqRef; - (void)kqueueFired; @end static void KQCallback(CFFileDescriptorRef kqRef, CFOptionFlags callBackTypes, void *info) { // Pick up the object passed in the "info" member of the CFFileDescriptorContext passed to CFFileDescriptorCreate SGDirWatchdog* obj = (__bridge SGDirWatchdog*) info; if ([obj isKindOfClass:[SGDirWatchdog class]] && // If we can call back to the proper sort of object ... (kqRef == obj.kqRef) && // and the FD that issued the CB is the expected one ... (callBackTypes == kCFFileDescriptorReadCallBack) ) // and we're processing the proper sort of CB ... { [obj kqueueFired]; // Invoke the instance's CB handler } } @implementation SGDirWatchdog { int _dirFD; CFFileDescriptorRef _kqRef; } + (NSString *)documentsPath { NSArray *documentsPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); return documentsPaths[0]; // Path to the application's "Documents" directory } + (id)watchtdogOnDocumentsDir:(void (^)(void))update; { return [[SGDirWatchdog alloc]initWithPath:[self documentsPath] update:update]; } - (id)initWithPath:(NSString *)path update:(void (^)(void))update; { if ((self = [super init])) { _path = path; _update = [update copy]; } return self; } - (void)dealloc { [self stop]; } #pragma mark - #pragma mark Extension methods - (void)kqueueFired { // Pull the native FD around which the CFFileDescriptor was wrapped int kq = CFFileDescriptorGetNativeDescriptor(_kqRef); if (kq < 0) return; // If we pull a single available event out of the queue, assume the directory was updated struct kevent event; struct timespec timeout = {0, 0}; if (kevent(kq, NULL, 0, &event, 1, &timeout) == 1 && _update) { _update(); } // (Re-)Enable a one-shot (the only kind) callback CFFileDescriptorEnableCallBacks(_kqRef, kCFFileDescriptorReadCallBack); } - (void)start { // One ping only if (_kqRef != NULL) return; // Fetch pathname of the directory to monitor NSString* docPath = self.path; if (!docPath) return; // Open an event-only file descriptor associated with the directory int dirFD = open([docPath fileSystemRepresentation], O_EVTONLY); if (dirFD < 0) return; // Create a new kernel event queue int kq = kqueue(); if (kq < 0) { close(dirFD); return; } // Set up a kevent to monitor struct kevent eventToAdd; // Register an (ident, filter) pair with the kqueue eventToAdd.ident = dirFD; // The object to watch (the directory FD) eventToAdd.filter = EVFILT_VNODE; // Watch for certain events on the VNODE spec'd by ident eventToAdd.flags = EV_ADD | EV_CLEAR; // Add a resetting kevent eventToAdd.fflags = NOTE_WRITE; // The events to watch for on the VNODE spec'd by ident (writes) eventToAdd.data = 0; // No filter-specific data eventToAdd.udata = NULL; // No user data // Add a kevent to monitor if (kevent(kq, &eventToAdd, 1, NULL, 0, NULL)) { close(kq); close(dirFD); return; } // Wrap a CFFileDescriptor around a native FD CFFileDescriptorContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; _kqRef = CFFileDescriptorCreate(NULL, // Use the default allocator kq, // Wrap the kqueue true, // Close the CFFileDescriptor if kq is invalidated KQCallback, // Fxn to call on activity &context); // Supply a context to set the callback's "info" argument if (_kqRef == NULL) { close(kq); close(dirFD); return; } // Spin out a pluggable run loop source from the CFFileDescriptorRef // Add it to the current run loop, then release it CFRunLoopSourceRef rls = CFFileDescriptorCreateRunLoopSource(NULL, _kqRef, 0); if (rls == NULL) { CFRelease(_kqRef); _kqRef = NULL; close(kq); close(dirFD); return; } CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); CFRelease(rls); // Store the directory FD for later closing _dirFD = dirFD; // Enable a one-shot (the only kind) callback CFFileDescriptorEnableCallBacks(_kqRef, kCFFileDescriptorReadCallBack); } - (void)stop { if (_kqRef) { close(_dirFD); CFFileDescriptorInvalidate(_kqRef); CFRelease(_kqRef); _kqRef = NULL; } } @end ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/main.m ================================================ // // main.m // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/src/JPDemoController.js ================================================ require('UILabel, UIColor, UIFont, UIScreen, UIImageView, UIImage') var screenWidth = UIScreen.mainScreen().bounds().width; var screenHeight = UIScreen.mainScreen().bounds().height; defineClass('JPDemoController: UIViewController', { viewDidLoad: function() { self.super().viewDidLoad(); self.view().setBackgroundColor(UIColor.whiteColor()); var size = 120; var imgView = UIImageView.alloc().initWithFrame({x: (screenWidth - size)/2, y: 150, width: size, height: size}); imgView.setImage(UIImage.imageWithContentsOfFile(resourcePath('apple.png'))); self.view().addSubview(imgView); var label = UILabel.alloc().initWithFrame({x: 0, y: 310, width: screenWidth, height: 30}); label.setText("JSPatch"); label.setTextAlignment(1); label.setFont(UIFont.systemFontOfSize(25)); self.view().addSubview(label); }, }) ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground/src/main.js ================================================ include('JPDemoController.js'); defineClass('JPRootViewController', { showController: function() { var ctrl = JPDemoController.alloc().init(); self.navigationController().pushViewController_animated(ctrl, NO); } }); ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 361443641CE8041A00B303D4 /* JPCleaner.m in Sources */ = {isa = PBXBuildFile; fileRef = 361443461CE8041A00B303D4 /* JPCleaner.m */; }; 361443651CE8041A00B303D4 /* JPLocker.m in Sources */ = {isa = PBXBuildFile; fileRef = 361443481CE8041A00B303D4 /* JPLocker.m */; }; 361443671CE8041A00B303D4 /* JPSpecialInit.m in Sources */ = {isa = PBXBuildFile; fileRef = 3614434C1CE8041A00B303D4 /* JPSpecialInit.m */; }; 3614436D1CE8041A00B303D4 /* JPEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 3614435A1CE8041A00B303D4 /* JPEngine.m */; }; 3614436E1CE8041A00B303D4 /* JSPatch.js in Resources */ = {isa = PBXBuildFile; fileRef = 3614435B1CE8041A00B303D4 /* JSPatch.js */; }; 3660A8671CE3542A008970B4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3660A8661CE3542A008970B4 /* main.m */; }; 3660A86A1CE3542A008970B4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3660A8691CE3542A008970B4 /* AppDelegate.m */; }; 3660A86D1CE3542A008970B4 /* JPRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3660A86C1CE3542A008970B4 /* JPRootViewController.m */; }; 3660A8721CE3542A008970B4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3660A8711CE3542A008970B4 /* Assets.xcassets */; }; 3660A8B51CE365FB008970B4 /* src in Resources */ = {isa = PBXBuildFile; fileRef = 3660A8B41CE365FB008970B4 /* src */; }; 3660A8F21CE36D05008970B4 /* SGDirWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 3660A8F11CE36D05008970B4 /* SGDirWatchdog.m */; }; 3660A90D1CE4A546008970B4 /* JPErrorMsgViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3660A90C1CE4A546008970B4 /* JPErrorMsgViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 361443451CE8041A00B303D4 /* JPCleaner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCleaner.h; sourceTree = ""; }; 361443461CE8041A00B303D4 /* JPCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCleaner.m; sourceTree = ""; }; 361443471CE8041A00B303D4 /* JPLocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPLocker.h; sourceTree = ""; }; 361443481CE8041A00B303D4 /* JPLocker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPLocker.m; sourceTree = ""; }; 3614434B1CE8041A00B303D4 /* JPSpecialInit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPSpecialInit.h; sourceTree = ""; }; 3614434C1CE8041A00B303D4 /* JPSpecialInit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPSpecialInit.m; sourceTree = ""; }; 361443591CE8041A00B303D4 /* JPEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPEngine.h; sourceTree = ""; }; 3614435A1CE8041A00B303D4 /* JPEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPEngine.m; sourceTree = ""; }; 3614435B1CE8041A00B303D4 /* JSPatch.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSPatch.js; sourceTree = ""; }; 3660A8621CE3542A008970B4 /* JSPatchPlayground.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSPatchPlayground.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3660A8661CE3542A008970B4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 3660A8681CE3542A008970B4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 3660A8691CE3542A008970B4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 3660A86B1CE3542A008970B4 /* JPRootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JPRootViewController.h; sourceTree = ""; }; 3660A86C1CE3542A008970B4 /* JPRootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JPRootViewController.m; sourceTree = ""; }; 3660A8711CE3542A008970B4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 3660A8761CE3542A008970B4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 3660A8B41CE365FB008970B4 /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; name = src; path = JSPatchPlayground/src; sourceTree = SOURCE_ROOT; }; 3660A8F01CE36D05008970B4 /* SGDirWatchdog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGDirWatchdog.h; sourceTree = ""; }; 3660A8F11CE36D05008970B4 /* SGDirWatchdog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGDirWatchdog.m; sourceTree = ""; }; 3660A90B1CE4A546008970B4 /* JPErrorMsgViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPErrorMsgViewController.h; sourceTree = ""; }; 3660A90C1CE4A546008970B4 /* JPErrorMsgViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPErrorMsgViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 3660A85F1CE3542A008970B4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 361443331CE8041A00B303D4 /* Extensions */ = { isa = PBXGroup; children = ( 361443451CE8041A00B303D4 /* JPCleaner.h */, 361443461CE8041A00B303D4 /* JPCleaner.m */, 361443471CE8041A00B303D4 /* JPLocker.h */, 361443481CE8041A00B303D4 /* JPLocker.m */, 3614434B1CE8041A00B303D4 /* JPSpecialInit.h */, 3614434C1CE8041A00B303D4 /* JPSpecialInit.m */, ); name = Extensions; path = ../../../Extensions; sourceTree = ""; }; 361443581CE8041A00B303D4 /* JSPatch */ = { isa = PBXGroup; children = ( 361443591CE8041A00B303D4 /* JPEngine.h */, 3614435A1CE8041A00B303D4 /* JPEngine.m */, 3614435B1CE8041A00B303D4 /* JSPatch.js */, ); name = JSPatch; path = ../../../JSPatch; sourceTree = ""; }; 3660A8591CE3542A008970B4 = { isa = PBXGroup; children = ( 3660A8641CE3542A008970B4 /* JSPatchPlayground */, 3660A8631CE3542A008970B4 /* Products */, ); sourceTree = ""; }; 3660A8631CE3542A008970B4 /* Products */ = { isa = PBXGroup; children = ( 3660A8621CE3542A008970B4 /* JSPatchPlayground.app */, ); name = Products; sourceTree = ""; }; 3660A8641CE3542A008970B4 /* JSPatchPlayground */ = { isa = PBXGroup; children = ( 361443331CE8041A00B303D4 /* Extensions */, 361443581CE8041A00B303D4 /* JSPatch */, 3660A8B61CE369F0008970B4 /* libs */, 3660A8B41CE365FB008970B4 /* src */, 3660A8681CE3542A008970B4 /* AppDelegate.h */, 3660A8691CE3542A008970B4 /* AppDelegate.m */, 3660A86B1CE3542A008970B4 /* JPRootViewController.h */, 3660A86C1CE3542A008970B4 /* JPRootViewController.m */, 3660A90B1CE4A546008970B4 /* JPErrorMsgViewController.h */, 3660A90C1CE4A546008970B4 /* JPErrorMsgViewController.m */, 3660A8711CE3542A008970B4 /* Assets.xcassets */, 3660A8761CE3542A008970B4 /* Info.plist */, 3660A8651CE3542A008970B4 /* Supporting Files */, ); path = JSPatchPlayground; sourceTree = ""; }; 3660A8651CE3542A008970B4 /* Supporting Files */ = { isa = PBXGroup; children = ( 3660A8661CE3542A008970B4 /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; 3660A8B61CE369F0008970B4 /* libs */ = { isa = PBXGroup; children = ( 3660A8F01CE36D05008970B4 /* SGDirWatchdog.h */, 3660A8F11CE36D05008970B4 /* SGDirWatchdog.m */, ); path = libs; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 3660A8611CE3542A008970B4 /* JSPatchPlayground */ = { isa = PBXNativeTarget; buildConfigurationList = 3660A8791CE3542A008970B4 /* Build configuration list for PBXNativeTarget "JSPatchPlayground" */; buildPhases = ( 3660A85E1CE3542A008970B4 /* Sources */, 3660A85F1CE3542A008970B4 /* Frameworks */, 3660A8601CE3542A008970B4 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = JSPatchPlayground; productName = JSPatchPlayground; productReference = 3660A8621CE3542A008970B4 /* JSPatchPlayground.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 3660A85A1CE3542A008970B4 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0720; ORGANIZATIONNAME = bang; TargetAttributes = { 3660A8611CE3542A008970B4 = { CreatedOnToolsVersion = 7.2.1; }; }; }; buildConfigurationList = 3660A85D1CE3542A008970B4 /* Build configuration list for PBXProject "JSPatchPlayground" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 3660A8591CE3542A008970B4; productRefGroup = 3660A8631CE3542A008970B4 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 3660A8611CE3542A008970B4 /* JSPatchPlayground */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 3660A8601CE3542A008970B4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 3614436E1CE8041A00B303D4 /* JSPatch.js in Resources */, 3660A8721CE3542A008970B4 /* Assets.xcassets in Resources */, 3660A8B51CE365FB008970B4 /* src in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 3660A85E1CE3542A008970B4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3660A8F21CE36D05008970B4 /* SGDirWatchdog.m in Sources */, 3660A90D1CE4A546008970B4 /* JPErrorMsgViewController.m in Sources */, 361443641CE8041A00B303D4 /* JPCleaner.m in Sources */, 361443671CE8041A00B303D4 /* JPSpecialInit.m in Sources */, 361443651CE8041A00B303D4 /* JPLocker.m in Sources */, 3660A86D1CE3542A008970B4 /* JPRootViewController.m in Sources */, 3614436D1CE8041A00B303D4 /* JPEngine.m in Sources */, 3660A86A1CE3542A008970B4 /* AppDelegate.m in Sources */, 3660A8671CE3542A008970B4 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 3660A8771CE3542A008970B4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; 3660A8781CE3542A008970B4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 3660A87A1CE3542A008970B4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = JSPatchPlayground/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = net.cnbang.JSPatchPlayground; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 3660A87B1CE3542A008970B4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = JSPatchPlayground/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = net.cnbang.JSPatchPlayground; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 3660A85D1CE3542A008970B4 /* Build configuration list for PBXProject "JSPatchPlayground" */ = { isa = XCConfigurationList; buildConfigurations = ( 3660A8771CE3542A008970B4 /* Debug */, 3660A8781CE3542A008970B4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3660A8791CE3542A008970B4 /* Build configuration list for PBXNativeTarget "JSPatchPlayground" */ = { isa = XCConfigurationList; buildConfigurations = ( 3660A87A1CE3542A008970B4 /* Debug */, 3660A87B1CE3542A008970B4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 3660A85A1CE3542A008970B4 /* Project object */; } ================================================ FILE: Demo/iOSPlayground/JSPatchPlayground.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/iOSPlayground/README.md ================================================ # JSPatch Playground ![Screenshot](https://raw.github.com/bang590/JSPatch/master/Demo/iOSPlayground/Screenshot.gif) ## Introduce JSPatch Playground is an interactive JSPatch coding environment, the iOS simulator will refresh and displays results instantly as js files save. You can also setup a playground in your own project to use JSPatch build user interface easily. Tips: if there is error of the script code, the status bar will show the messages, tap the status bar if you want to see more details. ## 介绍 JSPatch Playground 可以让你快速看到 JSPatch 代码执行效果,APP在模拟器运行后,每次修改脚本保存模拟器都会自动刷新,无需重启模拟器,即时看到效果。 你也可以仿照 JSPatch Playground 在你的项目里添加 JSPatch 脚本即时刷新功能,帮助你快速使用 JSPatch 开发功能模块。 Tips: 如果运行过程中脚本执行错误,会在状态栏里显示错误原因,点击状态栏可以看到更详细的错误提示。 ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/AppDelegate.h ================================================ // // AppDelegate.h // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015年 bang. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/AppDelegate.m ================================================ // // AppDelegate.m // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015年 bang. All rights reserved. // #import "AppDelegate.h" #import "JPEngine.h" #import "JPRootViewController.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; JPRootViewController *rootViewController = [[JPRootViewController alloc] init]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController]; self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; return YES; } @end ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/Assets.xcassets/apple.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "apple.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight projectPath $(SRCROOT)/$(TARGET_NAME) ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/JPRootViewController.h ================================================ // // ViewController.h // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import @interface JPRootViewController : UIViewController @end ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/JPRootViewController.m ================================================ // // ViewController.m // JSPatchPlayground // // Created by bang on 5/14/16. // Copyright © 2016 bang. All rights reserved. // #import "JPRootViewController.h" #import "JPEngine.h" #import "JPPlayground.h" @interface JPRootViewController () @end @implementation JPRootViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; [JPEngine startEngine]; #if TARGET_IPHONE_SIMULATOR //playground调试 //JS测试包的本地绝对路径 NSString *rootPath = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"projectPath"];; NSString *scriptPath = [NSString stringWithFormat:@"%@/js/%@", rootPath, @"/demo.js"]; [JPPlayground setReloadCompleteHandler:^{ [self showController]; }]; [JPPlayground startPlaygroundWithJSPath:scriptPath]; #else //正常执行JSPatch NSString *rootPath = [[NSBundle mainBundle] bundlePath]; NSString *scriptPath = [rootPath stringByAppendingPathComponent:@"demo.js"]; [JPEngine evaluateScriptWithPath:scriptPath]; #endif UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, 50)]; [btn setTitle:@"Push Playground" forState:UIControlStateNormal]; [btn addTarget:self action:@selector(showController) forControlEvents:UIControlEventTouchUpInside]; [btn setBackgroundColor:[UIColor grayColor]]; [self.view addSubview:btn]; } - (void)showController { Class clz = NSClassFromString(@"JPDemoController"); if (clz) { id vc = [[clz alloc]init]; [self.navigationController popViewControllerAnimated:NO]; [self.navigationController pushViewController:vc animated:NO]; } } @end ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/js/demo.js ================================================ require('UILabel, UIColor, UIFont, UIScreen, UIImageView, UIImage') var screenWidth = UIScreen.mainScreen().bounds().width; var screenHeight = UIScreen.mainScreen().bounds().height; defineClass('JPDemoController: UIViewController', { viewDidLoad: function() { self.super().viewDidLoad(); self.view().setBackgroundColor(UIColor.whiteColor()); var size = 120; var imgView = UIImageView.alloc().initWithFrame({x: (screenWidth - size)/2, y: 150, width: size, height: size}); imgView.setImage(UIImage.imageNamed('apple')) self.view().addSubview(imgView); var label = UILabesl.alloc().initWithFrame({x: 0, y: 310, width: screenWidth, height: 30}); label.setText("JSPatc22h"); label.setTextAlignment(1); label.setFont(UIFont.systemFontOfSize(25)); self.view().addSubview(label); }, }) ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo/main.m ================================================ // // main.m // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 6C0910D41D5829C6006CB65E /* JPCFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910771D5829C6006CB65E /* JPCFunction.m */; }; 6C0910D51D5829C6006CB65E /* JPMemory.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910791D5829C6006CB65E /* JPMemory.m */; }; 6C0910D61D5829C6006CB65E /* JPStructPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C09107B1D5829C6006CB65E /* JPStructPointer.m */; }; 6C0910D71D5829C6006CB65E /* ffi_arm64.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910901D5829C6006CB65E /* ffi_arm64.c */; }; 6C0910D81D5829C6006CB65E /* sysv_arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910911D5829C6006CB65E /* sysv_arm64.S */; }; 6C0910D91D5829C6006CB65E /* ffi_armv7.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910931D5829C6006CB65E /* ffi_armv7.c */; }; 6C0910DA1D5829C6006CB65E /* sysv_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910941D5829C6006CB65E /* sysv_armv7.S */; }; 6C0910DB1D5829C6006CB65E /* trampoline_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910951D5829C6006CB65E /* trampoline_armv7.S */; }; 6C0910DC1D5829C6006CB65E /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910971D5829C6006CB65E /* prep_cif.c */; }; 6C0910DD1D5829C6006CB65E /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910981D5829C6006CB65E /* raw_api.c */; }; 6C0910DE1D5829C6006CB65E /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910991D5829C6006CB65E /* types.c */; }; 6C0910DF1D5829C6006CB65E /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C09109B1D5829C6006CB65E /* darwin64_x86_64.S */; }; 6C0910E01D5829C6006CB65E /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C09109C1D5829C6006CB65E /* darwin_i386.S */; }; 6C0910E11D5829C6006CB65E /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C09109D1D5829C6006CB65E /* ffi64_x86_64.c */; }; 6C0910E21D5829C6006CB65E /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C09109E1D5829C6006CB65E /* ffi_i386.c */; }; 6C0910E31D5829C6006CB65E /* win32_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C09109F1D5829C6006CB65E /* win32_i386.S */; }; 6C0910E41D5829C6006CB65E /* JPCGBitmapContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910A31D5829C6006CB65E /* JPCGBitmapContext.m */; }; 6C0910E51D5829C6006CB65E /* JPCGColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910A51D5829C6006CB65E /* JPCGColor.m */; }; 6C0910E61D5829C6006CB65E /* JPCGContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910A71D5829C6006CB65E /* JPCGContext.m */; }; 6C0910E71D5829C6006CB65E /* JPCGGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910A91D5829C6006CB65E /* JPCGGeometry.m */; }; 6C0910E81D5829C6006CB65E /* JPCGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910AB1D5829C6006CB65E /* JPCGImage.m */; }; 6C0910E91D5829C6006CB65E /* JPCGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910AD1D5829C6006CB65E /* JPCGPath.m */; }; 6C0910EA1D5829C6006CB65E /* JPCGTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910AF1D5829C6006CB65E /* JPCGTransform.m */; }; 6C0910EB1D5829C6006CB65E /* JPCoreGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910B11D5829C6006CB65E /* JPCoreGraphics.m */; }; 6C0910EC1D5829C6006CB65E /* JPUIGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910B41D5829C6006CB65E /* JPUIGeometry.m */; }; 6C0910ED1D5829C6006CB65E /* JPUIGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910B61D5829C6006CB65E /* JPUIGraphics.m */; }; 6C0910EE1D5829C6006CB65E /* JPUIImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910B81D5829C6006CB65E /* JPUIImage.m */; }; 6C0910EF1D5829C6006CB65E /* JPUIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910BA1D5829C6006CB65E /* JPUIKit.m */; }; 6C0910F01D5829C6006CB65E /* JPCleaner.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910BC1D5829C6006CB65E /* JPCleaner.m */; }; 6C0910F11D5829C6006CB65E /* JPLocker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910BE1D5829C6006CB65E /* JPLocker.m */; }; 6C0910F21D5829C6006CB65E /* JPPlayground.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910C11D5829C6006CB65E /* JPPlayground.m */; }; 6C0910F31D5829C6006CB65E /* JPKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910C41D5829C6006CB65E /* JPKeyCommands.m */; }; 6C0910F41D5829C6006CB65E /* SGDirWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910C61D5829C6006CB65E /* SGDirWatchdog.m */; }; 6C0910F51D5829C6006CB65E /* JPDevErrorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910C91D5829C6006CB65E /* JPDevErrorView.m */; }; 6C0910F61D5829C6006CB65E /* JPDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910CB1D5829C6006CB65E /* JPDevMenu.m */; }; 6C0910F71D5829C6006CB65E /* JPDevTipView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910CD1D5829C6006CB65E /* JPDevTipView.m */; }; 6C0910F81D5829C6006CB65E /* JPSpecialInit.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910CF1D5829C6006CB65E /* JPSpecialInit.m */; }; 6C0910F91D5829C6006CB65E /* JPEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0910D21D5829C6006CB65E /* JPEngine.m */; }; 6C0910FA1D5829C6006CB65E /* JSPatch.js in Resources */ = {isa = PBXBuildFile; fileRef = 6C0910D31D5829C6006CB65E /* JSPatch.js */; }; 6C5D37AD1D56F58600B78CD9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C5D37AC1D56F58600B78CD9 /* main.m */; }; 6C5D37B01D56F58600B78CD9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C5D37AF1D56F58600B78CD9 /* AppDelegate.m */; }; 6C5D37B61D56F58600B78CD9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6C5D37B41D56F58600B78CD9 /* Main.storyboard */; }; 6C5D37B81D56F58600B78CD9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6C5D37B71D56F58600B78CD9 /* Assets.xcassets */; }; 6C5D37BB1D56F58600B78CD9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6C5D37B91D56F58600B78CD9 /* LaunchScreen.storyboard */; }; 6C5D387B1D57237200B78CD9 /* JPRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C5D387A1D57237200B78CD9 /* JPRootViewController.m */; }; 6CC772261D575D400001B951 /* demo.js in Resources */ = {isa = PBXBuildFile; fileRef = 6CC772241D575D400001B951 /* demo.js */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 6C0910761D5829C6006CB65E /* JPCFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCFunction.h; sourceTree = ""; }; 6C0910771D5829C6006CB65E /* JPCFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCFunction.m; sourceTree = ""; }; 6C0910781D5829C6006CB65E /* JPMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPMemory.h; sourceTree = ""; }; 6C0910791D5829C6006CB65E /* JPMemory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPMemory.m; sourceTree = ""; }; 6C09107A1D5829C6006CB65E /* JPStructPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPStructPointer.h; sourceTree = ""; }; 6C09107B1D5829C6006CB65E /* JPStructPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPStructPointer.m; sourceTree = ""; }; 6C09107E1D5829C6006CB65E /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = ""; }; 6C09107F1D5829C6006CB65E /* ffi_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_arm64.h; sourceTree = ""; }; 6C0910801D5829C6006CB65E /* ffi_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_armv7.h; sourceTree = ""; }; 6C0910811D5829C6006CB65E /* ffi_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_common.h; sourceTree = ""; }; 6C0910821D5829C6006CB65E /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = ""; }; 6C0910831D5829C6006CB65E /* ffi_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_x86_64.h; sourceTree = ""; }; 6C0910841D5829C6006CB65E /* fficonfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig.h; sourceTree = ""; }; 6C0910851D5829C6006CB65E /* fficonfig_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_arm64.h; sourceTree = ""; }; 6C0910861D5829C6006CB65E /* fficonfig_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_armv7.h; sourceTree = ""; }; 6C0910871D5829C6006CB65E /* fficonfig_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_i386.h; sourceTree = ""; }; 6C0910881D5829C6006CB65E /* fficonfig_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_x86_64.h; sourceTree = ""; }; 6C0910891D5829C6006CB65E /* ffitarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget.h; sourceTree = ""; }; 6C09108A1D5829C6006CB65E /* ffitarget_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_arm64.h; sourceTree = ""; }; 6C09108B1D5829C6006CB65E /* ffitarget_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_armv7.h; sourceTree = ""; }; 6C09108C1D5829C6006CB65E /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = ""; }; 6C09108D1D5829C6006CB65E /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = ""; }; 6C0910901D5829C6006CB65E /* ffi_arm64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_arm64.c; sourceTree = ""; }; 6C0910911D5829C6006CB65E /* sysv_arm64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_arm64.S; sourceTree = ""; }; 6C0910931D5829C6006CB65E /* ffi_armv7.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_armv7.c; sourceTree = ""; }; 6C0910941D5829C6006CB65E /* sysv_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_armv7.S; sourceTree = ""; }; 6C0910951D5829C6006CB65E /* trampoline_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = trampoline_armv7.S; sourceTree = ""; }; 6C0910971D5829C6006CB65E /* prep_cif.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = prep_cif.c; sourceTree = ""; }; 6C0910981D5829C6006CB65E /* raw_api.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = raw_api.c; sourceTree = ""; }; 6C0910991D5829C6006CB65E /* types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = types.c; sourceTree = ""; }; 6C09109B1D5829C6006CB65E /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = ""; }; 6C09109C1D5829C6006CB65E /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = ""; }; 6C09109D1D5829C6006CB65E /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = ""; }; 6C09109E1D5829C6006CB65E /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = ""; }; 6C09109F1D5829C6006CB65E /* win32_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = win32_i386.S; sourceTree = ""; }; 6C0910A21D5829C6006CB65E /* JPCGBitmapContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGBitmapContext.h; sourceTree = ""; }; 6C0910A31D5829C6006CB65E /* JPCGBitmapContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGBitmapContext.m; sourceTree = ""; }; 6C0910A41D5829C6006CB65E /* JPCGColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGColor.h; sourceTree = ""; }; 6C0910A51D5829C6006CB65E /* JPCGColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGColor.m; sourceTree = ""; }; 6C0910A61D5829C6006CB65E /* JPCGContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGContext.h; sourceTree = ""; }; 6C0910A71D5829C6006CB65E /* JPCGContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGContext.m; sourceTree = ""; }; 6C0910A81D5829C6006CB65E /* JPCGGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGGeometry.h; sourceTree = ""; }; 6C0910A91D5829C6006CB65E /* JPCGGeometry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGGeometry.m; sourceTree = ""; }; 6C0910AA1D5829C6006CB65E /* JPCGImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGImage.h; sourceTree = ""; }; 6C0910AB1D5829C6006CB65E /* JPCGImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGImage.m; sourceTree = ""; }; 6C0910AC1D5829C6006CB65E /* JPCGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGPath.h; sourceTree = ""; }; 6C0910AD1D5829C6006CB65E /* JPCGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGPath.m; sourceTree = ""; }; 6C0910AE1D5829C6006CB65E /* JPCGTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGTransform.h; sourceTree = ""; }; 6C0910AF1D5829C6006CB65E /* JPCGTransform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGTransform.m; sourceTree = ""; }; 6C0910B01D5829C6006CB65E /* JPCoreGraphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCoreGraphics.h; sourceTree = ""; }; 6C0910B11D5829C6006CB65E /* JPCoreGraphics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCoreGraphics.m; sourceTree = ""; }; 6C0910B31D5829C6006CB65E /* JPUIGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIGeometry.h; sourceTree = ""; }; 6C0910B41D5829C6006CB65E /* JPUIGeometry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIGeometry.m; sourceTree = ""; }; 6C0910B51D5829C6006CB65E /* JPUIGraphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIGraphics.h; sourceTree = ""; }; 6C0910B61D5829C6006CB65E /* JPUIGraphics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIGraphics.m; sourceTree = ""; }; 6C0910B71D5829C6006CB65E /* JPUIImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIImage.h; sourceTree = ""; }; 6C0910B81D5829C6006CB65E /* JPUIImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIImage.m; sourceTree = ""; }; 6C0910B91D5829C6006CB65E /* JPUIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIKit.h; sourceTree = ""; }; 6C0910BA1D5829C6006CB65E /* JPUIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIKit.m; sourceTree = ""; }; 6C0910BB1D5829C6006CB65E /* JPCleaner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCleaner.h; sourceTree = ""; }; 6C0910BC1D5829C6006CB65E /* JPCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCleaner.m; sourceTree = ""; }; 6C0910BD1D5829C6006CB65E /* JPLocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPLocker.h; sourceTree = ""; }; 6C0910BE1D5829C6006CB65E /* JPLocker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPLocker.m; sourceTree = ""; }; 6C0910C01D5829C6006CB65E /* JPPlayground.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPPlayground.h; sourceTree = ""; }; 6C0910C11D5829C6006CB65E /* JPPlayground.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPPlayground.m; sourceTree = ""; }; 6C0910C31D5829C6006CB65E /* JPKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPKeyCommands.h; sourceTree = ""; }; 6C0910C41D5829C6006CB65E /* JPKeyCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPKeyCommands.m; sourceTree = ""; }; 6C0910C51D5829C6006CB65E /* SGDirWatchdog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGDirWatchdog.h; sourceTree = ""; }; 6C0910C61D5829C6006CB65E /* SGDirWatchdog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGDirWatchdog.m; sourceTree = ""; }; 6C0910C81D5829C6006CB65E /* JPDevErrorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPDevErrorView.h; sourceTree = ""; }; 6C0910C91D5829C6006CB65E /* JPDevErrorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPDevErrorView.m; sourceTree = ""; }; 6C0910CA1D5829C6006CB65E /* JPDevMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPDevMenu.h; sourceTree = ""; }; 6C0910CB1D5829C6006CB65E /* JPDevMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPDevMenu.m; sourceTree = ""; }; 6C0910CC1D5829C6006CB65E /* JPDevTipView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPDevTipView.h; sourceTree = ""; }; 6C0910CD1D5829C6006CB65E /* JPDevTipView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPDevTipView.m; sourceTree = ""; }; 6C0910CE1D5829C6006CB65E /* JPSpecialInit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPSpecialInit.h; sourceTree = ""; }; 6C0910CF1D5829C6006CB65E /* JPSpecialInit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPSpecialInit.m; sourceTree = ""; }; 6C0910D11D5829C6006CB65E /* JPEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPEngine.h; sourceTree = ""; }; 6C0910D21D5829C6006CB65E /* JPEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPEngine.m; sourceTree = ""; }; 6C0910D31D5829C6006CB65E /* JSPatch.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSPatch.js; sourceTree = ""; }; 6C5D37A81D56F58600B78CD9 /* JSPatchPlaygroundDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSPatchPlaygroundDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6C5D37AC1D56F58600B78CD9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 6C5D37AE1D56F58600B78CD9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 6C5D37AF1D56F58600B78CD9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 6C5D37B51D56F58600B78CD9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 6C5D37B71D56F58600B78CD9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 6C5D37BA1D56F58600B78CD9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 6C5D37BC1D56F58600B78CD9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6C5D38791D57237200B78CD9 /* JPRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPRootViewController.h; sourceTree = ""; }; 6C5D387A1D57237200B78CD9 /* JPRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPRootViewController.m; sourceTree = ""; }; 6CC772241D575D400001B951 /* demo.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = demo.js; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 6C5D37A51D56F58600B78CD9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 6C0910741D5829C6006CB65E /* Extensions */ = { isa = PBXGroup; children = ( 6C0910751D5829C6006CB65E /* JPCFunction */, 6C0910A01D5829C6006CB65E /* JPCFunctionBinder */, 6C0910BB1D5829C6006CB65E /* JPCleaner.h */, 6C0910BC1D5829C6006CB65E /* JPCleaner.m */, 6C0910BD1D5829C6006CB65E /* JPLocker.h */, 6C0910BE1D5829C6006CB65E /* JPLocker.m */, 6C0910BF1D5829C6006CB65E /* JPPlaygroundTool */, 6C0910CE1D5829C6006CB65E /* JPSpecialInit.h */, 6C0910CF1D5829C6006CB65E /* JPSpecialInit.m */, ); name = Extensions; path = ../../Extensions; sourceTree = ""; }; 6C0910751D5829C6006CB65E /* JPCFunction */ = { isa = PBXGroup; children = ( 6C0910761D5829C6006CB65E /* JPCFunction.h */, 6C0910771D5829C6006CB65E /* JPCFunction.m */, 6C0910781D5829C6006CB65E /* JPMemory.h */, 6C0910791D5829C6006CB65E /* JPMemory.m */, 6C09107A1D5829C6006CB65E /* JPStructPointer.h */, 6C09107B1D5829C6006CB65E /* JPStructPointer.m */, 6C09107C1D5829C6006CB65E /* libffi */, ); path = JPCFunction; sourceTree = ""; }; 6C09107C1D5829C6006CB65E /* libffi */ = { isa = PBXGroup; children = ( 6C09107D1D5829C6006CB65E /* headers */, 6C09108E1D5829C6006CB65E /* src */, ); path = libffi; sourceTree = ""; }; 6C09107D1D5829C6006CB65E /* headers */ = { isa = PBXGroup; children = ( 6C09107E1D5829C6006CB65E /* ffi.h */, 6C09107F1D5829C6006CB65E /* ffi_arm64.h */, 6C0910801D5829C6006CB65E /* ffi_armv7.h */, 6C0910811D5829C6006CB65E /* ffi_common.h */, 6C0910821D5829C6006CB65E /* ffi_i386.h */, 6C0910831D5829C6006CB65E /* ffi_x86_64.h */, 6C0910841D5829C6006CB65E /* fficonfig.h */, 6C0910851D5829C6006CB65E /* fficonfig_arm64.h */, 6C0910861D5829C6006CB65E /* fficonfig_armv7.h */, 6C0910871D5829C6006CB65E /* fficonfig_i386.h */, 6C0910881D5829C6006CB65E /* fficonfig_x86_64.h */, 6C0910891D5829C6006CB65E /* ffitarget.h */, 6C09108A1D5829C6006CB65E /* ffitarget_arm64.h */, 6C09108B1D5829C6006CB65E /* ffitarget_armv7.h */, 6C09108C1D5829C6006CB65E /* ffitarget_i386.h */, 6C09108D1D5829C6006CB65E /* ffitarget_x86_64.h */, ); path = headers; sourceTree = ""; }; 6C09108E1D5829C6006CB65E /* src */ = { isa = PBXGroup; children = ( 6C09108F1D5829C6006CB65E /* aarch64 */, 6C0910921D5829C6006CB65E /* arm */, 6C0910961D5829C6006CB65E /* common */, 6C09109A1D5829C6006CB65E /* x86 */, ); path = src; sourceTree = ""; }; 6C09108F1D5829C6006CB65E /* aarch64 */ = { isa = PBXGroup; children = ( 6C0910901D5829C6006CB65E /* ffi_arm64.c */, 6C0910911D5829C6006CB65E /* sysv_arm64.S */, ); path = aarch64; sourceTree = ""; }; 6C0910921D5829C6006CB65E /* arm */ = { isa = PBXGroup; children = ( 6C0910931D5829C6006CB65E /* ffi_armv7.c */, 6C0910941D5829C6006CB65E /* sysv_armv7.S */, 6C0910951D5829C6006CB65E /* trampoline_armv7.S */, ); path = arm; sourceTree = ""; }; 6C0910961D5829C6006CB65E /* common */ = { isa = PBXGroup; children = ( 6C0910971D5829C6006CB65E /* prep_cif.c */, 6C0910981D5829C6006CB65E /* raw_api.c */, 6C0910991D5829C6006CB65E /* types.c */, ); path = common; sourceTree = ""; }; 6C09109A1D5829C6006CB65E /* x86 */ = { isa = PBXGroup; children = ( 6C09109B1D5829C6006CB65E /* darwin64_x86_64.S */, 6C09109C1D5829C6006CB65E /* darwin_i386.S */, 6C09109D1D5829C6006CB65E /* ffi64_x86_64.c */, 6C09109E1D5829C6006CB65E /* ffi_i386.c */, 6C09109F1D5829C6006CB65E /* win32_i386.S */, ); path = x86; sourceTree = ""; }; 6C0910A01D5829C6006CB65E /* JPCFunctionBinder */ = { isa = PBXGroup; children = ( 6C0910A11D5829C6006CB65E /* CoreGraphics */, 6C0910B21D5829C6006CB65E /* UIKit */, ); path = JPCFunctionBinder; sourceTree = ""; }; 6C0910A11D5829C6006CB65E /* CoreGraphics */ = { isa = PBXGroup; children = ( 6C0910A21D5829C6006CB65E /* JPCGBitmapContext.h */, 6C0910A31D5829C6006CB65E /* JPCGBitmapContext.m */, 6C0910A41D5829C6006CB65E /* JPCGColor.h */, 6C0910A51D5829C6006CB65E /* JPCGColor.m */, 6C0910A61D5829C6006CB65E /* JPCGContext.h */, 6C0910A71D5829C6006CB65E /* JPCGContext.m */, 6C0910A81D5829C6006CB65E /* JPCGGeometry.h */, 6C0910A91D5829C6006CB65E /* JPCGGeometry.m */, 6C0910AA1D5829C6006CB65E /* JPCGImage.h */, 6C0910AB1D5829C6006CB65E /* JPCGImage.m */, 6C0910AC1D5829C6006CB65E /* JPCGPath.h */, 6C0910AD1D5829C6006CB65E /* JPCGPath.m */, 6C0910AE1D5829C6006CB65E /* JPCGTransform.h */, 6C0910AF1D5829C6006CB65E /* JPCGTransform.m */, 6C0910B01D5829C6006CB65E /* JPCoreGraphics.h */, 6C0910B11D5829C6006CB65E /* JPCoreGraphics.m */, ); path = CoreGraphics; sourceTree = ""; }; 6C0910B21D5829C6006CB65E /* UIKit */ = { isa = PBXGroup; children = ( 6C0910B31D5829C6006CB65E /* JPUIGeometry.h */, 6C0910B41D5829C6006CB65E /* JPUIGeometry.m */, 6C0910B51D5829C6006CB65E /* JPUIGraphics.h */, 6C0910B61D5829C6006CB65E /* JPUIGraphics.m */, 6C0910B71D5829C6006CB65E /* JPUIImage.h */, 6C0910B81D5829C6006CB65E /* JPUIImage.m */, 6C0910B91D5829C6006CB65E /* JPUIKit.h */, 6C0910BA1D5829C6006CB65E /* JPUIKit.m */, ); path = UIKit; sourceTree = ""; }; 6C0910BF1D5829C6006CB65E /* JPPlaygroundTool */ = { isa = PBXGroup; children = ( 6C0910C01D5829C6006CB65E /* JPPlayground.h */, 6C0910C11D5829C6006CB65E /* JPPlayground.m */, 6C0910C21D5829C6006CB65E /* JPPlaygroundModule */, 6C0910C71D5829C6006CB65E /* JPPlaygroundView */, ); path = JPPlaygroundTool; sourceTree = ""; }; 6C0910C21D5829C6006CB65E /* JPPlaygroundModule */ = { isa = PBXGroup; children = ( 6C0910C31D5829C6006CB65E /* JPKeyCommands.h */, 6C0910C41D5829C6006CB65E /* JPKeyCommands.m */, 6C0910C51D5829C6006CB65E /* SGDirWatchdog.h */, 6C0910C61D5829C6006CB65E /* SGDirWatchdog.m */, ); path = JPPlaygroundModule; sourceTree = ""; }; 6C0910C71D5829C6006CB65E /* JPPlaygroundView */ = { isa = PBXGroup; children = ( 6C0910C81D5829C6006CB65E /* JPDevErrorView.h */, 6C0910C91D5829C6006CB65E /* JPDevErrorView.m */, 6C0910CA1D5829C6006CB65E /* JPDevMenu.h */, 6C0910CB1D5829C6006CB65E /* JPDevMenu.m */, 6C0910CC1D5829C6006CB65E /* JPDevTipView.h */, 6C0910CD1D5829C6006CB65E /* JPDevTipView.m */, ); path = JPPlaygroundView; sourceTree = ""; }; 6C0910D01D5829C6006CB65E /* JSPatch */ = { isa = PBXGroup; children = ( 6C0910D11D5829C6006CB65E /* JPEngine.h */, 6C0910D21D5829C6006CB65E /* JPEngine.m */, 6C0910D31D5829C6006CB65E /* JSPatch.js */, ); name = JSPatch; path = ../../JSPatch; sourceTree = ""; }; 6C5D379F1D56F58600B78CD9 = { isa = PBXGroup; children = ( 6C0910741D5829C6006CB65E /* Extensions */, 6C0910D01D5829C6006CB65E /* JSPatch */, 6CC772231D575D400001B951 /* js */, 6C5D37AA1D56F58600B78CD9 /* JSPatchPlaygroundDemo */, 6C5D37A91D56F58600B78CD9 /* Products */, ); sourceTree = ""; }; 6C5D37A91D56F58600B78CD9 /* Products */ = { isa = PBXGroup; children = ( 6C5D37A81D56F58600B78CD9 /* JSPatchPlaygroundDemo.app */, ); name = Products; sourceTree = ""; }; 6C5D37AA1D56F58600B78CD9 /* JSPatchPlaygroundDemo */ = { isa = PBXGroup; children = ( 6C5D38791D57237200B78CD9 /* JPRootViewController.h */, 6C5D387A1D57237200B78CD9 /* JPRootViewController.m */, 6C5D37AE1D56F58600B78CD9 /* AppDelegate.h */, 6C5D37AF1D56F58600B78CD9 /* AppDelegate.m */, 6C5D37B41D56F58600B78CD9 /* Main.storyboard */, 6C5D37B71D56F58600B78CD9 /* Assets.xcassets */, 6C5D37B91D56F58600B78CD9 /* LaunchScreen.storyboard */, 6C5D37BC1D56F58600B78CD9 /* Info.plist */, 6C5D37AB1D56F58600B78CD9 /* Supporting Files */, ); path = JSPatchPlaygroundDemo; sourceTree = ""; }; 6C5D37AB1D56F58600B78CD9 /* Supporting Files */ = { isa = PBXGroup; children = ( 6C5D37AC1D56F58600B78CD9 /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; 6CC772231D575D400001B951 /* js */ = { isa = PBXGroup; children = ( 6CC772241D575D400001B951 /* demo.js */, ); name = js; path = JSPatchPlaygroundDemo/js; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 6C5D37A71D56F58600B78CD9 /* JSPatchPlaygroundDemo */ = { isa = PBXNativeTarget; buildConfigurationList = 6C5D37BF1D56F58600B78CD9 /* Build configuration list for PBXNativeTarget "JSPatchPlaygroundDemo" */; buildPhases = ( 6C5D37A41D56F58600B78CD9 /* Sources */, 6C5D37A51D56F58600B78CD9 /* Frameworks */, 6C5D37A61D56F58600B78CD9 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = JSPatchPlaygroundDemo; productName = JSPatchPlaygroundDemo; productReference = 6C5D37A81D56F58600B78CD9 /* JSPatchPlaygroundDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 6C5D37A01D56F58600B78CD9 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0720; ORGANIZATIONNAME = baidu; TargetAttributes = { 6C5D37A71D56F58600B78CD9 = { CreatedOnToolsVersion = 7.2.1; }; }; }; buildConfigurationList = 6C5D37A31D56F58600B78CD9 /* Build configuration list for PBXProject "JSPatchPlaygroundDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 6C5D379F1D56F58600B78CD9; productRefGroup = 6C5D37A91D56F58600B78CD9 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 6C5D37A71D56F58600B78CD9 /* JSPatchPlaygroundDemo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 6C5D37A61D56F58600B78CD9 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 6C0910FA1D5829C6006CB65E /* JSPatch.js in Resources */, 6CC772261D575D400001B951 /* demo.js in Resources */, 6C5D37BB1D56F58600B78CD9 /* LaunchScreen.storyboard in Resources */, 6C5D37B81D56F58600B78CD9 /* Assets.xcassets in Resources */, 6C5D37B61D56F58600B78CD9 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 6C5D37A41D56F58600B78CD9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 6C0910F41D5829C6006CB65E /* SGDirWatchdog.m in Sources */, 6C0910D51D5829C6006CB65E /* JPMemory.m in Sources */, 6C0910DE1D5829C6006CB65E /* types.c in Sources */, 6C5D37B01D56F58600B78CD9 /* AppDelegate.m in Sources */, 6C0910D61D5829C6006CB65E /* JPStructPointer.m in Sources */, 6C0910E41D5829C6006CB65E /* JPCGBitmapContext.m in Sources */, 6C0910E81D5829C6006CB65E /* JPCGImage.m in Sources */, 6C0910E91D5829C6006CB65E /* JPCGPath.m in Sources */, 6C0910D81D5829C6006CB65E /* sysv_arm64.S in Sources */, 6C0910DA1D5829C6006CB65E /* sysv_armv7.S in Sources */, 6C0910F51D5829C6006CB65E /* JPDevErrorView.m in Sources */, 6C0910DF1D5829C6006CB65E /* darwin64_x86_64.S in Sources */, 6C0910F11D5829C6006CB65E /* JPLocker.m in Sources */, 6C5D37AD1D56F58600B78CD9 /* main.m in Sources */, 6C0910DD1D5829C6006CB65E /* raw_api.c in Sources */, 6C0910EF1D5829C6006CB65E /* JPUIKit.m in Sources */, 6C5D387B1D57237200B78CD9 /* JPRootViewController.m in Sources */, 6C0910EE1D5829C6006CB65E /* JPUIImage.m in Sources */, 6C0910E11D5829C6006CB65E /* ffi64_x86_64.c in Sources */, 6C0910D71D5829C6006CB65E /* ffi_arm64.c in Sources */, 6C0910D91D5829C6006CB65E /* ffi_armv7.c in Sources */, 6C0910E01D5829C6006CB65E /* darwin_i386.S in Sources */, 6C0910D41D5829C6006CB65E /* JPCFunction.m in Sources */, 6C0910DB1D5829C6006CB65E /* trampoline_armv7.S in Sources */, 6C0910F61D5829C6006CB65E /* JPDevMenu.m in Sources */, 6C0910E51D5829C6006CB65E /* JPCGColor.m in Sources */, 6C0910DC1D5829C6006CB65E /* prep_cif.c in Sources */, 6C0910EB1D5829C6006CB65E /* JPCoreGraphics.m in Sources */, 6C0910E61D5829C6006CB65E /* JPCGContext.m in Sources */, 6C0910E31D5829C6006CB65E /* win32_i386.S in Sources */, 6C0910F91D5829C6006CB65E /* JPEngine.m in Sources */, 6C0910F01D5829C6006CB65E /* JPCleaner.m in Sources */, 6C0910ED1D5829C6006CB65E /* JPUIGraphics.m in Sources */, 6C0910E21D5829C6006CB65E /* ffi_i386.c in Sources */, 6C0910F81D5829C6006CB65E /* JPSpecialInit.m in Sources */, 6C0910F21D5829C6006CB65E /* JPPlayground.m in Sources */, 6C0910F71D5829C6006CB65E /* JPDevTipView.m in Sources */, 6C0910EC1D5829C6006CB65E /* JPUIGeometry.m in Sources */, 6C0910EA1D5829C6006CB65E /* JPCGTransform.m in Sources */, 6C0910E71D5829C6006CB65E /* JPCGGeometry.m in Sources */, 6C0910F31D5829C6006CB65E /* JPKeyCommands.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 6C5D37B41D56F58600B78CD9 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 6C5D37B51D56F58600B78CD9 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 6C5D37B91D56F58600B78CD9 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 6C5D37BA1D56F58600B78CD9 /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 6C5D37BD1D56F58600B78CD9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 6C5D37BE1D56F58600B78CD9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 6C5D37C01D56F58600B78CD9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = JSPatchPlaygroundDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.baidu.JSPatchPlaygroundDemo; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 6C5D37C11D56F58600B78CD9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = JSPatchPlaygroundDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.baidu.JSPatchPlaygroundDemo; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 6C5D37A31D56F58600B78CD9 /* Build configuration list for PBXProject "JSPatchPlaygroundDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( 6C5D37BD1D56F58600B78CD9 /* Debug */, 6C5D37BE1D56F58600B78CD9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 6C5D37BF1D56F58600B78CD9 /* Build configuration list for PBXNativeTarget "JSPatchPlaygroundDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( 6C5D37C01D56F58600B78CD9 /* Debug */, 6C5D37C11D56F58600B78CD9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 6C5D37A01D56F58600B78CD9 /* Project object */; } ================================================ FILE: Demo/iOSPlaygroundToolDemo/JSPatchPlaygroundDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/iOSPlaygroundToolDemo/README.md ================================================ # JSPatchPlaygroundTool JSPatch天然能实现playground黑科技一样的效果,什么样的黑科技呢?我们改的每一行代码,每一个语句,完全无需重新运行app,直接能立刻看到效果。 并且bang哥已经给出了如何操作和说明 # JSPatch Playground [JSPatch Playground Github](https://github.com/bang590/JSPatch/tree/master/Demo/iOSPlayground) ![Screenshot](https://raw.github.com/bang590/JSPatch/master/Demo/iOSPlayground/Screenshot.gif) ## 介绍 JSPatch Playground 可以让你快速看到 JSPatch 代码执行效果,APP在模拟器运行后,每次修改脚本保存模拟器都会自动刷新,无需重启模拟器,即时看到效果。 你也可以仿照 JSPatch Playground 在你的项目里添加 JSPatch 脚本即时刷新功能,帮助你快速使用 JSPatch 开发功能模块。 Tips: 如果运行过程中脚本执行错误,会在状态栏里显示错误原因,点击状态栏可以看到更详细的错误提示。 # JSPatchPlaygroundTool bang哥的Playground工程下面,可以看到想要配置这样一个如此酷炫的黑科技,[JSPatch Playground Github](https://github.com/bang590/JSPatch/tree/master/Demo/iOSPlayground) 项目下的`JPRootViewController.m`文件里面的代码还是挺多的 由于前些日子搞了一阵子ReactNative,发现ReactNative下面的Debug,Reload工具很是方便,心想也给JSPatch弄一套,于是就有了这个`JSPatchPlaygroundTool` 初衷是,把一整套playground的思路以及环境代码配置,封装成工具,以简洁的API就能轻松运行。 ## JSPatchPlaygroundTool的使用 这段代码分成两部分,上半部分就是配置`JSPatchPlaygroundTool`,让JSPatch以Playground的模式进行工作。下半部分则是正常代码,正常的按既有方案加载JSPatch ```objectivec #if TARGET_IPHONE_SIMULATOR //playground调试 //JS测试包的本地绝对路径 NSString *rootPath = @"/Users/Awhisper/Desktop/Github/JSPatchPlaygroundTool/JSPatchPlaygroundDemo/JSPatchPlaygroundDemo"; NSString *scriptRootPath = [rootPath stringByAppendingPathComponent:@"js"]; NSString *mainScriptPath = [NSString stringWithFormat:@"%@/%@", scriptRootPath, @"demo.js"]; [JPPlayground setReloadCompleteHandler:^{ [self showController]; }]; [JPPlayground startPlaygroundWithJSPath:mainScriptPath]; #else //正常执行JSPatch //JS测试包的本地绝对路径 NSString *rootPath = [[NSBundle mainBundle] bundlePath]; NSString *scriptPath = [rootPath stringByAppendingPathComponent:@"demo.js"]; NSString *script = [NSString stringWithContentsOfFile:scriptPath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; #endif ``` 这里只讲解上半部分的API,`rootPath`此处切记输入Mac电脑的mainJS文件所在的路径,我的目录里在工程文件`JSPatchPlaygroundDemo`下专门放了个名字为JS的文件夹,里面放着核心的JS代码逻辑,所以我又补充了`\js\demo.js`作为后缀 - [JPPlayground setReloadCompleteHandler:block] 这个API的意义在于,每次重新刷新JS后,如果有一些额外的想要操作的东西就可以在此时执行,如果没有,这个API完全可以不使用 - [JPPlayground startPlaygroundWithJSPath:path] 这个API是核心API,输入mainJS的路径后,整个JSPatch将会以playground的模式进行运行 ## JSPatchPlaygroundTool的效果 __command + X__:可以打开操作菜单 ![menu](http://ww2.sinaimg.cn/mw690/678c3e91jw1f6lkzh8zwdj208n0fyaam.jpg) __command + R__:可以ReloadJS 当APP在保持运行的时候,我们可以任意修改main.js文件然后进行保存,然后按command+R的组合键,就可以立刻刷新 __JS Error__:当JS文件有错误,app并不会崩溃,保持持续运行,并且弹出红色界面,详细描述错误信息,当把js文件修改正确后,重新reload,自然就会顺利运行。 ![error](http://ww2.sinaimg.cn/mw690/678c3e91jw1f6lkzglfruj208n0fyq3t.jpg) __AutoReload JS__:Tool可以开启监听JS文件的变化,当你把menu中的这个开关打开,每一次修改js文件进行保存,都会自动触发reload。再次点击这个按钮,会关闭监听,(AutoReload默认不开启) __Todo List__:我还想尝试在菜单里面多做2个功能,但并未能找到办法 - 自动打开Finder,打开JS文件所在的目录,从而能快速找到要修改的JS文件,轻轻松松的开始畅快的JS代码之旅,从此告别编译,运行,重启app的烦躁过程 - 自动打开Safari的开发者模式,打开正在run的JSContext,从而能对js代码进行断点调试,就好像ReactNative能自动打开chrome一样 我没有找到很好的办法,能在iOS框架里面,在模拟器里面,打开Mac上的Mac app,太多的方法都是OSX开发才能使用的库,比如`NSWorkSpace`,这玩意没法在iOS项目里用。发愁 ## JSPatchPlaygroundTool的目标 当使用JSPatch进行一整个功能模块的开发,而不仅仅是只用来修改bug,能像ReactNative一样,run起app后,告别反锁的编译,运行,写出来的代码立刻就生效,代码出错也立刻报出来,丝毫不影响运行,重新修改好后,自然完美运作。 # JSPatchPlayground的原理 之前提到过JSPatch是天然支持这种playground的黑科技玩法的~ 原因就在于JSPatch的一个Extension`JPCleaner`,他可以让所有被JSPatch的hook的函数都恢复原样,这样将修改过最新的JS,重新执行以下,就实现了Reload的效果 ================================================ FILE: Demo/tvOSDemo/JSPatchDemo/AppDelegate.h ================================================ // // AppDelegate.h // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015年 bang. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Demo/tvOSDemo/JSPatchDemo/AppDelegate.m ================================================ // // AppDelegate.m // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015年 bang. All rights reserved. // #import "AppDelegate.h" #import "JPEngine.h" #import "JPViewController.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [JPEngine startEngine]; NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"]; NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; JPViewController *rootViewController = [[JPViewController alloc] init]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController]; self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; [[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsCompact]; return YES; } @end ================================================ FILE: Demo/tvOSDemo/JSPatchDemo/JPViewController.h ================================================ // // JPViewController.h // JSPatch // // Created by bang on 15/5/2. // Copyright (c) 2015年 bang. All rights reserved. // #import @interface JPViewController : UIViewController @end ================================================ FILE: Demo/tvOSDemo/JSPatchDemo/JPViewController.m ================================================ // // JPViewController.m // JSPatch // // Created by bang on 15/5/2. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPViewController.h" @implementation JPViewController - (void)viewDidLoad { [super viewDidLoad]; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, 50)]; [btn setTitle:@"Push JPTableViewController" forState:UIControlStateNormal]; [btn addTarget:self action:@selector(handleBtn:) forControlEvents:UIControlEventPrimaryActionTriggered]; [btn setBackgroundColor:[UIColor grayColor]]; [self.view addSubview:btn]; } - (void)handleBtn:(id)sender { } @end ================================================ FILE: Demo/tvOSDemo/JSPatchDemo/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/tvOSDemo/JSPatchDemo/Supporting Files/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier net.cnbang.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Demo/tvOSDemo/JSPatchDemo/Supporting Files/main.m ================================================ // // main.m // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015年 bang. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Demo/tvOSDemo/JSPatchDemo/demo.js ================================================ defineClass('JPViewController', { handleBtn: function(sender) { var tableViewCtrl = JPTableViewController.alloc().init() self.navigationController().pushViewController_animated(tableViewCtrl, YES) } }) defineClass('JPTableViewController : UITableViewController ', ['data'], { dataSource: function() { var data = self.data(); if (data) return data; var data = []; for (var i = 0; i < 20; i ++) { data.push("cell from js " + i); } self.setData(data) return data; }, numberOfSectionsInTableView: function(tableView) { return 1; }, tableView_numberOfRowsInSection: function(tableView, section) { return self.dataSource().length; }, tableView_cellForRowAtIndexPath: function(tableView, indexPath) { var cell = tableView.dequeueReusableCellWithIdentifier("cell") if (!cell) { cell = require('UITableViewCell').alloc().initWithStyle_reuseIdentifier(0, "cell") } cell.textLabel().setText(self.dataSource()[indexPath.row()]) return cell }, tableView_heightForRowAtIndexPath: function(tableView, indexPath) { return 60 }, tableView_didSelectRowAtIndexPath: function(tableView, indexPath) { var alertController = require('UIAlertController').alertControllerWithTitle_message_preferredStyle("Alert", self.dataSource()[indexPath.row()], 1); alertController.addAction(require('UIAlertAction').actionWithTitle_style_handler("OK", 0, null)); self.presentViewController_animated_completion(alertController, YES, null); }, alertView_willDismissWithButtonIndex: function(alertView, idx) { console.log('click btn ' + alertView.buttonTitleAtIndex(idx).toJS()) } }) ================================================ FILE: Demo/tvOSDemo/JSPatchDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 40D88CF81CCB7D2A00A8837D /* JPUIGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3581C6329F300E915CB /* JPUIGeometry.m */; }; 40D88CF91CCB7D2A00A8837D /* JPUIGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C35A1C6329F300E915CB /* JPUIGraphics.m */; }; 40D88CFA1CCB7D2A00A8837D /* JPUIImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C35C1C6329F300E915CB /* JPUIImage.m */; }; 40D88CFB1CCB7D2A00A8837D /* JPUIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C35E1C6329F300E915CB /* JPUIKit.m */; }; 40D88CFC1CCB7D2A00A8837D /* JPCGBitmapContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3411C6329F300E915CB /* JPCGBitmapContext.m */; }; 40D88CFD1CCB7D2A00A8837D /* JPCGColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3431C6329F300E915CB /* JPCGColor.m */; }; 40D88CFE1CCB7D2A00A8837D /* JPCGContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3451C6329F300E915CB /* JPCGContext.m */; }; 40D88CFF1CCB7D2A00A8837D /* JPCGGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3471C6329F300E915CB /* JPCGGeometry.m */; }; 40D88D001CCB7D2A00A8837D /* JPCGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3491C6329F300E915CB /* JPCGImage.m */; }; 40D88D011CCB7D2A00A8837D /* JPCGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C34B1C6329F300E915CB /* JPCGPath.m */; }; 40D88D021CCB7D2A00A8837D /* JPCGTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C34D1C6329F300E915CB /* JPCGTransform.m */; }; 40D88D031CCB7D2A00A8837D /* JPCoreGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C34F1C6329F300E915CB /* JPCoreGraphics.m */; }; 40D88D041CCB7D2A00A8837D /* JPMemory.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3531C6329F300E915CB /* JPMemory.m */; }; 40D88D051CCB7D2A00A8837D /* JPStructPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3551C6329F300E915CB /* JPStructPointer.m */; }; 40D88D061CCB7D2A00A8837D /* JPSpecialInit.m in Sources */ = {isa = PBXBuildFile; fileRef = 369EC2961C9925A400334A64 /* JPSpecialInit.m */; }; 40D88D071CCB7D2A00A8837D /* JPCleaner.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3AE1C6346F500E915CB /* JPCleaner.m */; }; 40D88D081CCB7D2A00A8837D /* JPLocker.m in Sources */ = {isa = PBXBuildFile; fileRef = 3646F8B31CA0F89C00E10774 /* JPLocker.m */; }; 40D88D091CCB7D2A00A8837D /* JPEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3611C6329F300E915CB /* JPEngine.m */; }; 40D88D0A1CCB7D2A00A8837D /* JPLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3651C6329F300E915CB /* JPLoader.m */; }; 40D88D0B1CCB7D2A00A8837D /* RSA.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3721C6329F300E915CB /* RSA.m */; }; 40D88D0C1CCB7D2A00A8837D /* ZipArchive.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3741C6329F300E915CB /* ZipArchive.m */; }; 40D88D0D1CCB7D2A00A8837D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D6D12FC1B0B8CF20095A435 /* main.m */; }; 40D88D0E1CCB7D2A00A8837D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D5D89181B0B8BFF009382EC /* AppDelegate.m */; }; 40D88D0F1CCB7D2A00A8837D /* JPViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D5D891E1B0B8BFF009382EC /* JPViewController.m */; }; 40D88D161CCB7EBE00A8837D /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 40D88D151CCB7EBE00A8837D /* libz.tbd */; }; 40D88D181CCB800200A8837D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40D88D171CCB800200A8837D /* Foundation.framework */; }; 40D88D191CCB802A00A8837D /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3691C6329F300E915CB /* ioapi.c */; }; 40D88D1A1CCB802A00A8837D /* mztools.c in Sources */ = {isa = PBXBuildFile; fileRef = 3613C36B1C6329F300E915CB /* mztools.c */; }; 40D88D1B1CCB802A00A8837D /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 3613C36D1C6329F300E915CB /* unzip.c */; }; 40D88D1C1CCB802A00A8837D /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 3613C36F1C6329F300E915CB /* zip.c */; }; 40D88D1D1CCBB00400A8837D /* JSPatch.js in Resources */ = {isa = PBXBuildFile; fileRef = 3613C3621C6329F300E915CB /* JSPatch.js */; }; 40D88D1E1CCBB00400A8837D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2D6D12FA1B0B8CF20095A435 /* Images.xcassets */; }; 40D88D1F1CCBB00400A8837D /* demo.js in Resources */ = {isa = PBXBuildFile; fileRef = 2D6D13001B0B8CFF0095A435 /* demo.js */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 2D5D89171B0B8BFF009382EC /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 2D5D89181B0B8BFF009382EC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 2D5D891D1B0B8BFF009382EC /* JPViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPViewController.h; sourceTree = ""; }; 2D5D891E1B0B8BFF009382EC /* JPViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPViewController.m; sourceTree = ""; }; 2D6D12FA1B0B8CF20095A435 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 2D6D12FB1B0B8CF20095A435 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2D6D12FC1B0B8CF20095A435 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2D6D13001B0B8CFF0095A435 /* demo.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = demo.js; sourceTree = ""; }; 3613C3401C6329F300E915CB /* JPCGBitmapContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGBitmapContext.h; sourceTree = ""; }; 3613C3411C6329F300E915CB /* JPCGBitmapContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGBitmapContext.m; sourceTree = ""; }; 3613C3421C6329F300E915CB /* JPCGColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGColor.h; sourceTree = ""; }; 3613C3431C6329F300E915CB /* JPCGColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGColor.m; sourceTree = ""; }; 3613C3441C6329F300E915CB /* JPCGContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGContext.h; sourceTree = ""; }; 3613C3451C6329F300E915CB /* JPCGContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGContext.m; sourceTree = ""; }; 3613C3461C6329F300E915CB /* JPCGGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGGeometry.h; sourceTree = ""; }; 3613C3471C6329F300E915CB /* JPCGGeometry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGGeometry.m; sourceTree = ""; }; 3613C3481C6329F300E915CB /* JPCGImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGImage.h; sourceTree = ""; }; 3613C3491C6329F300E915CB /* JPCGImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGImage.m; sourceTree = ""; }; 3613C34A1C6329F300E915CB /* JPCGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGPath.h; sourceTree = ""; }; 3613C34B1C6329F300E915CB /* JPCGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGPath.m; sourceTree = ""; }; 3613C34C1C6329F300E915CB /* JPCGTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCGTransform.h; sourceTree = ""; }; 3613C34D1C6329F300E915CB /* JPCGTransform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCGTransform.m; sourceTree = ""; }; 3613C34E1C6329F300E915CB /* JPCoreGraphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCoreGraphics.h; sourceTree = ""; }; 3613C34F1C6329F300E915CB /* JPCoreGraphics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCoreGraphics.m; sourceTree = ""; }; 3613C3521C6329F300E915CB /* JPMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPMemory.h; sourceTree = ""; }; 3613C3531C6329F300E915CB /* JPMemory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPMemory.m; sourceTree = ""; }; 3613C3541C6329F300E915CB /* JPStructPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPStructPointer.h; sourceTree = ""; }; 3613C3551C6329F300E915CB /* JPStructPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPStructPointer.m; sourceTree = ""; }; 3613C3571C6329F300E915CB /* JPUIGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIGeometry.h; sourceTree = ""; }; 3613C3581C6329F300E915CB /* JPUIGeometry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIGeometry.m; sourceTree = ""; }; 3613C3591C6329F300E915CB /* JPUIGraphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIGraphics.h; sourceTree = ""; }; 3613C35A1C6329F300E915CB /* JPUIGraphics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIGraphics.m; sourceTree = ""; }; 3613C35B1C6329F300E915CB /* JPUIImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIImage.h; sourceTree = ""; }; 3613C35C1C6329F300E915CB /* JPUIImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIImage.m; sourceTree = ""; }; 3613C35D1C6329F300E915CB /* JPUIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPUIKit.h; sourceTree = ""; }; 3613C35E1C6329F300E915CB /* JPUIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPUIKit.m; sourceTree = ""; }; 3613C3601C6329F300E915CB /* JPEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPEngine.h; sourceTree = ""; }; 3613C3611C6329F300E915CB /* JPEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPEngine.m; sourceTree = ""; }; 3613C3621C6329F300E915CB /* JSPatch.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSPatch.js; sourceTree = ""; }; 3613C3641C6329F300E915CB /* JPLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPLoader.h; sourceTree = ""; }; 3613C3651C6329F300E915CB /* JPLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPLoader.m; sourceTree = ""; }; 3613C3681C6329F300E915CB /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = ""; }; 3613C3691C6329F300E915CB /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = ""; }; 3613C36A1C6329F300E915CB /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = ""; }; 3613C36B1C6329F300E915CB /* mztools.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mztools.c; sourceTree = ""; }; 3613C36C1C6329F300E915CB /* mztools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mztools.h; sourceTree = ""; }; 3613C36D1C6329F300E915CB /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = ""; }; 3613C36E1C6329F300E915CB /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = ""; }; 3613C36F1C6329F300E915CB /* zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip.c; sourceTree = ""; }; 3613C3701C6329F300E915CB /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; 3613C3711C6329F300E915CB /* RSA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSA.h; sourceTree = ""; }; 3613C3721C6329F300E915CB /* RSA.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSA.m; sourceTree = ""; }; 3613C3731C6329F300E915CB /* ZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZipArchive.h; sourceTree = ""; }; 3613C3741C6329F300E915CB /* ZipArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZipArchive.m; sourceTree = ""; }; 3613C3761C6329F300E915CB /* packer.php */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.php; path = packer.php; sourceTree = ""; }; 3613C3AD1C6346F500E915CB /* JPCleaner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPCleaner.h; sourceTree = ""; }; 3613C3AE1C6346F500E915CB /* JPCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPCleaner.m; sourceTree = ""; }; 3646F8B21CA0F89C00E10774 /* JPLocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPLocker.h; sourceTree = ""; }; 3646F8B31CA0F89C00E10774 /* JPLocker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPLocker.m; sourceTree = ""; }; 369EC2951C9925A400334A64 /* JPSpecialInit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPSpecialInit.h; sourceTree = ""; }; 369EC2961C9925A400334A64 /* JPSpecialInit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPSpecialInit.m; sourceTree = ""; }; 40D88CE41CCB7D0100A8837D /* JSPatchDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSPatchDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40D88D101CCB7DB800A8837D /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.2.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; 40D88D121CCB7DBF00A8837D /* libz.1.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.1.tbd; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.2.sdk/usr/lib/libz.1.tbd; sourceTree = DEVELOPER_DIR; }; 40D88D151CCB7EBE00A8837D /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.2.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; 40D88D171CCB800200A8837D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.2.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 40D88CE11CCB7D0100A8837D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40D88D181CCB800200A8837D /* Foundation.framework in Frameworks */, 40D88D161CCB7EBE00A8837D /* libz.tbd in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 2D5D89161B0B8BFF009382EC /* JSPatchDemo */ = { isa = PBXGroup; children = ( 3613C33E1C6329F300E915CB /* Extensions */, 3613C35F1C6329F300E915CB /* JSPatch */, 3613C3631C6329F300E915CB /* Loader */, 2D6D12F91B0B8CF20095A435 /* Supporting Files */, 2D5D89171B0B8BFF009382EC /* AppDelegate.h */, 2D5D89181B0B8BFF009382EC /* AppDelegate.m */, 2D5D891D1B0B8BFF009382EC /* JPViewController.h */, 2D5D891E1B0B8BFF009382EC /* JPViewController.m */, 2D6D13001B0B8CFF0095A435 /* demo.js */, ); path = JSPatchDemo; sourceTree = ""; }; 2D6D12F91B0B8CF20095A435 /* Supporting Files */ = { isa = PBXGroup; children = ( 2D6D12FA1B0B8CF20095A435 /* Images.xcassets */, 2D6D12FB1B0B8CF20095A435 /* Info.plist */, 2D6D12FC1B0B8CF20095A435 /* main.m */, ); path = "Supporting Files"; sourceTree = ""; }; 3613C33E1C6329F300E915CB /* Extensions */ = { isa = PBXGroup; children = ( 3613C3561C6329F300E915CB /* UIKit */, 3613C33F1C6329F300E915CB /* CoreGraphics */, 3613C3521C6329F300E915CB /* JPMemory.h */, 3613C3531C6329F300E915CB /* JPMemory.m */, 3613C3541C6329F300E915CB /* JPStructPointer.h */, 3613C3551C6329F300E915CB /* JPStructPointer.m */, 369EC2951C9925A400334A64 /* JPSpecialInit.h */, 369EC2961C9925A400334A64 /* JPSpecialInit.m */, 3613C3AD1C6346F500E915CB /* JPCleaner.h */, 3613C3AE1C6346F500E915CB /* JPCleaner.m */, 3646F8B21CA0F89C00E10774 /* JPLocker.h */, 3646F8B31CA0F89C00E10774 /* JPLocker.m */, ); name = Extensions; path = ../../../Extensions; sourceTree = ""; }; 3613C33F1C6329F300E915CB /* CoreGraphics */ = { isa = PBXGroup; children = ( 3613C3401C6329F300E915CB /* JPCGBitmapContext.h */, 3613C3411C6329F300E915CB /* JPCGBitmapContext.m */, 3613C3421C6329F300E915CB /* JPCGColor.h */, 3613C3431C6329F300E915CB /* JPCGColor.m */, 3613C3441C6329F300E915CB /* JPCGContext.h */, 3613C3451C6329F300E915CB /* JPCGContext.m */, 3613C3461C6329F300E915CB /* JPCGGeometry.h */, 3613C3471C6329F300E915CB /* JPCGGeometry.m */, 3613C3481C6329F300E915CB /* JPCGImage.h */, 3613C3491C6329F300E915CB /* JPCGImage.m */, 3613C34A1C6329F300E915CB /* JPCGPath.h */, 3613C34B1C6329F300E915CB /* JPCGPath.m */, 3613C34C1C6329F300E915CB /* JPCGTransform.h */, 3613C34D1C6329F300E915CB /* JPCGTransform.m */, 3613C34E1C6329F300E915CB /* JPCoreGraphics.h */, 3613C34F1C6329F300E915CB /* JPCoreGraphics.m */, ); path = CoreGraphics; sourceTree = ""; }; 3613C3561C6329F300E915CB /* UIKit */ = { isa = PBXGroup; children = ( 3613C3571C6329F300E915CB /* JPUIGeometry.h */, 3613C3581C6329F300E915CB /* JPUIGeometry.m */, 3613C3591C6329F300E915CB /* JPUIGraphics.h */, 3613C35A1C6329F300E915CB /* JPUIGraphics.m */, 3613C35B1C6329F300E915CB /* JPUIImage.h */, 3613C35C1C6329F300E915CB /* JPUIImage.m */, 3613C35D1C6329F300E915CB /* JPUIKit.h */, 3613C35E1C6329F300E915CB /* JPUIKit.m */, ); path = UIKit; sourceTree = ""; }; 3613C35F1C6329F300E915CB /* JSPatch */ = { isa = PBXGroup; children = ( 3613C3601C6329F300E915CB /* JPEngine.h */, 3613C3611C6329F300E915CB /* JPEngine.m */, 3613C3621C6329F300E915CB /* JSPatch.js */, ); name = JSPatch; path = ../../../JSPatch; sourceTree = ""; }; 3613C3631C6329F300E915CB /* Loader */ = { isa = PBXGroup; children = ( 3613C3641C6329F300E915CB /* JPLoader.h */, 3613C3651C6329F300E915CB /* JPLoader.m */, 3613C3661C6329F300E915CB /* libs */, 3613C3751C6329F300E915CB /* tools */, ); name = Loader; path = ../../../Loader; sourceTree = ""; }; 3613C3661C6329F300E915CB /* libs */ = { isa = PBXGroup; children = ( 3613C3671C6329F300E915CB /* minizip */, 3613C3711C6329F300E915CB /* RSA.h */, 3613C3721C6329F300E915CB /* RSA.m */, 3613C3731C6329F300E915CB /* ZipArchive.h */, 3613C3741C6329F300E915CB /* ZipArchive.m */, ); path = libs; sourceTree = ""; }; 3613C3671C6329F300E915CB /* minizip */ = { isa = PBXGroup; children = ( 3613C3681C6329F300E915CB /* crypt.h */, 3613C3691C6329F300E915CB /* ioapi.c */, 3613C36A1C6329F300E915CB /* ioapi.h */, 3613C36B1C6329F300E915CB /* mztools.c */, 3613C36C1C6329F300E915CB /* mztools.h */, 3613C36D1C6329F300E915CB /* unzip.c */, 3613C36E1C6329F300E915CB /* unzip.h */, 3613C36F1C6329F300E915CB /* zip.c */, 3613C3701C6329F300E915CB /* zip.h */, ); path = minizip; sourceTree = ""; }; 3613C3751C6329F300E915CB /* tools */ = { isa = PBXGroup; children = ( 3613C3761C6329F300E915CB /* packer.php */, ); path = tools; sourceTree = ""; }; DE94AE021AF246BE00E461D4 = { isa = PBXGroup; children = ( 40D88D171CCB800200A8837D /* Foundation.framework */, 40D88D151CCB7EBE00A8837D /* libz.tbd */, 40D88D121CCB7DBF00A8837D /* libz.1.tbd */, 40D88D101CCB7DB800A8837D /* JavaScriptCore.framework */, 2D5D89161B0B8BFF009382EC /* JSPatchDemo */, DE94AE0C1AF246BF00E461D4 /* Products */, ); sourceTree = ""; }; DE94AE0C1AF246BF00E461D4 /* Products */ = { isa = PBXGroup; children = ( 40D88CE41CCB7D0100A8837D /* JSPatchDemo.app */, ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 40D88CE31CCB7D0100A8837D /* JSPatchDemo */ = { isa = PBXNativeTarget; buildConfigurationList = 40D88CF51CCB7D0100A8837D /* Build configuration list for PBXNativeTarget "JSPatchDemo" */; buildPhases = ( 40D88CE01CCB7D0100A8837D /* Sources */, 40D88CE11CCB7D0100A8837D /* Frameworks */, 40D88CE21CCB7D0100A8837D /* Resources */, ); buildRules = ( ); dependencies = ( ); name = JSPatchDemo; productName = "JSPatchDemo-tvOS"; productReference = 40D88CE41CCB7D0100A8837D /* JSPatchDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ DE94AE031AF246BF00E461D4 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0620; ORGANIZATIONNAME = bang; TargetAttributes = { 40D88CE31CCB7D0100A8837D = { CreatedOnToolsVersion = 7.3.1; }; }; }; buildConfigurationList = DE94AE061AF246BF00E461D4 /* Build configuration list for PBXProject "JSPatchDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = DE94AE021AF246BE00E461D4; productRefGroup = DE94AE0C1AF246BF00E461D4 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 40D88CE31CCB7D0100A8837D /* JSPatchDemo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 40D88CE21CCB7D0100A8837D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 40D88D1D1CCBB00400A8837D /* JSPatch.js in Resources */, 40D88D1E1CCBB00400A8837D /* Images.xcassets in Resources */, 40D88D1F1CCBB00400A8837D /* demo.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 40D88CE01CCB7D0100A8837D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40D88D191CCB802A00A8837D /* ioapi.c in Sources */, 40D88D1A1CCB802A00A8837D /* mztools.c in Sources */, 40D88D1B1CCB802A00A8837D /* unzip.c in Sources */, 40D88D1C1CCB802A00A8837D /* zip.c in Sources */, 40D88CF81CCB7D2A00A8837D /* JPUIGeometry.m in Sources */, 40D88CF91CCB7D2A00A8837D /* JPUIGraphics.m in Sources */, 40D88CFA1CCB7D2A00A8837D /* JPUIImage.m in Sources */, 40D88CFB1CCB7D2A00A8837D /* JPUIKit.m in Sources */, 40D88CFC1CCB7D2A00A8837D /* JPCGBitmapContext.m in Sources */, 40D88CFD1CCB7D2A00A8837D /* JPCGColor.m in Sources */, 40D88CFE1CCB7D2A00A8837D /* JPCGContext.m in Sources */, 40D88CFF1CCB7D2A00A8837D /* JPCGGeometry.m in Sources */, 40D88D001CCB7D2A00A8837D /* JPCGImage.m in Sources */, 40D88D011CCB7D2A00A8837D /* JPCGPath.m in Sources */, 40D88D021CCB7D2A00A8837D /* JPCGTransform.m in Sources */, 40D88D031CCB7D2A00A8837D /* JPCoreGraphics.m in Sources */, 40D88D041CCB7D2A00A8837D /* JPMemory.m in Sources */, 40D88D051CCB7D2A00A8837D /* JPStructPointer.m in Sources */, 40D88D061CCB7D2A00A8837D /* JPSpecialInit.m in Sources */, 40D88D071CCB7D2A00A8837D /* JPCleaner.m in Sources */, 40D88D081CCB7D2A00A8837D /* JPLocker.m in Sources */, 40D88D091CCB7D2A00A8837D /* JPEngine.m in Sources */, 40D88D0A1CCB7D2A00A8837D /* JPLoader.m in Sources */, 40D88D0B1CCB7D2A00A8837D /* RSA.m in Sources */, 40D88D0C1CCB7D2A00A8837D /* ZipArchive.m in Sources */, 40D88D0D1CCB7D2A00A8837D /* main.m in Sources */, 40D88D0E1CCB7D2A00A8837D /* AppDelegate.m in Sources */, 40D88D0F1CCB7D2A00A8837D /* JPViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 40D88CF61CCB7D0100A8837D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ANALYZER_NONNULL = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = "$(SRCROOT)/JSPatchDemo/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.2; }; name = Debug; }; 40D88CF71CCB7D0100A8837D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ANALYZER_NONNULL = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = "$(SRCROOT)/JSPatchDemo/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.2; }; name = Release; }; DE94AE2C1AF246C000E461D4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; DE94AE2D1AF246C000E461D4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 40D88CF51CCB7D0100A8837D /* Build configuration list for PBXNativeTarget "JSPatchDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( 40D88CF61CCB7D0100A8837D /* Debug */, 40D88CF71CCB7D0100A8837D /* Release */, ); defaultConfigurationIsVisible = 0; }; DE94AE061AF246BF00E461D4 /* Build configuration list for PBXProject "JSPatchDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( DE94AE2C1AF246C000E461D4 /* Debug */, DE94AE2D1AF246C000E461D4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = DE94AE031AF246BF00E461D4 /* Project object */; } ================================================ FILE: Demo/tvOSDemo/JSPatchDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Extensions/JPBlock/JPBlock.h ================================================ // // JPBlock.h // JSPatch // // Created by bang on 1/19/17. // Copyright © 2017 bang. All rights reserved. // #import "JPEngine.h" @interface JPBlock : JPExtension + (id)blockWithBlockObj:(id)blockObj; @end ================================================ FILE: Extensions/JPBlock/JPBlock.m ================================================ // // JPBlock.m // JSPatch // // Created by bang on 1/19/17. // Copyright © 2017 bang. All rights reserved. // #import "JPBlock.h" #import "JPBlockWrapper.h" #import @implementation JPBlock + (void)main:(JSContext *)context { context[@"__genBlock"] = ^id(NSString *typeString, JSValue *cb) { JPBlockWrapper *blockWrapper = [[JPBlockWrapper alloc] initWithTypeString:typeString callbackFunction:cb]; return blockWrapper; }; } + (id)blockWithBlockObj:(JPBlockWrapper *)blockObj { return [blockObj blockPtr]; } @end ================================================ FILE: Extensions/JPBlock/JPBlockWrapper.h ================================================ // // JPBlockWrapper.h // JSPatch // // Created by bang on 1/19/17. // Copyright © 2017 bang. All rights reserved. // #import #import @interface JPBlockWrapper : NSObject; - (void *)blockPtr; - (id)initWithTypeString:(NSString *)typeString callbackFunction:(JSValue *)jsFunction; @end ================================================ FILE: Extensions/JPBlock/JPBlockWrapper.m ================================================ // // JPBlockWrapper.m // JSPatch // // Created by bang on 1/19/17. // Copyright © 2017 bang. All rights reserved. // #import "JPBlockWrapper.h" #import "ffi.h" #import "JPEngine.h" #import "JPMethodSignature.h" enum { BLOCK_DEALLOCATING = (0x0001), BLOCK_REFCOUNT_MASK = (0xfffe), BLOCK_NEEDS_FREE = (1 << 24), BLOCK_HAS_COPY_DISPOSE = (1 << 25), BLOCK_HAS_CTOR = (1 << 26), BLOCK_IS_GC = (1 << 27), BLOCK_IS_GLOBAL = (1 << 28), BLOCK_USE_STRET = (1 << 29), BLOCK_HAS_SIGNATURE = (1 << 30) }; struct JPSimulateBlock { void *isa; int flags; int reserved; void *invoke; struct JPSimulateBlockDescriptor *descriptor; void *wrapper; }; struct JPSimulateBlockDescriptor { //Block_descriptor_1 struct { unsigned long int reserved; unsigned long int size; }; //Block_descriptor_2 struct { // requires BLOCK_HAS_COPY_DISPOSE void (*copy)(void *dst, const void *src); void (*dispose)(const void *); }; //Block_descriptor_3 struct { // requires BLOCK_HAS_SIGNATURE const char *signature; }; }; void copy_helper(struct JPSimulateBlock *dst, struct JPSimulateBlock *src) { // do not copy anything is this funcion! just retain if need. CFRetain(dst->wrapper); } void dispose_helper(struct JPSimulateBlock *src) { CFRelease(src->wrapper); } @interface JPBlockWrapper () { ffi_cif *_cifPtr; ffi_type **_args; ffi_closure *_closure; BOOL _generatedPtr; void *_blockPtr; struct JPSimulateBlockDescriptor *_descriptor; } @property (nonatomic,strong) JPMethodSignature *signature; @property (nonatomic,strong) JSValue *jsFunction; @end void JPBlockInterpreter(ffi_cif *cif, void *ret, void **args, void *userdata) { JPBlockWrapper *blockObj = (__bridge JPBlockWrapper*)userdata; NSMutableArray *params = [[NSMutableArray alloc] init]; for (int i = 1; i < blockObj.signature.argumentTypes.count; i ++) { id param; void *argumentPtr = args[i]; const char *typeEncoding = [blockObj.signature.argumentTypes[i] UTF8String]; switch (typeEncoding[0]) { #define JP_BLOCK_PARAM_CASE(_typeString, _type, _selector) \ case _typeString: { \ _type returnValue = *(_type *)argumentPtr; \ param = [NSNumber _selector:returnValue];\ break; \ } JP_BLOCK_PARAM_CASE('c', char, numberWithChar) JP_BLOCK_PARAM_CASE('C', unsigned char, numberWithUnsignedChar) JP_BLOCK_PARAM_CASE('s', short, numberWithShort) JP_BLOCK_PARAM_CASE('S', unsigned short, numberWithUnsignedShort) JP_BLOCK_PARAM_CASE('i', int, numberWithInt) JP_BLOCK_PARAM_CASE('I', unsigned int, numberWithUnsignedInt) JP_BLOCK_PARAM_CASE('l', long, numberWithLong) JP_BLOCK_PARAM_CASE('L', unsigned long, numberWithUnsignedLong) JP_BLOCK_PARAM_CASE('q', long long, numberWithLongLong) JP_BLOCK_PARAM_CASE('Q', unsigned long long, numberWithUnsignedLongLong) JP_BLOCK_PARAM_CASE('f', float, numberWithFloat) JP_BLOCK_PARAM_CASE('d', double, numberWithDouble) JP_BLOCK_PARAM_CASE('B', BOOL, numberWithBool) case '@': { param = (__bridge id)(*(void**)argumentPtr); break; } } [params addObject:[JPExtension formatOCToJS:param]]; } JSValue *jsResult = [blockObj.jsFunction callWithArguments:params]; switch ([blockObj.signature.returnType UTF8String][0]) { #define JP_BLOCK_RET_CASE(_typeString, _type, _selector) \ case _typeString: { \ _type *retPtr = ret; \ *retPtr = [((NSNumber *)[jsResult toObject]) _selector]; \ break; \ } JP_BLOCK_RET_CASE('c', char, charValue) JP_BLOCK_RET_CASE('C', unsigned char, unsignedCharValue) JP_BLOCK_RET_CASE('s', short, shortValue) JP_BLOCK_RET_CASE('S', unsigned short, unsignedShortValue) JP_BLOCK_RET_CASE('i', int, intValue) JP_BLOCK_RET_CASE('I', unsigned int, unsignedIntValue) JP_BLOCK_RET_CASE('l', long, longValue) JP_BLOCK_RET_CASE('L', unsigned long, unsignedLongValue) JP_BLOCK_RET_CASE('q', long long, longLongValue) JP_BLOCK_RET_CASE('Q', unsigned long long, unsignedLongLongValue) JP_BLOCK_RET_CASE('f', float, floatValue) JP_BLOCK_RET_CASE('d', double, doubleValue) JP_BLOCK_RET_CASE('B', BOOL, boolValue) case '@': case '#': { id retObj = [JPExtension formatJSToOC:jsResult]; void **retPtrPtr = ret; *retPtrPtr = (__bridge void *)retObj; break; } case '^': { JPBoxing *box = [JPExtension formatJSToOC:jsResult]; void *pointer = [box unboxPointer]; void **retPtrPtr = ret; *retPtrPtr = pointer; break; } } } @implementation JPBlockWrapper - (id)initWithTypeString:(NSString *)typeString callbackFunction:(JSValue *)jsFunction { self = [super init]; if(self) { _generatedPtr = NO; self.jsFunction = jsFunction; self.signature = [[JPMethodSignature alloc] initWithBlockTypeNames:typeString]; } return self; } - (void *)blockPtr { if (_generatedPtr) { return _blockPtr; } _generatedPtr = YES; ffi_type *returnType = [JPMethodSignature ffiTypeWithEncodingChar:[self.signature.returnType UTF8String]]; NSUInteger argumentCount = self.signature.argumentTypes.count; _cifPtr = malloc(sizeof(ffi_cif)); void *blockImp = NULL; _args = malloc(sizeof(ffi_type *) *argumentCount) ; for (int i = 0; i < argumentCount; i++){ ffi_type* current_ffi_type = [JPMethodSignature ffiTypeWithEncodingChar:[self.signature.argumentTypes[i] UTF8String]]; _args[i] = current_ffi_type; } _closure = ffi_closure_alloc(sizeof(ffi_closure), (void **)&blockImp); if(ffi_prep_cif(_cifPtr, FFI_DEFAULT_ABI, (unsigned int)argumentCount, returnType, _args) == FFI_OK) { if (ffi_prep_closure_loc(_closure, _cifPtr, JPBlockInterpreter, (__bridge void *)self, blockImp) != FFI_OK) { NSAssert(NO, @"generate block error"); } } struct JPSimulateBlockDescriptor descriptor = { 0, sizeof(struct JPSimulateBlock), (void (*)(void *dst, const void *src))copy_helper, (void (*)(const void *src))dispose_helper, [self.signature.types cStringUsingEncoding:NSASCIIStringEncoding] }; _descriptor = malloc(sizeof(struct JPSimulateBlockDescriptor)); memcpy(_descriptor, &descriptor, sizeof(struct JPSimulateBlockDescriptor)); struct JPSimulateBlock simulateBlock = { &_NSConcreteStackBlock, (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_SIGNATURE), 0, blockImp, _descriptor, (__bridge void*)self }; _blockPtr = Block_copy(&simulateBlock); return _blockPtr; } - (void)dealloc { ffi_closure_free(_closure); free(_args); free(_cifPtr); free(_descriptor); return; } @end ================================================ FILE: Extensions/JPCFunction/JPCFunction.h ================================================ // // JPCFunction.h // JSPatch // // Created by bang on 5/30/16. // Copyright © 2016 bang. All rights reserved. // #import "JPEngine.h" @interface JPCFunction : JPExtension @end ================================================ FILE: Extensions/JPCFunction/JPCFunction.m ================================================ // // JPCFunction.m // JSPatch // // Created by bang on 5/30/16. // Copyright © 2016 bang. All rights reserved. // #import "JPCFunction.h" #import "ffi.h" #import #import "JPMethodSignature.h" #if CGFLOAT_IS_DOUBLE #define CGFloatValue doubleValue #define numberWithCGFloat numberWithDouble #else #define CGFloatValue floatValue #define numberWithCGFloat numberWithFloat #endif @implementation JPCFunction static NSMutableDictionary *_funcDefines; + (void)main:(JSContext *)context { if (!_funcDefines) { _funcDefines = [[NSMutableDictionary alloc] init]; } [context evaluateScript:@" \ global.defineCFunction = function(funcName, paramsStr) { \ _OC_defineCFunction(funcName, paramsStr); \ global[funcName] = function() { \ var args = Array.prototype.slice.call(arguments); \ return _OC_callCFunc.apply(global, [funcName, args]); \ } \ } \ "]; context[@"_OC_defineCFunction"] = ^void(NSString *funcName, NSString *types) { [self defineCFunction:funcName types:types]; }; context[@"_OC_callCFunc"] = ^id(NSString *funcName, JSValue *args) { id ret = [self callCFunction:funcName arguments:[self formatJSToOC:args]]; return [self formatOCToJS:ret]; }; } + (void)defineCFunction:(NSString *)funcName types:(NSString *)types { NSMutableString *encodeStr = [[NSMutableString alloc] init]; NSArray *typeArr = [types componentsSeparatedByString:@","]; for (NSInteger i = 0; i < typeArr.count; i++) { NSString *typeStr = trim([typeArr objectAtIndex:i]); NSString *encode = [JPMethodSignature typeEncodeWithTypeName:typeStr]; if (!encode) { if ([typeStr hasPrefix:@"{"] && [typeStr hasSuffix:@"}"]) { encode = typeStr; } else { NSString *argClassName = trim([typeStr stringByReplacingOccurrencesOfString:@"*" withString:@""]); if (NSClassFromString(argClassName) != NULL) { encode = @"@"; } else { NSCAssert(NO, @"unreconized type %@", typeStr); return; } } } [encodeStr appendString:encode]; } [_funcDefines setObject:encodeStr forKey:funcName]; } + (id)objectWithCValue:(void *)src forType:(const char *)typeString { switch (typeString[0]) { #define JP_FFI_RETURN_CASE(_typeString, _type, _selector)\ case _typeString:{\ _type v = *(_type *)src;\ return [NSNumber _selector:v];\ } JP_FFI_RETURN_CASE('c', char, numberWithChar) JP_FFI_RETURN_CASE('C', unsigned char, numberWithUnsignedChar) JP_FFI_RETURN_CASE('s', short, numberWithShort) JP_FFI_RETURN_CASE('S', unsigned short, numberWithUnsignedShort) JP_FFI_RETURN_CASE('i', int, numberWithInt) JP_FFI_RETURN_CASE('I', unsigned int, numberWithUnsignedInt) JP_FFI_RETURN_CASE('l', long, numberWithLong) JP_FFI_RETURN_CASE('L', unsigned long, numberWithUnsignedLong) JP_FFI_RETURN_CASE('q', long long, numberWithLongLong) JP_FFI_RETURN_CASE('Q', unsigned long long, numberWithUnsignedLongLong) JP_FFI_RETURN_CASE('f', float, numberWithFloat) JP_FFI_RETURN_CASE('F', CGFloat, numberWithCGFloat) JP_FFI_RETURN_CASE('d', double, numberWithDouble) JP_FFI_RETURN_CASE('B', BOOL, numberWithBool) case '^': { JPBoxing *box = [[JPBoxing alloc] init]; box.pointer = (*(void**)src); return box; } case '@': case '#': { return (__bridge id)(*(void**)src); } case '{': { NSString *structName = [NSString stringWithCString:typeString encoding:NSASCIIStringEncoding]; NSUInteger end = [structName rangeOfString:@"}"].location; if (end != NSNotFound) { structName = [structName substringWithRange:NSMakeRange(1, end - 1)]; NSDictionary *structDefine = [JPExtension registeredStruct][structName]; id dict = [JPExtension getDictOfStruct:src structDefine:structDefine]; id ret = [JSValue valueWithObject:dict inContext:[JPEngine context]]; return ret; } } default: return nil; } } + (void)convertObject:(id)object toCValue:(void *)dist forType:(const char *)typeString { #define JP_CALL_ARG_CASE(_typeString, _type, _selector)\ case _typeString:{\ *(_type *)dist = [(NSNumber *)object _selector];\ break;\ } switch (typeString[0]) { JP_CALL_ARG_CASE('c', char, charValue) JP_CALL_ARG_CASE('C', unsigned char, unsignedCharValue) JP_CALL_ARG_CASE('s', short, shortValue) JP_CALL_ARG_CASE('S', unsigned short, unsignedShortValue) JP_CALL_ARG_CASE('i', int, intValue) JP_CALL_ARG_CASE('I', unsigned int, unsignedIntValue) JP_CALL_ARG_CASE('l', long, longValue) JP_CALL_ARG_CASE('L', unsigned long, unsignedLongValue) JP_CALL_ARG_CASE('q', long long, longLongValue) JP_CALL_ARG_CASE('Q', unsigned long long, unsignedLongLongValue) JP_CALL_ARG_CASE('f', float, floatValue) JP_CALL_ARG_CASE('F', CGFloat, CGFloatValue) JP_CALL_ARG_CASE('d', double, doubleValue) JP_CALL_ARG_CASE('B', BOOL, boolValue) case '^': { void *ptr = [((JPBoxing *)object) unboxPointer]; *(void **)dist = ptr; break; } case '#': case '@': { id ptr = object; *(void **)dist = (__bridge void *)(ptr); break; } case '{': { NSString *structName = [NSString stringWithCString:typeString encoding:NSASCIIStringEncoding]; NSUInteger end = [structName rangeOfString:@"}"].location; if (end != NSNotFound) { structName = [structName substringWithRange:NSMakeRange(1, end - 1)]; NSDictionary *structDefine = [JPExtension registeredStruct][structName]; [JPExtension getStructDataWidthDict:dist dict:object structDefine:structDefine]; break; } } default: break; } } + (id)callCFunction:(NSString *)funcName arguments:(NSArray *)arguments { void* functionPtr = dlsym(RTLD_DEFAULT, [funcName UTF8String]); if (!functionPtr) { return nil; } JPMethodSignature *funcSignature = [[JPMethodSignature alloc] initWithObjCTypes:[_funcDefines objectForKey:funcName]]; NSUInteger argCount = funcSignature.argumentTypes.count; if (argCount != [arguments count]){ return nil; } ffi_type **ffiArgTypes = alloca(sizeof(ffi_type *) *argCount); void **ffiArgs = alloca(sizeof(void *) *argCount); for (int i = 0; i < argCount; i ++) { const char *argumentType = [funcSignature.argumentTypes[i] UTF8String]; ffi_type *ffiType = [JPMethodSignature ffiTypeWithEncodingChar:argumentType]; ffiArgTypes[i] = ffiType; void *ffiArgPtr = alloca(ffiType->size); [self convertObject:arguments[i] toCValue:ffiArgPtr forType:argumentType]; ffiArgs[i] = ffiArgPtr; } ffi_cif cif; id ret = nil; const char *returnTypeChar = [funcSignature.returnType UTF8String]; ffi_type *returnFfiType = [JPMethodSignature ffiTypeWithEncodingChar:returnTypeChar]; ffi_status ffiPrepStatus = ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, (unsigned int)0, (unsigned int)argCount, returnFfiType, ffiArgTypes); if (ffiPrepStatus == FFI_OK) { void *returnPtr = NULL; if (returnFfiType->size) { returnPtr = alloca(returnFfiType->size); } ffi_call(&cif, functionPtr, returnPtr, ffiArgs); if (returnFfiType->size) { ret = [self objectWithCValue:returnPtr forType:returnTypeChar]; } } return ret; } static NSString *trim(NSString *string) { return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; } @end ================================================ FILE: Extensions/JPCFunction/JPMemory.h ================================================ // // JPMemory.h // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPMemory : JPExtension @end ================================================ FILE: Extensions/JPCFunction/JPMemory.m ================================================ // // JPMemory.m // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPMemory.h" @implementation JPMemory + (void)main:(JSContext *)context { context[@"memset"] = ^void(JSValue *jsVal, int ch,size_t n) { memset([self formatPointerJSToOC:jsVal], ch, n); }; context[@"memmove"] = ^id(JSValue *des, JSValue *src, size_t n) { void *ret = memmove([self formatPointerJSToOC:des], [self formatPointerJSToOC:src], n); return [self formatPointerOCToJS:ret]; }; context[@"memcpy"] = ^id(JSValue *des, JSValue *src, size_t n) { void *ret = memcpy([self formatPointerJSToOC:des], [self formatPointerJSToOC:src], n); return [self formatPointerOCToJS:ret]; }; context[@"malloc"] = ^id(size_t size) { void *m = malloc(size); return [self formatPointerOCToJS:m]; }; context[@"free"] = ^void(JSValue *jsVal) { void *m = [self formatPointerJSToOC:jsVal]; free(m); }; context[@"pval"] = ^id(JSValue *jsVal) { void *m = [self formatPointerJSToOC:jsVal]; id obj = *((__unsafe_unretained id *)m); return [self formatOCToJS:obj]; }; context[@"getPointer"] = ^id(JSValue *jsVal) { void **p = malloc(sizeof(void *)); void *pointer = [self formatPointerJSToOC:jsVal]; if (pointer != NULL) { *p = pointer; } else { id obj = [self formatJSToOC:jsVal]; *p = (__bridge void*)obj; } return [self formatPointerOCToJS:p]; }; context[@"pvalBool"] = ^id(JSValue *jsVal) { void *m = [self formatPointerJSToOC:jsVal]; BOOL b = *((BOOL *)m); return [self formatOCToJS:[NSNumber numberWithBool:b]]; }; __weak JSContext *weakCtx = context; context[@"sizeof"] = ^size_t(JSValue *jsVal) { NSString *typeName = [jsVal toString]; if ([typeName isEqualToString:@"id"]) return sizeof(id); if ([typeName isEqualToString:@"CGRect"]) return sizeof(CGRect); if ([typeName isEqualToString:@"CGPoint"]) return sizeof(CGPoint); if ([typeName isEqualToString:@"CGSize"]) return sizeof(CGSize); if ([typeName isEqualToString:@"NSRange"]) return sizeof(NSRange); @synchronized (weakCtx) { NSDictionary *structDefine = [JPExtension registeredStruct][typeName]; if (structDefine) { return [self sizeOfStructTypes:structDefine[@"types"]]; } } return 0; }; context[@"__bridge_id"] = ^id(JSValue *jsVal) { void *p = [self formatPointerJSToOC:jsVal]; id obj = (__bridge id)p; return [self formatOCToJS:obj]; }; context[@"CFRelease"] = ^void(JSValue *jsVal) { CFRelease([self formatPointerJSToOC:jsVal]); }; context[@"CFRetain"] = ^void(JSValue *jsVal) { CFRetain([self formatPointerJSToOC:jsVal]); }; context[@"assignPointer"] = ^void(JSValue *jsVal, JSValue *value) { void *m = [self formatPointerJSToOC:jsVal]; id obj = [self formatJSToOC:value]; *((__unsafe_unretained id *)m) = obj; }; context[@"assignScalarTypePointer"] = ^void(JSValue *jsVal, JSValue *value, NSString *type) { void *pointer = [self formatPointerJSToOC:jsVal]; char *typeChar = (char*)[type UTF8String]; switch (typeChar[0]) { #define JP_ASSIGN_SCALAR_CASE(_typeChar, _type, _method) \ case _typeChar: { \ NSNumber *num = [value toNumber]; \ (*(_type *)pointer) = [num _method]; \ break; \ } JP_ASSIGN_SCALAR_CASE('s', short, shortValue) JP_ASSIGN_SCALAR_CASE('S', unsigned short, unsignedShortValue) JP_ASSIGN_SCALAR_CASE('i', int, intValue) JP_ASSIGN_SCALAR_CASE('I', unsigned int, unsignedIntValue) JP_ASSIGN_SCALAR_CASE('l', long, longValue) JP_ASSIGN_SCALAR_CASE('L', unsigned long, unsignedLongValue) JP_ASSIGN_SCALAR_CASE('q', long long, longLongValue) JP_ASSIGN_SCALAR_CASE('Q', unsigned long long, unsignedLongLongValue) JP_ASSIGN_SCALAR_CASE('f', float, floatValue) JP_ASSIGN_SCALAR_CASE('d', double, doubleValue) JP_ASSIGN_SCALAR_CASE('B', BOOL, boolValue) case 'c': case 'C': { NSString *str = [value toString]; (*(char *)pointer) = *[str cStringUsingEncoding:NSUTF8StringEncoding]; break; } default: { break; } } }; context[@"autoreleasepool"] = ^void(JSValue *cb) { @autoreleasepool { [cb callWithArguments:nil]; } }; } @end ================================================ FILE: Extensions/JPCFunction/JPStructPointer.h ================================================ // // JPStructPointer.h // JSPatchDemo // // Created by bang on 15/8/13. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPStructPointer : JPExtension @end ================================================ FILE: Extensions/JPCFunction/JPStructPointer.m ================================================ // // JPStructPointer.m // JSPatchDemo // // Created by bang on 15/8/13. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPStructPointer.h" @implementation JPStructPointer + (void)main:(JSContext *)context { __weak JSContext *weakCtx = context; context[@"newStruct"] = ^id(NSString *structName, JSValue *structDict) { #define JP_NEW_STRUCT(_type, _method) \ if ([structName isEqualToString:@#_type]) { \ void *ret = malloc(sizeof(_type)); \ _type rect = [structDict _method]; \ ret = memcpy(ret, &rect, sizeof(_type)); \ return [self formatPointerOCToJS:ret]; \ } JP_NEW_STRUCT(CGRect, toRect) JP_NEW_STRUCT(CGPoint, toPoint) JP_NEW_STRUCT(CGSize, toSize) JP_NEW_STRUCT(NSRange, toRange) @synchronized (weakCtx) { NSDictionary *structDefine = [JPExtension registeredStruct][structName]; if (structDefine) { int size = [self sizeOfStructTypes:structDefine[@"types"]]; void *ret = malloc(size); memset(ret, 0, size); [self getStructDataWidthDict:ret dict:[structDict toObject] structDefine:structDefine]; return [self formatPointerOCToJS:ret]; } } return nil; }; context[@"pvalStruct"] = ^id(NSString *structName, JSValue *structPointer) { if ([structName isEqualToString:@"CGRect"]) { CGRect *rect = [self formatPointerJSToOC:structPointer]; return @{@"x": @(rect->origin.x), @"y": @(rect->origin.y), @"width": @(rect->size.width), @"height": @(rect->size.height)}; } if ([structName isEqualToString:@"CGPoint"]) { CGPoint *point = [self formatPointerJSToOC:structPointer]; return @{@"x": @(point->x), @"y": @(point->y)}; } if ([structName isEqualToString:@"CGSize"]) { CGSize *size = [self formatPointerJSToOC:structPointer]; return @{@"width": @(size->width), @"height": @(size->height)}; } if ([structName isEqualToString:@"NSRange"]) { NSRange *range = [self formatPointerJSToOC:structPointer]; return @{@"location": @(range->location), @"length": @(range->length)}; } @synchronized (weakCtx) { JSContext *context = [JPEngine context]; @synchronized (context) { NSDictionary *structDefine = [JPExtension registeredStruct][structName]; if (structDefine) { return [self getDictOfStruct:[self formatPointerJSToOC:structPointer] structDefine:structDefine]; } } } return nil; }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGBitmapContext.h ================================================ // // JPCGBitmapContext.h // JSPatchDemo // // Created by Albert438 on 15/7/3. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPCGBitmapContext : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGBitmapContext.m ================================================ // // JPCGBitmapContext.m // JSPatchDemo // // Created by Albert438 on 15/7/3. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPCGBitmapContext.h" #import @implementation JPCGBitmapContext + (void)main:(JSContext *)context { context[@"CGBitmapContextCreate"] = ^id(JSValue *data, size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow, JSValue *space, uint32_t bitmapInfo) { CGContextRef bitmapContext = CGBitmapContextCreate([self formatPointerJSToOC:data], width, height, bitsPerComponent, bytesPerRow, [self formatPointerJSToOC:space], bitmapInfo); return [self formatRetainedCFTypeOCToJS:bitmapContext]; }; context[@"CGBitmapContextCreateImage"] = ^id(JSValue *c) { CGImageRef image = CGBitmapContextCreateImage([self formatPointerJSToOC:c]); return [self formatRetainedCFTypeOCToJS:image]; }; context[@"CGBitmapContextGetBytesPerRow"] = ^size_t(JSValue *c) { return CGBitmapContextGetBytesPerRow([self formatPointerJSToOC:c]); }; context[@"CGBitmapContextGetData"] = ^id(JSValue *c) { return [self formatPointerJSToOC:CGBitmapContextGetData([self formatPointerJSToOC:c])]; }; context[@"CGBitmapContextGetHeight"] = ^size_t(JSValue *c) { return CGBitmapContextGetHeight([self formatPointerJSToOC:c]); }; context[@"CGBitmapContextGetWidth"] = ^size_t(JSValue *c) { return CGBitmapContextGetWidth([self formatPointerJSToOC:c]); }; context[@"CGImageRelease"] = ^void(JSValue *image) { CGImageRelease([self formatPointerJSToOC:image]); }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGColor.h ================================================ // // JPCGColor.h // JSPatchDemo // // Created by Albert438 on 15/7/3. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPCGColor : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGColor.m ================================================ // // JPCGColor.m // JSPatchDemo // // Created by Albert438 on 15/7/3. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPCGColor.h" #import @implementation JPCGColor + (void)main:(JSContext *)context { context[@"CGColorCreate"] = ^id(JSValue *space, NSArray *componentsArray) { CGFloat *components = malloc(componentsArray.count * sizeof(CGFloat)); for (int i = 0; i < componentsArray.count; i++) { components[i] = [componentsArray[i] doubleValue]; } CGColorRef color = CGColorCreate([self formatPointerJSToOC:space], components); free(components); return [self formatRetainedCFTypeOCToJS:color]; }; context[@"CGColorEqualToColor"] = ^BOOL(JSValue *color1, JSValue *color2) { return CGColorEqualToColor([self formatPointerJSToOC:color1], [self formatPointerJSToOC:color2]); }; context[@"CGColorGetColorSpace"] = ^id(JSValue *color) { CGColorSpaceRef space = CGColorGetColorSpace([self formatPointerJSToOC:color]); return [self formatPointerOCToJS:space]; }; context[@"CGColorGetComponents"] = ^NSArray *(JSValue *color) { size_t numberOfComponents = CGColorGetNumberOfComponents([self formatPointerJSToOC:color]); const CGFloat *componets = CGColorGetComponents([self formatPointerJSToOC:color]); NSMutableArray *componentsArray = [NSMutableArray array]; for (int i = 0 ; i < numberOfComponents ; i++) { [componentsArray addObject:[NSNumber numberWithDouble:componets[i]]]; } return componentsArray; }; context[@"CGColorGetNumberOfComponents"] = ^size_t(JSValue *color) { return CGColorGetNumberOfComponents([self formatPointerJSToOC:color]); }; context[@"CGColorRelease"] = ^void(JSValue *color){ CGColorRelease([self formatPointerJSToOC:color]); }; context[@"CGColorSpaceCreateDeviceGray"] = ^id() { return [self formatRetainedCFTypeOCToJS:CGColorSpaceCreateDeviceGray()]; }; context[@"CGColorSpaceCreateDeviceRGB"] = ^id() { return [self formatRetainedCFTypeOCToJS:CGColorSpaceCreateDeviceRGB()]; }; context[@"CGColorSpaceCreateDeviceCMYK"] = ^id() { return [self formatRetainedCFTypeOCToJS:CGColorSpaceCreateDeviceCMYK()]; }; context[@"CGColorSpaceCreatePattern"] = ^id(JSValue *baseSpace) { return [self formatRetainedCFTypeOCToJS:CGColorSpaceCreatePattern([self formatPointerJSToOC:baseSpace])]; }; context[@"CGColorSpaceGetModel"] = ^NSInteger(JSValue *space) { NSInteger model = CGColorSpaceGetModel([self formatPointerJSToOC:space]); return model; }; context[@"CGColorSpaceRelease"] = ^void(JSValue *space) { CGColorSpaceRelease([self formatPointerJSToOC:space]); }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGContext.h ================================================ // // JPCGContext.h // // // Created by Albert438 on 15/7/2. // Copyright © 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPCGContext : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGContext.m ================================================ // // JPCGContext.m // // // Created by Albert438 on 15/7/2. // Copyright © 2015年 bang. All rights reserved. // #import "JPCGContext.h" #import "JPCGTransform.h" #import "JPCGGeometry.h" #import @implementation JPCGContext + (void)main:(JSContext *)context { context[@"CGContextSetLineCap"] = ^void(JSValue *c, int cap) { CGContextSetLineCap([self formatPointerJSToOC:c], cap); }; context[@"CGContextSetFillColorWithColor"] = ^void(JSValue *c, JSValue *color) { CGContextSetFillColorWithColor([self formatPointerJSToOC:c], [self formatPointerJSToOC:color]); }; context[@"CGContextSetLineWidth"] = ^void(JSValue *c, CGFloat lineWidthValue) { CGContextSetLineWidth([self formatPointerJSToOC:c], lineWidthValue); }; context[@"CGContextBeginPath"] = ^void(JSValue *c) { CGContextBeginPath([self formatPointerJSToOC:c]); }; context[@"CGContextMoveToPoint"] = ^void(JSValue *c, CGFloat x, CGFloat y) { CGContextMoveToPoint([self formatPointerJSToOC:c], x, y); }; context[@"CGContextAddLineToPoint"] = ^void(JSValue *c, CGFloat x, CGFloat y) { CGContextAddLineToPoint([self formatPointerJSToOC:c], x, y); }; context[@"CGContextStrokePath"] = ^void(JSValue *c) { CGContextStrokePath([self formatPointerJSToOC:c]); }; context[@"CGContextSetRGBStrokeColor"] = ^void(JSValue *c,CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha){ CGContextSetRGBStrokeColor([self formatPointerJSToOC:c], red, green, blue, alpha); }; context[@"CGContextSetRGBFillColor"] = ^void(JSValue *c,CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha){ CGContextSetRGBFillColor([self formatPointerJSToOC:c], red, green, blue, alpha); }; context[@"CGContextClosePath"] = ^void(JSValue *c) { CGContextClosePath([self formatPointerJSToOC:c]); }; context[@"CGContextStrokeRect"] = ^void(JSValue *c, NSDictionary *cgRectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:cgRectDict]; CGContextStrokeRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextAddArc"] = ^void(JSValue *c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise) { CGContextAddArc([self formatPointerJSToOC:c], x, y, radius, startAngle, endAngle, clockwise); }; context[@"CGContextAddArcToPoint"] = ^void(JSValue *c, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat radius) { CGContextAddArcToPoint([self formatPointerJSToOC:c], x1, y1, x2, y2, radius); }; context[@"CGContextAddRect"] = ^void(JSValue *c, NSDictionary *cgRectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:cgRectDict]; CGContextAddRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextAddPath"] = ^void(JSValue *c, JSValue *path) { CGContextAddPath([self formatPointerJSToOC:c], [self formatPointerJSToOC:path]); }; context[@"CGContextAddLines"] = ^void(JSValue *c, NSArray *points, NSUInteger count){ CGPoint *pointsArray = malloc(count * sizeof(CGPoint)); for (int i = 0; i < count; i++) { CGPoint point; [JPCGGeometry pointStruct:&point ofDict:points[i]]; pointsArray[i] = point; } CGContextAddLines([self formatPointerJSToOC:c], pointsArray, count); free(pointsArray); }; context[@"CGContextAddEllipseInRect"] = ^void(JSValue *c, NSDictionary *rectDict){ CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGContextAddEllipseInRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextDrawImage"] = ^void(JSValue *c, NSDictionary *rectDict, JSValue *image) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGContextDrawImage([self formatPointerJSToOC:c], rect, [self formatPointerJSToOC:image]); }; context[@"CGContextDrawPath"] = ^void(JSValue *c, int mode) { CGContextDrawPath([self formatPointerJSToOC:c], mode); }; context[@"CGContextRestoreGState"] = ^void(JSValue *c) { CGContextRestoreGState([self formatPointerJSToOC:c]); }; context[@"CGContextSaveGState"] = ^void(JSValue *c) { CGContextSaveGState([self formatPointerJSToOC:c]); }; context[@"CGContextRetain"] = ^id(JSValue *c) { CGContextRef retainContext = CGContextRetain([self formatPointerJSToOC:c]); return [self formatPointerOCToJS:retainContext]; }; context[@"CGContextRelease"] = ^void(JSValue *c) { CGContextRelease([self formatPointerJSToOC:c]); }; context[@"CGContextTranslateCTM"] = ^void(JSValue *c, CGFloat tx, CGFloat ty) { CGContextTranslateCTM([self formatPointerJSToOC:c], tx, ty); }; context[@"CGContextScaleCTM"] = ^void(JSValue *c, CGFloat sx, CGFloat sy) { CGContextScaleCTM([self formatPointerJSToOC:c], sx, sy); }; context[@"CGContextFillPath"] = ^void(JSValue *c) { CGContextFillPath([self formatPointerJSToOC:c]); }; context[@"CGContextFillRect"] = ^void(JSValue *c, NSDictionary *cgRectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:cgRectDict]; CGContextFillRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextSetShadowWithColor"] = ^void(JSValue *c, CGSize offset, CGFloat blur, JSValue *color) { CGContextSetShadowWithColor([self formatPointerJSToOC:c], offset, blur, [self formatPointerJSToOC:color]); }; context[@"CGContextClip"] = ^void(JSValue *c) { CGContextClip([self formatPointerJSToOC:c]); }; context[@"CGContextConcatCTM"] = ^void(JSValue *c, NSDictionary *transfromDict) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:transfromDict]; CGContextConcatCTM([self formatPointerJSToOC:c], transform); }; context[@"CGContextGetClipBoundingBox"] = ^void(JSValue *c) { CGContextGetClipBoundingBox([self formatPointerJSToOC:c]); }; context[@"CGContextClearRect"] = ^void(JSValue *c, NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGContextClearRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextFillEllipseInRect"] = ^void(JSValue *c, NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGContextFillEllipseInRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextDrawLinearGradient"] = ^void(JSValue *c,JSValue *gradient, NSDictionary *startPointDict, NSDictionary *endPointDict,int options) { CGPoint startPoint; CGPoint endPoint; [JPCGGeometry pointStruct:&startPoint ofDict:startPointDict]; [JPCGGeometry pointStruct:&endPoint ofDict:endPointDict]; CGContextDrawLinearGradient([self formatPointerJSToOC:c], [self formatPointerJSToOC:gradient], startPoint, endPoint, options); }; context[@"CGContextSetAlpha"] = ^void(JSValue *c, CGFloat a) { CGContextSetAlpha([self formatPointerJSToOC:c], a); }; context[@"CGContextClipToRect"] = ^void(JSValue *c, NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGContextClipToRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextSetInterpolationQuality"] = ^void(JSValue *c, int quality) { CGContextSetInterpolationQuality([self formatPointerJSToOC:c], quality); }; context[@"CGContextClipToMask"] = ^void(JSValue *c, NSDictionary *rectDict, JSValue *mask) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGContextClipToMask([self formatPointerJSToOC:c], rect, [self formatPointerJSToOC:mask]); }; context[@"CGContextSetTextDrawingMode"] = ^void(JSValue *c, int mode) { CGContextSetTextDrawingMode([self formatPointerJSToOC:c], mode); }; context[@"CGContextGetCTM"] = ^void(JSValue *c) { CGContextGetCTM([self formatPointerJSToOC:c]); }; context[@"CGContextStrokeEllipseInRect"] = ^void(JSValue *c, NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGContextStrokeEllipseInRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextSetLineDash"] = ^void(JSValue *c, CGFloat phase, NSArray *lengths, size_t count) { CGFloat *lengthsArray = malloc(count * sizeof(CGFloat)); for (int i = 0 ; i < count; i++) { lengthsArray[i] = [lengths[i] doubleValue]; } CGContextSetLineDash([self formatPointerJSToOC:c], phase, lengthsArray, count); free(lengthsArray); }; context[@"CGContextRotateCTM"] = ^void(JSValue *c, CGFloat angle) { CGContextRotateCTM([self formatPointerJSToOC:c], angle); }; context[@"CGContextSetLineJoin"] = ^void(JSValue *c, int join) { CGContextSetLineJoin([self formatPointerJSToOC:c], join); }; context[@"CGContextSetGrayFillColor"] = ^void(JSValue *c, CGFloat gray, CGFloat alpha) { CGContextSetGrayFillColor([self formatPointerJSToOC:c], gray, alpha); }; context[@"CGContextBeginTransparencyLayer"] = ^void(JSValue *c,JSValue *auxiliaryInfo) { CGContextBeginTransparencyLayer([self formatPointerJSToOC:c], [self formatPointerJSToOC:auxiliaryInfo]); }; context[@"CGContextSetBlendMode"] = ^void(JSValue *context, int mode) { CGContextSetBlendMode([self formatPointerJSToOC:context], mode); }; context[@"CGContextEndTransparencyLayer"] = ^void(JSValue *c) { CGContextEndTransparencyLayer([self formatPointerJSToOC:c]); }; context[@"CGContextSetShadow"] = ^void(JSValue *c, NSDictionary *offsetDict, CGFloat blur) { CGSize size; [JPCGGeometry sizeStruct:&size ofDict:offsetDict]; CGContextSetShadow([self formatPointerJSToOC:c], size, blur); }; context[@"CGContextSetTextMatrix"] = ^void(JSValue *c, NSDictionary *transformDict) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:transformDict]; CGContextSetTextMatrix([self formatPointerJSToOC:c], transform); }; context[@"CGContextSetTextPosition"] = ^(JSValue *c, CGFloat x, CGFloat y) { CGContextSetTextPosition([self formatPointerJSToOC:c], x, y); }; context[@"CGContextSetMiterLimit"] = ^(JSValue *c, CGFloat limit) { CGContextSetMiterLimit([self formatPointerJSToOC:c], limit); }; context[@"CGContextStrokeRect"] = ^(JSValue *c, NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGContextStrokeRect([self formatPointerJSToOC:c], rect); }; context[@"CGContextSetFillColorSpace"] = ^(JSValue *c, JSValue *space) { CGContextSetFillColorSpace([self formatPointerJSToOC:c], [self formatPointerJSToOC:space]); }; context[@"CGContextSetFlatness"] = ^(JSValue *c, CGFloat flatness) { CGContextSetFlatness([self formatPointerJSToOC:c], flatness); }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGGeometry.h ================================================ // // JPCGGeometryHelper.h // JSPatchDemo // // Created by Albert438 on 15/7/2. // Copyright © 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPCGGeometry : JPExtension + (void)rectStruct:(CGRect *)rect ofDict:(NSDictionary *)dict; + (void)pointStruct:(CGPoint *)point ofDict:(NSDictionary *)dict; + (void)sizeStruct:(CGSize *)size ofDict:(NSDictionary *)dict; + (void)vectorStruct:(CGVector *)vector ofDict:(NSDictionary *)dict; + (NSDictionary *)rectDictOfStruct:(CGRect *)rect; + (NSDictionary *)sizeDictOfStruct:(CGSize *)size; + (NSDictionary *)pointDictOfStruct:(CGPoint *)point; + (NSDictionary *)vectorDictOfStruct:(CGVector *)vector; @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGGeometry.m ================================================ // // JPCGGeometryHelper.m // JSPatchDemo // // Created by Albert438 on 15/7/2. // Copyright © 2015年 bang. All rights reserved. // #import "JPCGGeometry.h" #import @implementation JPCGGeometry + (void)main:(JSContext *)context { [JPEngine defineStruct:@{ @"name": @"CGVector", @"types": @"FF", @"keys": @[@"dx", @"dy"] }]; [JPEngine defineStruct:@{ @"name": @"CGAffineTransform", @"types": @"FFFFFF", @"keys": @[@"a", @"b", @"c", @"d", @"tx", @"ty"] }]; context[@"CGRectContainsPoint"] = ^BOOL(NSDictionary *rectDict, NSDictionary *pointDict) { CGRect rect; CGPoint point; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; [JPCGGeometry pointStruct:&point ofDict:pointDict]; return CGRectContainsPoint(rect, point); }; context[@"CGRectEqualToRect"] = ^BOOL(NSDictionary *rectDict1, NSDictionary *rectDict2) { CGRect rect1,rect2; [JPCGGeometry rectStruct:&rect1 ofDict:rectDict1]; [JPCGGeometry rectStruct:&rect2 ofDict:rectDict2]; return CGRectEqualToRect(rect1, rect2); }; context[@"CGRectGetMaxX"] = ^CGFloat(NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; return CGRectGetMaxX(rect); }; context[@"CGRectGetMaxY"] = ^CGFloat(NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; return CGRectGetMaxY(rect); }; context[@"CGRectGetMidX"] = ^CGFloat(NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; return CGRectGetMidX(rect); }; context[@"CGRectGetMidY"] = ^CGFloat(NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; return CGRectGetMidY(rect); }; context[@"CGRectGetMinX"] = ^CGFloat(NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; return CGRectGetMinX(rect); }; context[@"CGRectGetMinY"] = ^CGFloat(NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; return CGRectGetMinY(rect); }; context[@"CGRectInset"] = ^CGRect(NSDictionary *rectDict, CGFloat dx, CGFloat dy) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGRect rectInset = CGRectInset(rect, dx, dy); return rectInset; }; context[@"CGRectIntegral"] = ^CGRect(NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGRect rectIntegral = CGRectIntegral(rect); return rectIntegral; }; context[@"CGRectIntersection"] = ^CGRect(NSDictionary *rectDict1, NSDictionary *rectDict2) { CGRect rect1,rect2; [JPCGGeometry rectStruct:&rect1 ofDict:rectDict1]; [JPCGGeometry rectStruct:&rect2 ofDict:rectDict2]; CGRect rectIntersection = CGRectIntersection(rect1, rect2); return rectIntersection; }; context[@"CGRectOffset"] = ^CGRect(NSDictionary *rectDict, CGFloat dx, CGFloat dy) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGRect rectOffset = CGRectOffset(rect, dx, dy); return rectOffset; }; context[@"CGRectIntersectsRect"] = ^BOOL(NSDictionary *rectDict1, NSDictionary *rectDict2) { CGRect rect1,rect2; [JPCGGeometry rectStruct:&rect1 ofDict:rectDict1]; [JPCGGeometry rectStruct:&rect2 ofDict:rectDict2]; return CGRectIntersectsRect(rect1, rect2); }; } #if CGFLOAT_IS_DOUBLE #define CGFloatValue doubleValue #else #define CGFloatValue floatValue #endif + (void)rectStruct:(CGRect *)rect ofDict:(NSDictionary *)dict { CGPoint point; CGSize size; point.x = [dict[@"x"] CGFloatValue]; point.y = [dict[@"y"] CGFloatValue]; size.width = [dict[@"width"] CGFloatValue]; size.height = [dict[@"height"] CGFloatValue]; rect->origin = point; rect->size = size; } + (void)pointStruct:(CGPoint *)point ofDict:(NSDictionary *)dict { point->x = [dict[@"x"] CGFloatValue]; point->y = [dict[@"y"] CGFloatValue]; } + (void)sizeStruct:(CGSize *)size ofDict:(NSDictionary *)dict { size->width = [dict[@"width"] CGFloatValue]; size->height = [dict[@"height"] CGFloatValue]; } + (void)vectorStruct:(CGVector *)vector ofDict:(NSDictionary *)dict { vector->dx = [dict[@"dx"] CGFloatValue]; vector->dy = [dict[@"dy"] CGFloatValue]; } #undef CGFloatValue + (NSDictionary *)rectDictOfStruct:(CGRect *)rect { return @{@"x": @(rect->origin.x), @"y": @(rect->origin.y), @"width": @(rect->size.width), @"height": @(rect->size.height)}; } + (NSDictionary *)sizeDictOfStruct:(CGSize *)size { return @{@"width": @(size->width), @"height": @(size->height)}; } + (NSDictionary *)pointDictOfStruct:(CGPoint *)point { return @{@"x": @(point->x), @"y": @(point->y)}; } + (NSDictionary *)vectorDictOfStruct:(CGVector *)vector { return @{@"dx": @(vector->dx), @"dy": @(vector->dy)}; } @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGImage.h ================================================ // // JPCGImage.h // JSPatchDemo // // Created by Albert438 on 15/7/3. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPCGImage : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGImage.m ================================================ // // JPCGImage.m // JSPatchDemo // // Created by Albert438 on 15/7/3. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPCGImage.h" #import #import "JPCGGeometry.h" @implementation JPCGImage + (void)main:(JSContext *)context { context[@"CGImageCreate"] = ^id(size_t width, size_t height, size_t bitsPerComponent, size_t bitsPerPixel, size_t bytesPerRow, JSValue *space, int bitmapInfo, JSValue *provider, NSArray *decodeArray, bool shouldInterpolate, int intent) { if (decodeArray == nil) { CGImageRef createdImage = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel,bytesPerRow, [self formatPointerJSToOC:space], bitmapInfo, [self formatPointerJSToOC:provider], NULL, shouldInterpolate, intent); return [self formatRetainedCFTypeOCToJS:createdImage]; }else { CGFloat *decode = malloc(decodeArray.count * sizeof(CGFloat)); for (int i = 0; i < decodeArray.count; i++) { decode[i] = [decodeArray[i] doubleValue]; } CGImageRef createdImage = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel,bytesPerRow, [self formatPointerJSToOC:space], bitmapInfo, [self formatPointerJSToOC:provider], decode, shouldInterpolate, intent); free(decode); return [self formatRetainedCFTypeOCToJS:createdImage]; } }; context[@"CGImageCreateWithImageInRect"] = ^id(JSValue *image, NSDictionary *rectDict) { CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGImageRef retImage = CGImageCreateWithImageInRect([self formatPointerJSToOC:image], rect); return [self formatRetainedCFTypeOCToJS:retImage]; }; context[@"CGImageCreateWithMask"] = ^id(JSValue *image, JSValue *mask) { CGImageRef createdImage = CGImageCreateWithMask([self formatPointerJSToOC:image], [self formatPointerJSToOC:mask]); return [self formatRetainedCFTypeOCToJS:createdImage]; }; context[@"CGImageGetAlphaInfo"] = ^CGImageAlphaInfo(JSValue *image) { return CGImageGetAlphaInfo([self formatPointerJSToOC:image]); }; context[@"CGImageGetBitmapInfo"] = ^CGBitmapInfo(JSValue *image) { CGBitmapInfo ret = CGImageGetBitmapInfo([self formatPointerJSToOC:image]); return ret; }; context[@"CGImageGetBitsPerComponent"] = ^size_t(JSValue *image) { return CGImageGetBitsPerComponent([self formatPointerJSToOC:image]); }; context[@"CGImageGetColorSpace"] = ^id(JSValue *image) { CGColorSpaceRef space = CGImageGetColorSpace([self formatPointerJSToOC:image]); return [self formatPointerOCToJS:space]; }; context[@"CGImageGetDataProvider"] = ^id(JSValue *image) { CGDataProviderRef provider = CGImageGetDataProvider([self formatPointerJSToOC:image]); return [self formatPointerOCToJS:provider]; }; context[@"CGImageGetHeight"] = ^size_t(JSValue *image) { return CGImageGetHeight([self formatPointerJSToOC:image]); }; context[@"CGImageGetWidth"] = ^size_t(JSValue *image) { return CGImageGetWidth([self formatPointerJSToOC:image]); }; context[@"CGImageRelease"] = ^void(JSValue *image) { CGImageRelease([self formatPointerJSToOC:image]); }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGPath.h ================================================ // // JPCGPath.h // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPCGPath : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGPath.m ================================================ // // JPCGPath.m // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPCGPath.h" #import "JPCGTransform.h" #import "JPCGGeometry.h" #import @implementation JPCGPath + (void)main:(JSContext *)context { context[@"CGPathAddArc"] = ^void(JSValue *path, NSDictionary *m, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, bool clockwise) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:m]; CGPathAddArc([self formatPointerJSToOC:path], &transform, x, y, radius, startAngle, endAngle, clockwise); }; context[@"CGPathAddArcToPoint"] = ^void(JSValue *path, NSDictionary *m, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat radius) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:m]; CGPathAddArcToPoint([self formatPointerJSToOC:path], &transform, x1, y1, x2, y2, radius); }; context[@"CGPathAddCurveToPoint"] = ^void(JSValue *path, NSDictionary *m, CGFloat cp1x, CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:m]; CGPathAddCurveToPoint([self formatPointerJSToOC:path], &transform, cp1x, cp1y, cp2x, cp2y, x, y); }; context[@"CGPathAddEllipseInRect"] = ^void(JSValue *path, NSDictionary *m, NSDictionary *rectDict) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:m]; CGRect rect; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGPathAddEllipseInRect([self formatPointerJSToOC:path], &transform, rect); }; context[@"CGPathAddLineToPoint"] = ^void(JSValue *path, NSDictionary *m, CGFloat x, CGFloat y) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:m]; CGPathAddLineToPoint([self formatPointerJSToOC:path], &transform, x, y); }; context[@"CGPathAddLines"] = ^void(JSValue *path, NSDictionary *m, NSArray *pointsArray, size_t count) { CGPoint *points = malloc(sizeof(CGPoint) * count); for (int i = 0; i < count; i++) { CGPoint point; [JPCGGeometry pointStruct:&point ofDict:pointsArray[i]]; points[i] = point; } CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:m]; CGPathAddLines([self formatPointerJSToOC:path], &transform, points, count); free(points); }; context[@"CGPathAddRect"] = ^void(JSValue *path, NSDictionary *m, NSDictionary *rectDict) { CGRect rect; CGAffineTransform transform; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; [JPCGTransform transStruct:&transform ofDict:m]; CGPathAddRect([self formatPointerJSToOC:path], &transform, rect); }; context[@"CGPathCreateMutable"] = ^id() { CGMutablePathRef path = CGPathCreateMutable(); return [self formatRetainedCFTypeOCToJS:path]; }; context[@"CGPathMoveToPoint"] = ^void(JSValue *path, NSDictionary *m, CGFloat x, CGFloat y) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:m]; CGPathMoveToPoint([self formatPointerJSToOC:path], &transform, x, y); }; context[@"CGPathCloseSubpath"] = ^void(JSValue *path) { CGPathCloseSubpath([self formatPointerJSToOC:path]); }; context[@"CGPathContainsPoint"] = ^BOOL(JSValue *path, NSDictionary *m, NSDictionary *pointDict, bool eoFill) { CGAffineTransform transform; [JPCGTransform transStruct:&transform ofDict:m]; CGPoint point; [JPCGGeometry pointDictOfStruct:&point]; return CGPathContainsPoint([self formatPointerJSToOC:path], &transform, point, eoFill); }; context[@"CGPathCreateWithEllipseInRect"] = ^id(NSDictionary *rectDict, NSDictionary *transformDict) { CGRect rect; CGAffineTransform transform; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; [JPCGTransform transStruct:&transform ofDict:transformDict]; CGPathRef path = CGPathCreateWithEllipseInRect(rect, &transform); return [self formatRetainedCFTypeOCToJS:(void *)path]; }; context[@"CGPathGetPathBoundingBox"] = ^NSDictionary *(JSValue *path) { CGRect rect = CGPathGetPathBoundingBox([self formatPointerJSToOC:path]); return [JPCGGeometry rectDictOfStruct:&rect]; }; context[@"CGPathRelease"] = ^void(JSValue *path) { CGPathRelease([self formatPointerJSToOC:path]); }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGTransform.h ================================================ // // JPCGTransform.h // JSPatchDemo // // Created by bang on 15/6/30. // Copyright (c) 2015 bang. All rights reserved. // #import "JPEngine.h" #import @interface JPCGTransform : JPExtension + (NSDictionary *)transDictOfStruct:(CGAffineTransform *)trans; + (void)transStruct:(CGAffineTransform *)trans ofDict:(NSDictionary *)dict; @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCGTransform.m ================================================ // // JPCGTransform.m // JSPatchDemo // // Created by bang on 15/6/30. // Copyright (c) 2015 bang. All rights reserved. // #import "JPCGTransform.h" #import "JPCGGeometry.h" #define TRANSFORM_DEFINE @{ \ @"name": @"CGAffineTransform", \ @"types": @"FFFFFF", \ @"keys": @[@"a", @"b", @"c", @"d", @"tx", @"ty"] \ } @implementation JPCGTransform static NSDictionary *transformStructDefine; + (void)main:(JSContext *)context { transformStructDefine = TRANSFORM_DEFINE; [JPEngine defineStruct:transformStructDefine]; context[@"CGAffineTransformMakeTranslation"] = ^id(CGFloat tx, CGFloat ty) { CGAffineTransform trans = CGAffineTransformMakeTranslation(tx, ty); return [self getDictOfStruct:&trans structDefine:transformStructDefine]; }; context[@"CGAffineTransformMakeRotation"] = ^id(CGFloat angle) { CGAffineTransform trans = CGAffineTransformMakeRotation(angle); return [self getDictOfStruct:&trans structDefine:transformStructDefine]; }; context[@"CGAffineTransformMakeScale"] = ^id(CGFloat sx, CGFloat sy) { CGAffineTransform trans = CGAffineTransformMakeScale(sx, sy); return [self getDictOfStruct:&trans structDefine:transformStructDefine]; }; context[@"CGAffineTransformTranslate"] = ^id(NSDictionary *transformDict, CGFloat tx, CGFloat ty) { CGAffineTransform trans; [self getStructDataWidthDict:&trans dict:transformDict structDefine:transformStructDefine]; CGAffineTransform translatedTransform = CGAffineTransformTranslate(trans, tx, ty); return [self getDictOfStruct:&translatedTransform structDefine:transformStructDefine]; }; context[@"CGAffineTransformScale"] = ^id(NSDictionary *transformDict, CGFloat sx, CGFloat sy) { CGAffineTransform trans; [self getStructDataWidthDict:&trans dict:transformDict structDefine:transformStructDefine]; CGAffineTransform translatedTransform = CGAffineTransformScale(trans, sx, sy); return [self getDictOfStruct:&translatedTransform structDefine:transformStructDefine]; }; context[@"CGAffineTransformRotate"] = ^id(NSDictionary *transformDict, CGFloat angle) { CGAffineTransform trans; [self getStructDataWidthDict:&trans dict:transformDict structDefine:transformStructDefine]; CGAffineTransform translatedTransform = CGAffineTransformRotate(trans, angle); return [self getDictOfStruct:&translatedTransform structDefine:transformStructDefine]; }; context[@"CGRectApplyAffineTransform"] = ^NSDictionary *(NSDictionary *rectDict, NSDictionary *transformDict) { CGRect rect; CGAffineTransform transform; [self getStructDataWidthDict:&transform dict:transformDict structDefine:transformStructDefine]; [JPCGGeometry rectStruct:&rect ofDict:rectDict]; CGRect retRect = CGRectApplyAffineTransform(rect, transform); return [JPCGGeometry rectDictOfStruct:&retRect]; }; } + (NSDictionary *)transDictOfStruct:(CGAffineTransform *)trans { return [self getDictOfStruct:trans structDefine:transformStructDefine ? transformStructDefine : TRANSFORM_DEFINE]; } + (void)transStruct:(CGAffineTransform *)trans ofDict:(NSDictionary *)dict { [self getStructDataWidthDict:trans dict:dict structDefine:transformStructDefine ? transformStructDefine : TRANSFORM_DEFINE]; } @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCoreGraphics.h ================================================ // // JPCoreGraphics.h // JSPatchDemo // // Created by Albert438 on 15/7/3. // Copyright © 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPCoreGraphics : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/CoreGraphics/JPCoreGraphics.m ================================================ // // JPCoreGraphics.m // JSPatchDemo // // Created by Albert438 on 15/7/3. // Copyright © 2015年 bang. All rights reserved. // #import "JPCoreGraphics.h" #import "JPEngine.h" @implementation JPCoreGraphics + (void)main:(JSContext *)context { NSArray *extensionArray = @[@"JPCGTransform", @"JPCGContext", @"JPCGGeometry", @"JPCGBitmapContext", @"JPCGColor", @"JPCGImage", @"JPCGPath"]; [JPEngine addExtensions:extensionArray]; } @end ================================================ FILE: Extensions/JPCFunctionBinder/UIKit/JPUIGeometry.h ================================================ // // JPUIGeometry.h // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPUIGeometry : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/UIKit/JPUIGeometry.m ================================================ // // JPUIGeometry.m // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPUIGeometry.h" #import "JPCGGeometry.h" #import @implementation JPUIGeometry + (void)main:(JSContext *)context { [JPEngine defineStruct:@{@"name": @"UIEdgeInsets", @"types": @"FFFF", @"keys": @[@"top", @"left", @"bottom", @"right"] }]; [JPEngine defineStruct:@{@"name": @"UIOffset", @"types": @"FF", @"keys": @[@"horizontal", @"vertical"] }]; context[@"CGRectFromString"] = ^NSDictionary *(NSString *string) { CGRect rect = CGRectFromString(string); return [JPCGGeometry rectDictOfStruct:&rect]; }; context[@"CGSizeFromString"] = ^NSDictionary *(NSString *string) { CGSize size = CGSizeFromString(string); return [JPCGGeometry sizeDictOfStruct:&size]; }; context[@"CGPointFromString"] = ^NSDictionary *(NSString *string) { CGPoint point = CGPointFromString(string); return [JPCGGeometry pointDictOfStruct:&point]; }; context[@"CGVectorFromString"] = ^NSDictionary *(NSString *string) { CGVector vector = CGVectorFromString(string); return [JPCGGeometry vectorDictOfStruct:&vector]; }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/UIKit/JPUIGraphics.h ================================================ // // UIGraphics.h // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPUIGraphics : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/UIKit/JPUIGraphics.m ================================================ // // UIGraphics.m // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPUIGraphics.h" #import "JPCGGeometry.h" #import @implementation JPUIGraphics + (void)main:(JSContext *)context { context[@"UIGraphicsGetCurrentContext"] = ^id() { CGContextRef c = UIGraphicsGetCurrentContext(); return [self formatPointerOCToJS:c]; }; context[@"UIGraphicsBeginImageContext"] = ^void(NSDictionary *sizeDict) { CGSize size; [JPCGGeometry sizeStruct:&size ofDict:sizeDict]; UIGraphicsBeginImageContext(size); }; context[@"UIGraphicsBeginImageContextWithOptions"] = ^void(NSDictionary *sizeDict, BOOL opaque, CGFloat scale) { CGSize size; [JPCGGeometry sizeStruct:&size ofDict:sizeDict]; UIGraphicsBeginImageContextWithOptions(size, opaque, scale); }; context[@"UIGraphicsGetImageFromCurrentImageContext"] = ^id() { UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); return [self formatOCToJS:image]; }; context[@"UIGraphicsEndImageContext"] = ^void() { UIGraphicsEndImageContext(); }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/UIKit/JPUIImage.h ================================================ // // JPUIImage.h // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPUIImage : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/UIKit/JPUIImage.m ================================================ // // JPUIImage.m // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPUIImage.h" #import @implementation JPUIImage + (void)main:(JSContext *)context { context[@"UIImageJPEGRepresentation"] = ^id(JSValue *jsVal, CGFloat compressionQuality) { UIImage *image = [self formatJSToOC:jsVal]; NSData *data = UIImageJPEGRepresentation(image, compressionQuality); return [self formatOCToJS:data]; }; context[@"UIImagePNGRepresentation"] = ^id(JSValue *jsVal) { UIImage *image = [self formatJSToOC:jsVal]; NSData *data = UIImagePNGRepresentation(image); return [self formatOCToJS:data]; }; } @end ================================================ FILE: Extensions/JPCFunctionBinder/UIKit/JPUIKit.h ================================================ // // JPUIKit.h // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPEngine.h" @interface JPUIKit : JPExtension @end ================================================ FILE: Extensions/JPCFunctionBinder/UIKit/JPUIKit.m ================================================ // // JPUIKit.m // JSPatchDemo // // Created by Albert438 on 15/7/6. // Copyright (c) 2015年 bang. All rights reserved. // #import "JPUIKit.h" @implementation JPUIKit + (void)main:(JSContext *)context { NSArray *extensionArray = @[@"JPUIGraphics", @"JPUIGeometry", @"JPUIImage"]; [JPEngine addExtensions:extensionArray]; } @end ================================================ FILE: Extensions/JPCleaner.h ================================================ // // JPReverter.h // JSPatchDemo // // Created by bang on 2/4/16. // Copyright © 2016 bang. All rights reserved. // #import "JPEngine.h" @interface JPCleaner : JPExtension + (void)cleanAll; + (void)cleanClass:(NSString *)className; @end ================================================ FILE: Extensions/JPCleaner.m ================================================ // // JPReverter.m // JSPatchDemo // // Created by bang on 2/4/16. // Copyright © 2016 bang. All rights reserved. // #import "JPCleaner.h" #import #import @implementation JPCleaner #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" + (void)cleanAll { [self cleanClass:nil]; [[self includedScriptPaths] removeAllObjects]; } + (void)cleanClass:(NSString *)className { NSDictionary *methodsDict = [JPExtension overideMethods]; for (Class cls in methodsDict.allKeys) { if (className && ![className isEqualToString:NSStringFromClass(cls)]) { continue; } for (NSString *jpSelectorName in [methodsDict[cls] allKeys]) { NSString *selectorName = [jpSelectorName substringFromIndex:3]; NSString *originalSelectorName = [NSString stringWithFormat:@"ORIG%@", selectorName]; SEL selector = NSSelectorFromString(selectorName); SEL originalSelector = NSSelectorFromString(originalSelectorName); IMP originalImp = class_respondsToSelector(cls, originalSelector) ? class_getMethodImplementation(cls, originalSelector) : NULL; Method method = class_getInstanceMethod(cls, originalSelector); char *typeDescription = (char *)method_getTypeEncoding(method); class_replaceMethod(cls, selector, originalImp, typeDescription); } char *typeDescription = (char *)method_getTypeEncoding(class_getInstanceMethod(cls, @selector(forwardInvocation:))); IMP forwardInvocationIMP = class_getMethodImplementation(cls, @selector(ORIGforwardInvocation:)); //forwardInvocationIMP will be _objc_msgForward if ORIGforwardInvocation: doesn't exist if (forwardInvocationIMP == _objc_msgForward) { class_replaceMethod(cls, @selector(forwardInvocation:), NULL, typeDescription); } else { class_replaceMethod(cls, @selector(forwardInvocation:), forwardInvocationIMP, typeDescription); } } } #pragma clang diagnostic pop @end ================================================ FILE: Extensions/JPDispatch.h ================================================ // // JPDispatch.h // JSPatchDemo // // Created by bang on 10/9/16. // Copyright © 2016 bang. All rights reserved. // #import #import "JPEngine.h" @interface JPDispatch : JPExtension @end ================================================ FILE: Extensions/JPDispatch.m ================================================ // // JPDispatch.m // JSPatchDemo // // Created by bang on 10/9/16. // Copyright © 2016 bang. All rights reserved. // #import "JPDispatch.h" @implementation JPDispatch + (void)main:(JSContext *)context { /* CONSTANT */ context[@"_DISPATCH_QUEUE_PRIORITY_BACKGROUND"] = ^id() { return @(DISPATCH_QUEUE_PRIORITY_BACKGROUND); }; context[@"_DISPATCH_TIME_FOREVER"] = ^id() { return @(DISPATCH_TIME_FOREVER); }; context[@"_DISPATCH_TIME_NOW"] = ^id() { return @(DISPATCH_TIME_NOW); }; context[@"_DISPATCH_QUEUE_CONCURRENT"] = ^id() { return [self formatPointerOCToJS:(__bridge void *)DISPATCH_QUEUE_CONCURRENT]; }; context[@"dispatch_time"] = ^id(double second) { return @(dispatch_time(DISPATCH_TIME_NOW, second * NSEC_PER_SEC)); }; /* queue */ context[@"dispatch_get_global_queue"] = ^id(long identifier, unsigned long flags) { return dispatch_get_global_queue(identifier, flags); }; context[@"dispatch_get_main_queue"] = ^id(long identifier, unsigned long flags) { return dispatch_get_main_queue(); }; context[@"dispatch_queue_create"] = ^id(NSString *queueName, JSValue *attrJS) { dispatch_queue_attr_t attr = [self formatPointerJSToOC:attrJS]; dispatch_queue_t queue = dispatch_queue_create([queueName cStringUsingEncoding:NSUTF8StringEncoding], attr); return queue; }; /* dispatch & dispatch_barrier */ context[@"dispatch_async"] = ^void(JSValue *queue, JSValue *cb) { dispatch_async([self formatJSToOC:queue], ^{ [cb callWithArguments:nil]; }); }; context[@"dispatch_sync"] = ^void(JSValue *queue, JSValue *cb) { dispatch_sync([self formatJSToOC:queue], ^{ [cb callWithArguments:nil]; }); }; context[@"dispatch_barrier_async"] = ^void(JSValue *queue, JSValue *cb) { dispatch_barrier_async([self formatJSToOC:queue], ^{ [cb callWithArguments:nil]; }); }; context[@"dispatch_barrier_sync"] = ^void(JSValue *queue, JSValue *cb) { dispatch_barrier_sync([self formatJSToOC:queue], ^{ [cb callWithArguments:nil]; }); }; context[@"dispatch_apply"] = ^void(size_t iterations, JSValue *queue, JSValue *cb) { dispatch_apply(iterations, [self formatJSToOC:queue], ^(size_t index) { [cb callWithArguments:@[@(index)]]; }); }; /* dispatch_group */ context[@"dispatch_group_create"] = ^id() { dispatch_group_t group = dispatch_group_create(); return group; }; context[@"dispatch_group_async"] = ^void(JSValue *group, JSValue *queue, JSValue *cb) { dispatch_group_async([self formatJSToOC:group], [self formatJSToOC:queue], ^{ [cb callWithArguments:nil]; }); }; context[@"dispatch_group_wait"] = ^void(JSValue *group, uint64_t dispatch_time) { dispatch_group_wait([self formatJSToOC:group], dispatch_time); }; context[@"dispatch_group_notify"] = ^void(JSValue *group, JSValue *queue, JSValue *cb) { dispatch_group_notify([self formatJSToOC:group], [self formatJSToOC:queue], ^{ [cb callWithArguments:nil]; }); }; context[@"dispatch_group_enter"] = ^void(JSValue *group) { dispatch_group_enter([self formatJSToOC:group]); }; context[@"dispatch_group_leave"] = ^void(JSValue *group) { dispatch_group_leave([self formatJSToOC:group]); }; [context evaluateScript:@" \ global.DISPATCH_QUEUE_PRIORITY_HIGH = 2; \ global.DISPATCH_QUEUE_PRIORITY_DEFAULT = 0; \ global.DISPATCH_QUEUE_PRIORITY_LOW = -2; \ global.DISPATCH_QUEUE_PRIORITY_BACKGROUND = _DISPATCH_QUEUE_PRIORITY_BACKGROUND(); \ global.DISPATCH_TIME_NOW = _DISPATCH_TIME_NOW(); \ global.DISPATCH_TIME_FOREVER = _DISPATCH_TIME_FOREVER(); \ global.DISPATCH_QUEUE_CONCURRENT = _DISPATCH_QUEUE_CONCURRENT(); \ global.DISPATCH_QUEUE_SERIAL = 0; \ "]; } @end ================================================ FILE: Extensions/JPLibffi/JPMethodSignature.h ================================================ // // JPMethodSignature.h // JSPatch // // Created by bang on 1/19/17. // Copyright © 2017 bang. All rights reserved. // #import #import "ffi.h" @interface JPMethodSignature : NSObject @property (nonatomic, readonly) NSString *types; @property (nonatomic, readonly) NSArray *argumentTypes; @property (nonatomic, readonly) NSString *returnType; - (instancetype)initWithObjCTypes:(NSString *)objCTypes; - (instancetype)initWithBlockTypeNames:(NSString *)typeNames; + (ffi_type *)ffiTypeWithEncodingChar:(const char *)c; + (NSString *)typeEncodeWithTypeName:(NSString *)typeName; @end ================================================ FILE: Extensions/JPLibffi/JPMethodSignature.m ================================================ // // JPMethodSignature.m // JSPatch // // Created by bang on 1/19/17. // Copyright © 2017 bang. All rights reserved. // #import "JPMethodSignature.h" #import #import "JPEngine.h" @implementation JPMethodSignature { NSString *_typeNames; NSMutableArray *_argumentTypes; NSString *_returnType; NSString *_types; BOOL _isBlock; } - (instancetype)initWithBlockTypeNames:(NSString *)typeNames { self = [super init]; if (self) { _typeNames = typeNames; _isBlock = YES; [self _parseTypeNames]; [self _parse]; } return self; } - (instancetype)initWithObjCTypes:(NSString *)objCTypes { self = [super init]; if (self) { _types = objCTypes; [self _parse]; } return self; } - (void)_parse { _argumentTypes = [[NSMutableArray alloc] init]; for (int i = 0; i < _types.length; i ++) { unichar c = [_types characterAtIndex:i]; NSString *arg; if (isdigit(c)) continue; BOOL skipNext = NO; if (c == '^') { skipNext = YES; arg = [_types substringWithRange:NSMakeRange(i, 2)]; } else if (c == '?') { // @? is block arg = [_types substringWithRange:NSMakeRange(i - 1, 2)]; [_argumentTypes removeLastObject]; } else if (c == '{') { NSUInteger end = [[_types substringFromIndex:i] rangeOfString:@"}"].location + i; arg = [_types substringWithRange:NSMakeRange(i, end - i + 1)]; if (i == 0) { _returnType = arg; } else { [_argumentTypes addObject:arg]; } i = (int)end; continue; } else { arg = [_types substringWithRange:NSMakeRange(i, 1)]; } if (i == 0) { _returnType = arg; } else { [_argumentTypes addObject:arg]; } if (skipNext) i++; } } - (void)_parseTypeNames { NSMutableString *encodeStr = [[NSMutableString alloc] init]; NSArray *typeArr = [_typeNames componentsSeparatedByString:@","]; for (NSInteger i = 0; i < typeArr.count; i++) { NSString *typeStr = trim([typeArr objectAtIndex:i]); NSString *encode = [JPMethodSignature typeEncodeWithTypeName:typeStr]; if (!encode) { NSString *argClassName = trim([typeStr stringByReplacingOccurrencesOfString:@"*" withString:@""]); if (NSClassFromString(argClassName) != NULL) { encode = @"@"; } else { NSCAssert(NO, @"unreconized type %@", typeStr); return; } } [encodeStr appendString:encode]; int length = [JPMethodSignature typeLengthWithTypeName:typeStr]; [encodeStr appendString:[NSString stringWithFormat:@"%d", length]]; if (_isBlock && i == 0) { // Blocks are passed one implicit argument - the block, of type "@?". [encodeStr appendString:@"@?0"]; } } _types = encodeStr; } - (NSArray *)argumentTypes { return _argumentTypes; } - (NSString *)types { return _types; } - (NSString *)returnType { return _returnType; } #pragma mark - class methods + (ffi_type *)ffiTypeWithEncodingChar:(const char *)c { switch (c[0]) { case 'v': return &ffi_type_void; case 'c': return &ffi_type_schar; case 'C': return &ffi_type_uchar; case 's': return &ffi_type_sshort; case 'S': return &ffi_type_ushort; case 'i': return &ffi_type_sint; case 'I': return &ffi_type_uint; case 'l': return &ffi_type_slong; case 'L': return &ffi_type_ulong; case 'q': return &ffi_type_sint64; case 'Q': return &ffi_type_uint64; case 'f': return &ffi_type_float; case 'd': return &ffi_type_double; case 'F': #if CGFLOAT_IS_DOUBLE return &ffi_type_double; #else return &ffi_type_float; #endif case 'B': return &ffi_type_uint8; case '^': return &ffi_type_pointer; case '@': return &ffi_type_pointer; case '#': return &ffi_type_pointer; case '{': { NSString *typeStr = [NSString stringWithCString:c encoding:NSASCIIStringEncoding]; NSUInteger end = [typeStr rangeOfString:@"}"].location; if (end != NSNotFound) { NSString *structName = [typeStr substringWithRange:NSMakeRange(1, end - 1)]; ffi_type *type = malloc(sizeof(ffi_type)); type->alignment = 0; type->size = 0; type->type = FFI_TYPE_STRUCT; NSDictionary *structDefine = [JPExtension registeredStruct][structName]; NSUInteger subTypeCount = [structDefine[@"keys"] count]; NSString *subTypes = structDefine[@"types"]; ffi_type **sub_types = malloc(sizeof(ffi_type *) * (subTypeCount + 1)); for (NSUInteger i=0; isize += sub_types[i]->size; } sub_types[subTypeCount] = NULL; type->elements = sub_types; return type; } } } return NULL; } static NSMutableDictionary *_typeEncodeDict; static NSMutableDictionary *_typeLengthDict; + (int)typeLengthWithTypeName:(NSString *)typeName { if (!typeName) return 0; if (!_typeLengthDict) { _typeLengthDict = [[NSMutableDictionary alloc] init]; #define JP_DEFINE_TYPE_LENGTH(_type) \ [_typeLengthDict setObject:@(sizeof(_type)) forKey:@#_type];\ JP_DEFINE_TYPE_LENGTH(id); JP_DEFINE_TYPE_LENGTH(BOOL); JP_DEFINE_TYPE_LENGTH(int); JP_DEFINE_TYPE_LENGTH(void); JP_DEFINE_TYPE_LENGTH(char); JP_DEFINE_TYPE_LENGTH(short); JP_DEFINE_TYPE_LENGTH(unsigned short); JP_DEFINE_TYPE_LENGTH(unsigned int); JP_DEFINE_TYPE_LENGTH(long); JP_DEFINE_TYPE_LENGTH(unsigned long); JP_DEFINE_TYPE_LENGTH(long long); JP_DEFINE_TYPE_LENGTH(unsigned long long); JP_DEFINE_TYPE_LENGTH(float); JP_DEFINE_TYPE_LENGTH(double); JP_DEFINE_TYPE_LENGTH(bool); JP_DEFINE_TYPE_LENGTH(size_t); JP_DEFINE_TYPE_LENGTH(CGFloat); JP_DEFINE_TYPE_LENGTH(CGSize); JP_DEFINE_TYPE_LENGTH(CGRect); JP_DEFINE_TYPE_LENGTH(CGPoint); JP_DEFINE_TYPE_LENGTH(CGVector); JP_DEFINE_TYPE_LENGTH(NSRange); JP_DEFINE_TYPE_LENGTH(NSInteger); JP_DEFINE_TYPE_LENGTH(Class); JP_DEFINE_TYPE_LENGTH(SEL); JP_DEFINE_TYPE_LENGTH(void*); JP_DEFINE_TYPE_LENGTH(void *); JP_DEFINE_TYPE_LENGTH(id *); } return [_typeLengthDict[typeName] intValue]; } + (NSString *)typeEncodeWithTypeName:(NSString *)typeName { if (!typeName) return nil; if (!_typeEncodeDict) { _typeEncodeDict = [[NSMutableDictionary alloc] init]; #define JP_DEFINE_TYPE_ENCODE_CASE(_type) \ [_typeEncodeDict setObject:[NSString stringWithUTF8String:@encode(_type)] forKey:@#_type];\ JP_DEFINE_TYPE_ENCODE_CASE(id); JP_DEFINE_TYPE_ENCODE_CASE(BOOL); JP_DEFINE_TYPE_ENCODE_CASE(int); JP_DEFINE_TYPE_ENCODE_CASE(void); JP_DEFINE_TYPE_ENCODE_CASE(char); JP_DEFINE_TYPE_ENCODE_CASE(short); JP_DEFINE_TYPE_ENCODE_CASE(unsigned short); JP_DEFINE_TYPE_ENCODE_CASE(unsigned int); JP_DEFINE_TYPE_ENCODE_CASE(long); JP_DEFINE_TYPE_ENCODE_CASE(unsigned long); JP_DEFINE_TYPE_ENCODE_CASE(long long); JP_DEFINE_TYPE_ENCODE_CASE(unsigned long long); JP_DEFINE_TYPE_ENCODE_CASE(float); JP_DEFINE_TYPE_ENCODE_CASE(double); JP_DEFINE_TYPE_ENCODE_CASE(bool); JP_DEFINE_TYPE_ENCODE_CASE(size_t); JP_DEFINE_TYPE_ENCODE_CASE(CGFloat); JP_DEFINE_TYPE_ENCODE_CASE(CGSize); JP_DEFINE_TYPE_ENCODE_CASE(CGRect); JP_DEFINE_TYPE_ENCODE_CASE(CGPoint); JP_DEFINE_TYPE_ENCODE_CASE(CGVector); JP_DEFINE_TYPE_ENCODE_CASE(NSRange); JP_DEFINE_TYPE_ENCODE_CASE(NSInteger); JP_DEFINE_TYPE_ENCODE_CASE(Class); JP_DEFINE_TYPE_ENCODE_CASE(SEL); JP_DEFINE_TYPE_ENCODE_CASE(void*); JP_DEFINE_TYPE_ENCODE_CASE(void *); [_typeEncodeDict setObject:@"@?" forKey:@"block"]; [_typeEncodeDict setObject:@"^@" forKey:@"id*"]; } return _typeEncodeDict[typeName]; } static NSString *trim(NSString *string) { return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; } @end ================================================ FILE: Extensions/JPLibffi/libffi/ffi.h ================================================ #ifdef __arm64__ #include "ffi_arm64.h" #endif #ifdef __i386__ #include "ffi_i386.h" #endif #ifdef __arm__ #include "ffi_arm.h" #endif #ifdef __x86_64__ #include "ffi_x86_64.h" #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffi_arm.h ================================================ /* -----------------------------------------------------------------*-C-*- libffi 3.99999 - Copyright (c) 2011, 2014 Anthony Green - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ /* ------------------------------------------------------------------- Most of the API is documented in doc/libffi.texi. The raw API is designed to bypass some of the argument packing and unpacking on architectures for which it can be avoided. Routines are provided to emulate the raw API if the underlying platform doesn't allow faster implementation. More details on the raw API can be found in: http://gcc.gnu.org/ml/java/1999-q3/msg00138.html and http://gcc.gnu.org/ml/java/1999-q3/msg00174.html -------------------------------------------------------------------- */ #ifndef LIBFFI_H #define LIBFFI_H #ifdef __cplusplus extern "C" { #endif /* Specify which architecture libffi is configured for. */ #ifndef ARM #define ARM #endif /* ---- System configuration information --------------------------------- */ #include "ffitarget.h" #ifndef LIBFFI_ASM #if defined(_MSC_VER) && !defined(__clang__) #define __attribute__(X) #endif #include #include /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). But we can find it either under the correct ANSI name, or under GNU C's internal name. */ #define FFI_64_BIT_MAX 9223372036854775807 #ifdef LONG_LONG_MAX # define FFI_LONG_LONG_MAX LONG_LONG_MAX #else # ifdef LLONG_MAX # define FFI_LONG_LONG_MAX LLONG_MAX # ifdef _AIX52 /* or newer has C99 LLONG_MAX */ # undef FFI_64_BIT_MAX # define FFI_64_BIT_MAX 9223372036854775807LL # endif /* _AIX52 or newer */ # else # ifdef __GNUC__ # define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ # endif # ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */ # ifndef __PPC64__ # if defined (__IBMC__) || defined (__IBMCPP__) # define FFI_LONG_LONG_MAX LONGLONG_MAX # endif # endif /* __PPC64__ */ # undef FFI_64_BIT_MAX # define FFI_64_BIT_MAX 9223372036854775807LL # endif # endif #endif /* The closure code assumes that this works on pointers, i.e. a size_t can hold a pointer. */ typedef struct _ffi_type { size_t size; unsigned short alignment; unsigned short type; struct _ffi_type **elements; } ffi_type; #ifndef LIBFFI_HIDE_BASIC_TYPES #if SCHAR_MAX == 127 # define ffi_type_uchar ffi_type_uint8 # define ffi_type_schar ffi_type_sint8 #else #error "char size not supported" #endif #if SHRT_MAX == 32767 # define ffi_type_ushort ffi_type_uint16 # define ffi_type_sshort ffi_type_sint16 #elif SHRT_MAX == 2147483647 # define ffi_type_ushort ffi_type_uint32 # define ffi_type_sshort ffi_type_sint32 #else #error "short size not supported" #endif #if INT_MAX == 32767 # define ffi_type_uint ffi_type_uint16 # define ffi_type_sint ffi_type_sint16 #elif INT_MAX == 2147483647 # define ffi_type_uint ffi_type_uint32 # define ffi_type_sint ffi_type_sint32 #elif INT_MAX == 9223372036854775807 # define ffi_type_uint ffi_type_uint64 # define ffi_type_sint ffi_type_sint64 #else #error "int size not supported" #endif #if LONG_MAX == 2147483647 # if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX #error "no 64-bit data type supported" # endif #elif LONG_MAX != FFI_64_BIT_MAX #error "long size not supported" #endif #if LONG_MAX == 2147483647 # define ffi_type_ulong ffi_type_uint32 # define ffi_type_slong ffi_type_sint32 #elif LONG_MAX == FFI_64_BIT_MAX # define ffi_type_ulong ffi_type_uint64 # define ffi_type_slong ffi_type_sint64 #else #error "long size not supported" #endif /* Need minimal decorations for DLLs to works on Windows. GCC has autoimport and autoexport. Rely on Libtool to help MSVC export from a DLL, but always declare data to be imported for MSVC clients. This costs an extra indirection for MSVC clients using the static version of the library, but don't worry about that. Besides, as a workaround, they can define FFI_BUILDING if they *know* they are going to link with the static library. */ #if defined _MSC_VER && !defined FFI_BUILDING #define FFI_EXTERN extern __declspec(dllimport) #else #define FFI_EXTERN extern #endif /* These are defined in types.c. */ FFI_EXTERN ffi_type ffi_type_void; FFI_EXTERN ffi_type ffi_type_uint8; FFI_EXTERN ffi_type ffi_type_sint8; FFI_EXTERN ffi_type ffi_type_uint16; FFI_EXTERN ffi_type ffi_type_sint16; FFI_EXTERN ffi_type ffi_type_uint32; FFI_EXTERN ffi_type ffi_type_sint32; FFI_EXTERN ffi_type ffi_type_uint64; FFI_EXTERN ffi_type ffi_type_sint64; FFI_EXTERN ffi_type ffi_type_float; FFI_EXTERN ffi_type ffi_type_double; FFI_EXTERN ffi_type ffi_type_pointer; #if 0 FFI_EXTERN ffi_type ffi_type_longdouble; #else #define ffi_type_longdouble ffi_type_double #endif #ifdef FFI_TARGET_HAS_COMPLEX_TYPE FFI_EXTERN ffi_type ffi_type_complex_float; FFI_EXTERN ffi_type ffi_type_complex_double; #if 0 FFI_EXTERN ffi_type ffi_type_complex_longdouble; #else #define ffi_type_complex_longdouble ffi_type_complex_double #endif #endif #endif /* LIBFFI_HIDE_BASIC_TYPES */ typedef enum { FFI_OK = 0, FFI_BAD_TYPEDEF, FFI_BAD_ABI } ffi_status; typedef struct { ffi_abi abi; unsigned nargs; ffi_type **arg_types; ffi_type *rtype; unsigned bytes; unsigned flags; #ifdef FFI_EXTRA_CIF_FIELDS FFI_EXTRA_CIF_FIELDS; #endif } ffi_cif; /* ---- Definitions for the raw API -------------------------------------- */ #ifndef FFI_SIZEOF_ARG # if LONG_MAX == 2147483647 # define FFI_SIZEOF_ARG 4 # elif LONG_MAX == FFI_64_BIT_MAX # define FFI_SIZEOF_ARG 8 # endif #endif #ifndef FFI_SIZEOF_JAVA_RAW # define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG #endif typedef union { ffi_sarg sint; ffi_arg uint; float flt; char data[FFI_SIZEOF_ARG]; void* ptr; } ffi_raw; #if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8 /* This is a special case for mips64/n32 ABI (and perhaps others) where sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */ typedef union { signed int sint; unsigned int uint; float flt; char data[FFI_SIZEOF_JAVA_RAW]; void* ptr; } ffi_java_raw; #else typedef ffi_raw ffi_java_raw; #endif void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue); void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); size_t ffi_raw_size (ffi_cif *cif); /* This is analogous to the raw API, except it uses Java parameter packing, even on 64-bit machines. I.e. on 64-bit machines longs and doubles are followed by an empty 64-bit word. */ void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_java_raw *avalue); void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); size_t ffi_java_raw_size (ffi_cif *cif); /* ---- Definitions for closures ----------------------------------------- */ #if FFI_CLOSURES #ifdef _MSC_VER __declspec(align(8)) #endif typedef struct { #if 1 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; } ffi_closure #ifdef __GNUC__ __attribute__((aligned (8))) #endif ; #ifndef __GNUC__ # ifdef __sgi # pragma pack 0 # endif #endif void *ffi_closure_alloc (size_t size, void **code); void ffi_closure_free (void *); ffi_status ffi_prep_closure (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data) __attribute__((deprecated ("use ffi_prep_closure_loc instead"))); ffi_status ffi_prep_closure_loc (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void*codeloc); #ifdef __sgi # pragma pack 8 #endif typedef struct { #if 1 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* If this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the transaltion, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_raw*,void*); void *user_data; } ffi_raw_closure; typedef struct { #if 1 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* If this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the translation, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*); void *user_data; } ffi_java_raw_closure; ffi_status ffi_prep_raw_closure (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data); ffi_status ffi_prep_raw_closure_loc (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data, void *codeloc); ffi_status ffi_prep_java_raw_closure (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data); ffi_status ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data, void *codeloc); #endif /* FFI_CLOSURES */ #if FFI_GO_CLOSURES typedef struct { void *tramp; ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); } ffi_go_closure; ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*)); void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure); #endif /* FFI_GO_CLOSURES */ /* ---- Public interface definition -------------------------------------- */ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes); ffi_status ffi_prep_cif_var(ffi_cif *cif, ffi_abi abi, unsigned int nfixedargs, unsigned int ntotalargs, ffi_type *rtype, ffi_type **atypes); void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets); /* Useful for eliminating compiler warnings. */ #define FFI_FN(f) ((void (*)(void))f) /* ---- Definitions shared with assembly code ---------------------------- */ #endif /* If these change, update src/mips/ffitarget.h. */ #define FFI_TYPE_VOID 0 #define FFI_TYPE_INT 1 #define FFI_TYPE_FLOAT 2 #define FFI_TYPE_DOUBLE 3 #if 0 #define FFI_TYPE_LONGDOUBLE 4 #else #define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE #endif #define FFI_TYPE_UINT8 5 #define FFI_TYPE_SINT8 6 #define FFI_TYPE_UINT16 7 #define FFI_TYPE_SINT16 8 #define FFI_TYPE_UINT32 9 #define FFI_TYPE_SINT32 10 #define FFI_TYPE_UINT64 11 #define FFI_TYPE_SINT64 12 #define FFI_TYPE_STRUCT 13 #define FFI_TYPE_POINTER 14 #define FFI_TYPE_COMPLEX 15 /* This should always refer to the last type code (for sanity checks). */ #define FFI_TYPE_LAST FFI_TYPE_COMPLEX #ifdef __cplusplus } #endif #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffi_arm64.h ================================================ /* -----------------------------------------------------------------*-C-*- libffi 3.99999 - Copyright (c) 2011, 2014 Anthony Green - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ /* ------------------------------------------------------------------- Most of the API is documented in doc/libffi.texi. The raw API is designed to bypass some of the argument packing and unpacking on architectures for which it can be avoided. Routines are provided to emulate the raw API if the underlying platform doesn't allow faster implementation. More details on the raw API can be found in: http://gcc.gnu.org/ml/java/1999-q3/msg00138.html and http://gcc.gnu.org/ml/java/1999-q3/msg00174.html -------------------------------------------------------------------- */ #ifndef LIBFFI_H #define LIBFFI_H #ifdef __cplusplus extern "C" { #endif /* Specify which architecture libffi is configured for. */ #ifndef AARCH64 #define AARCH64 #endif /* ---- System configuration information --------------------------------- */ #include "ffitarget.h" #ifndef LIBFFI_ASM #if defined(_MSC_VER) && !defined(__clang__) #define __attribute__(X) #endif #include #include /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). But we can find it either under the correct ANSI name, or under GNU C's internal name. */ #define FFI_64_BIT_MAX 9223372036854775807 #ifdef LONG_LONG_MAX # define FFI_LONG_LONG_MAX LONG_LONG_MAX #else # ifdef LLONG_MAX # define FFI_LONG_LONG_MAX LLONG_MAX # ifdef _AIX52 /* or newer has C99 LLONG_MAX */ # undef FFI_64_BIT_MAX # define FFI_64_BIT_MAX 9223372036854775807LL # endif /* _AIX52 or newer */ # else # ifdef __GNUC__ # define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ # endif # ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */ # ifndef __PPC64__ # if defined (__IBMC__) || defined (__IBMCPP__) # define FFI_LONG_LONG_MAX LONGLONG_MAX # endif # endif /* __PPC64__ */ # undef FFI_64_BIT_MAX # define FFI_64_BIT_MAX 9223372036854775807LL # endif # endif #endif /* The closure code assumes that this works on pointers, i.e. a size_t can hold a pointer. */ typedef struct _ffi_type { size_t size; unsigned short alignment; unsigned short type; struct _ffi_type **elements; } ffi_type; #ifndef LIBFFI_HIDE_BASIC_TYPES #if SCHAR_MAX == 127 # define ffi_type_uchar ffi_type_uint8 # define ffi_type_schar ffi_type_sint8 #else #error "char size not supported" #endif #if SHRT_MAX == 32767 # define ffi_type_ushort ffi_type_uint16 # define ffi_type_sshort ffi_type_sint16 #elif SHRT_MAX == 2147483647 # define ffi_type_ushort ffi_type_uint32 # define ffi_type_sshort ffi_type_sint32 #else #error "short size not supported" #endif #if INT_MAX == 32767 # define ffi_type_uint ffi_type_uint16 # define ffi_type_sint ffi_type_sint16 #elif INT_MAX == 2147483647 # define ffi_type_uint ffi_type_uint32 # define ffi_type_sint ffi_type_sint32 #elif INT_MAX == 9223372036854775807 # define ffi_type_uint ffi_type_uint64 # define ffi_type_sint ffi_type_sint64 #else #error "int size not supported" #endif #if LONG_MAX == 2147483647 # if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX #error "no 64-bit data type supported" # endif #elif LONG_MAX != FFI_64_BIT_MAX #error "long size not supported" #endif #if LONG_MAX == 2147483647 # define ffi_type_ulong ffi_type_uint32 # define ffi_type_slong ffi_type_sint32 #elif LONG_MAX == FFI_64_BIT_MAX # define ffi_type_ulong ffi_type_uint64 # define ffi_type_slong ffi_type_sint64 #else #error "long size not supported" #endif /* Need minimal decorations for DLLs to works on Windows. GCC has autoimport and autoexport. Rely on Libtool to help MSVC export from a DLL, but always declare data to be imported for MSVC clients. This costs an extra indirection for MSVC clients using the static version of the library, but don't worry about that. Besides, as a workaround, they can define FFI_BUILDING if they *know* they are going to link with the static library. */ #if defined _MSC_VER && !defined FFI_BUILDING #define FFI_EXTERN extern __declspec(dllimport) #else #define FFI_EXTERN extern #endif /* These are defined in types.c. */ FFI_EXTERN ffi_type ffi_type_void; FFI_EXTERN ffi_type ffi_type_uint8; FFI_EXTERN ffi_type ffi_type_sint8; FFI_EXTERN ffi_type ffi_type_uint16; FFI_EXTERN ffi_type ffi_type_sint16; FFI_EXTERN ffi_type ffi_type_uint32; FFI_EXTERN ffi_type ffi_type_sint32; FFI_EXTERN ffi_type ffi_type_uint64; FFI_EXTERN ffi_type ffi_type_sint64; FFI_EXTERN ffi_type ffi_type_float; FFI_EXTERN ffi_type ffi_type_double; FFI_EXTERN ffi_type ffi_type_pointer; #if 0 FFI_EXTERN ffi_type ffi_type_longdouble; #else #define ffi_type_longdouble ffi_type_double #endif #ifdef FFI_TARGET_HAS_COMPLEX_TYPE FFI_EXTERN ffi_type ffi_type_complex_float; FFI_EXTERN ffi_type ffi_type_complex_double; #if 0 FFI_EXTERN ffi_type ffi_type_complex_longdouble; #else #define ffi_type_complex_longdouble ffi_type_complex_double #endif #endif #endif /* LIBFFI_HIDE_BASIC_TYPES */ typedef enum { FFI_OK = 0, FFI_BAD_TYPEDEF, FFI_BAD_ABI } ffi_status; typedef struct { ffi_abi abi; unsigned nargs; ffi_type **arg_types; ffi_type *rtype; unsigned bytes; unsigned flags; #ifdef FFI_EXTRA_CIF_FIELDS FFI_EXTRA_CIF_FIELDS; #endif } ffi_cif; /* ---- Definitions for the raw API -------------------------------------- */ #ifndef FFI_SIZEOF_ARG # if LONG_MAX == 2147483647 # define FFI_SIZEOF_ARG 4 # elif LONG_MAX == FFI_64_BIT_MAX # define FFI_SIZEOF_ARG 8 # endif #endif #ifndef FFI_SIZEOF_JAVA_RAW # define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG #endif typedef union { ffi_sarg sint; ffi_arg uint; float flt; char data[FFI_SIZEOF_ARG]; void* ptr; } ffi_raw; #if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8 /* This is a special case for mips64/n32 ABI (and perhaps others) where sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */ typedef union { signed int sint; unsigned int uint; float flt; char data[FFI_SIZEOF_JAVA_RAW]; void* ptr; } ffi_java_raw; #else typedef ffi_raw ffi_java_raw; #endif void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue); void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); size_t ffi_raw_size (ffi_cif *cif); /* This is analogous to the raw API, except it uses Java parameter packing, even on 64-bit machines. I.e. on 64-bit machines longs and doubles are followed by an empty 64-bit word. */ void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_java_raw *avalue); void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); size_t ffi_java_raw_size (ffi_cif *cif); /* ---- Definitions for closures ----------------------------------------- */ #if FFI_CLOSURES #ifdef _MSC_VER __declspec(align(8)) #endif typedef struct { #if 1 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; } ffi_closure #ifdef __GNUC__ __attribute__((aligned (8))) #endif ; #ifndef __GNUC__ # ifdef __sgi # pragma pack 0 # endif #endif void *ffi_closure_alloc (size_t size, void **code); void ffi_closure_free (void *); ffi_status ffi_prep_closure (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data) __attribute__((deprecated ("use ffi_prep_closure_loc instead"))); ffi_status ffi_prep_closure_loc (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void*codeloc); #ifdef __sgi # pragma pack 8 #endif typedef struct { #if 1 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* If this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the transaltion, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_raw*,void*); void *user_data; } ffi_raw_closure; typedef struct { #if 1 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* If this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the translation, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*); void *user_data; } ffi_java_raw_closure; ffi_status ffi_prep_raw_closure (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data); ffi_status ffi_prep_raw_closure_loc (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data, void *codeloc); ffi_status ffi_prep_java_raw_closure (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data); ffi_status ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data, void *codeloc); #endif /* FFI_CLOSURES */ #if FFI_GO_CLOSURES typedef struct { void *tramp; ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); } ffi_go_closure; ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*)); void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure); #endif /* FFI_GO_CLOSURES */ /* ---- Public interface definition -------------------------------------- */ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes); ffi_status ffi_prep_cif_var(ffi_cif *cif, ffi_abi abi, unsigned int nfixedargs, unsigned int ntotalargs, ffi_type *rtype, ffi_type **atypes); void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets); /* Useful for eliminating compiler warnings. */ #define FFI_FN(f) ((void (*)(void))f) /* ---- Definitions shared with assembly code ---------------------------- */ #endif /* If these change, update src/mips/ffitarget.h. */ #define FFI_TYPE_VOID 0 #define FFI_TYPE_INT 1 #define FFI_TYPE_FLOAT 2 #define FFI_TYPE_DOUBLE 3 #if 0 #define FFI_TYPE_LONGDOUBLE 4 #else #define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE #endif #define FFI_TYPE_UINT8 5 #define FFI_TYPE_SINT8 6 #define FFI_TYPE_UINT16 7 #define FFI_TYPE_SINT16 8 #define FFI_TYPE_UINT32 9 #define FFI_TYPE_SINT32 10 #define FFI_TYPE_UINT64 11 #define FFI_TYPE_SINT64 12 #define FFI_TYPE_STRUCT 13 #define FFI_TYPE_POINTER 14 #define FFI_TYPE_COMPLEX 15 /* This should always refer to the last type code (for sanity checks). */ #define FFI_TYPE_LAST FFI_TYPE_COMPLEX #ifdef __cplusplus } #endif #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffi_i386.h ================================================ #ifdef __i386__ /* -----------------------------------------------------------------*-C-*- libffi 3.2.1 - Copyright (c) 2011, 2014 Anthony Green - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ /* ------------------------------------------------------------------- The basic API is described in the README file. The raw API is designed to bypass some of the argument packing and unpacking on architectures for which it can be avoided. The closure API allows interpreted functions to be packaged up inside a C function pointer, so that they can be called as C functions, with no understanding on the client side that they are interpreted. It can also be used in other cases in which it is necessary to package up a user specified parameter and a function pointer as a single function pointer. The closure API must be implemented in order to get its functionality, e.g. for use by gij. Routines are provided to emulate the raw API if the underlying platform doesn't allow faster implementation. More details on the raw and cloure API can be found in: http://gcc.gnu.org/ml/java/1999-q3/msg00138.html and http://gcc.gnu.org/ml/java/1999-q3/msg00174.html -------------------------------------------------------------------- */ #ifndef LIBFFI_H #define LIBFFI_H #ifdef __cplusplus extern "C" { #endif /* Specify which architecture libffi is configured for. */ #ifndef X86_DARWIN #define X86_DARWIN #endif /* ---- System configuration information --------------------------------- */ #include "ffitarget.h" #ifndef LIBFFI_ASM #if defined(_MSC_VER) && !defined(__clang__) #define __attribute__(X) #endif #include #include /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). But we can find it either under the correct ANSI name, or under GNU C's internal name. */ #define FFI_64_BIT_MAX 9223372036854775807 #ifdef LONG_LONG_MAX # define FFI_LONG_LONG_MAX LONG_LONG_MAX #else # ifdef LLONG_MAX # define FFI_LONG_LONG_MAX LLONG_MAX # ifdef _AIX52 /* or newer has C99 LLONG_MAX */ # undef FFI_64_BIT_MAX # define FFI_64_BIT_MAX 9223372036854775807LL # endif /* _AIX52 or newer */ # else # ifdef __GNUC__ # define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ # endif # ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */ # ifndef __PPC64__ # if defined (__IBMC__) || defined (__IBMCPP__) # define FFI_LONG_LONG_MAX LONGLONG_MAX # endif # endif /* __PPC64__ */ # undef FFI_64_BIT_MAX # define FFI_64_BIT_MAX 9223372036854775807LL # endif # endif #endif /* The closure code assumes that this works on pointers, i.e. a size_t */ /* can hold a pointer. */ typedef struct _ffi_type { size_t size; unsigned short alignment; unsigned short type; struct _ffi_type **elements; } ffi_type; #ifndef LIBFFI_HIDE_BASIC_TYPES #if SCHAR_MAX == 127 # define ffi_type_uchar ffi_type_uint8 # define ffi_type_schar ffi_type_sint8 #else #error "char size not supported" #endif #if SHRT_MAX == 32767 # define ffi_type_ushort ffi_type_uint16 # define ffi_type_sshort ffi_type_sint16 #elif SHRT_MAX == 2147483647 # define ffi_type_ushort ffi_type_uint32 # define ffi_type_sshort ffi_type_sint32 #else #error "short size not supported" #endif #if INT_MAX == 32767 # define ffi_type_uint ffi_type_uint16 # define ffi_type_sint ffi_type_sint16 #elif INT_MAX == 2147483647 # define ffi_type_uint ffi_type_uint32 # define ffi_type_sint ffi_type_sint32 #elif INT_MAX == 9223372036854775807 # define ffi_type_uint ffi_type_uint64 # define ffi_type_sint ffi_type_sint64 #else #error "int size not supported" #endif #if LONG_MAX == 2147483647 # if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX #error "no 64-bit data type supported" # endif #elif LONG_MAX != FFI_64_BIT_MAX #error "long size not supported" #endif #if LONG_MAX == 2147483647 # define ffi_type_ulong ffi_type_uint32 # define ffi_type_slong ffi_type_sint32 #elif LONG_MAX == FFI_64_BIT_MAX # define ffi_type_ulong ffi_type_uint64 # define ffi_type_slong ffi_type_sint64 #else #error "long size not supported" #endif /* Need minimal decorations for DLLs to works on Windows. */ /* GCC has autoimport and autoexport. Rely on Libtool to */ /* help MSVC export from a DLL, but always declare data */ /* to be imported for MSVC clients. This costs an extra */ /* indirection for MSVC clients using the static version */ /* of the library, but don't worry about that. Besides, */ /* as a workaround, they can define FFI_BUILDING if they */ /* *know* they are going to link with the static library. */ #if defined _MSC_VER && !defined FFI_BUILDING #define FFI_EXTERN extern __declspec(dllimport) #else #define FFI_EXTERN extern #endif /* These are defined in types.c */ FFI_EXTERN ffi_type ffi_type_void; FFI_EXTERN ffi_type ffi_type_uint8; FFI_EXTERN ffi_type ffi_type_sint8; FFI_EXTERN ffi_type ffi_type_uint16; FFI_EXTERN ffi_type ffi_type_sint16; FFI_EXTERN ffi_type ffi_type_uint32; FFI_EXTERN ffi_type ffi_type_sint32; FFI_EXTERN ffi_type ffi_type_uint64; FFI_EXTERN ffi_type ffi_type_sint64; FFI_EXTERN ffi_type ffi_type_float; FFI_EXTERN ffi_type ffi_type_double; FFI_EXTERN ffi_type ffi_type_pointer; #if 1 FFI_EXTERN ffi_type ffi_type_longdouble; #else #define ffi_type_longdouble ffi_type_double #endif #ifdef FFI_TARGET_HAS_COMPLEX_TYPE FFI_EXTERN ffi_type ffi_type_complex_float; FFI_EXTERN ffi_type ffi_type_complex_double; #if 1 FFI_EXTERN ffi_type ffi_type_complex_longdouble; #else #define ffi_type_complex_longdouble ffi_type_complex_double #endif #endif #endif /* LIBFFI_HIDE_BASIC_TYPES */ typedef enum { FFI_OK = 0, FFI_BAD_TYPEDEF, FFI_BAD_ABI } ffi_status; typedef unsigned FFI_TYPE; typedef struct { ffi_abi abi; unsigned nargs; ffi_type **arg_types; ffi_type *rtype; unsigned bytes; unsigned flags; #ifdef FFI_EXTRA_CIF_FIELDS FFI_EXTRA_CIF_FIELDS; #endif } ffi_cif; #if 0 /* Used to adjust size/alignment of ffi types. */ void ffi_prep_types (ffi_abi abi); #endif /* Used internally, but overridden by some architectures */ ffi_status ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, unsigned int isvariadic, unsigned int nfixedargs, unsigned int ntotalargs, ffi_type *rtype, ffi_type **atypes); /* ---- Definitions for the raw API -------------------------------------- */ #ifndef FFI_SIZEOF_ARG # if LONG_MAX == 2147483647 # define FFI_SIZEOF_ARG 4 # elif LONG_MAX == FFI_64_BIT_MAX # define FFI_SIZEOF_ARG 8 # endif #endif #ifndef FFI_SIZEOF_JAVA_RAW # define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG #endif typedef union { ffi_sarg sint; ffi_arg uint; float flt; char data[FFI_SIZEOF_ARG]; void* ptr; } ffi_raw; #if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8 /* This is a special case for mips64/n32 ABI (and perhaps others) where sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */ typedef union { signed int sint; unsigned int uint; float flt; char data[FFI_SIZEOF_JAVA_RAW]; void* ptr; } ffi_java_raw; #else typedef ffi_raw ffi_java_raw; #endif void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue); void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); size_t ffi_raw_size (ffi_cif *cif); /* This is analogous to the raw API, except it uses Java parameter */ /* packing, even on 64-bit machines. I.e. on 64-bit machines */ /* longs and doubles are followed by an empty 64-bit word. */ void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_java_raw *avalue); void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); size_t ffi_java_raw_size (ffi_cif *cif); /* ---- Definitions for closures ----------------------------------------- */ #if FFI_CLOSURES #ifdef _MSC_VER __declspec(align(8)) #endif typedef struct { #if 0 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; #ifdef __GNUC__ } ffi_closure __attribute__((aligned (8))); #else } ffi_closure; # ifdef __sgi # pragma pack 0 # endif #endif void *ffi_closure_alloc (size_t size, void **code); void ffi_closure_free (void *); ffi_status ffi_prep_closure (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data); ffi_status ffi_prep_closure_loc (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void*codeloc); #ifdef __sgi # pragma pack 8 #endif typedef struct { #if 0 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* if this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the transaltion, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_raw*,void*); void *user_data; } ffi_raw_closure; typedef struct { #if 0 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* if this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the transaltion, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*); void *user_data; } ffi_java_raw_closure; ffi_status ffi_prep_raw_closure (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data); ffi_status ffi_prep_raw_closure_loc (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data, void *codeloc); ffi_status ffi_prep_java_raw_closure (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data); ffi_status ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data, void *codeloc); #endif /* FFI_CLOSURES */ /* ---- Public interface definition -------------------------------------- */ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes); ffi_status ffi_prep_cif_var(ffi_cif *cif, ffi_abi abi, unsigned int nfixedargs, unsigned int ntotalargs, ffi_type *rtype, ffi_type **atypes); void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); /* Useful for eliminating compiler warnings */ #define FFI_FN(f) ((void (*)(void))f) /* ---- Definitions shared with assembly code ---------------------------- */ #endif /* If these change, update src/mips/ffitarget.h. */ #define FFI_TYPE_VOID 0 #define FFI_TYPE_INT 1 #define FFI_TYPE_FLOAT 2 #define FFI_TYPE_DOUBLE 3 #if 1 #define FFI_TYPE_LONGDOUBLE 4 #else #define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE #endif #define FFI_TYPE_UINT8 5 #define FFI_TYPE_SINT8 6 #define FFI_TYPE_UINT16 7 #define FFI_TYPE_SINT16 8 #define FFI_TYPE_UINT32 9 #define FFI_TYPE_SINT32 10 #define FFI_TYPE_UINT64 11 #define FFI_TYPE_SINT64 12 #define FFI_TYPE_STRUCT 13 #define FFI_TYPE_POINTER 14 #define FFI_TYPE_COMPLEX 15 /* This should always refer to the last type code (for sanity checks) */ #define FFI_TYPE_LAST FFI_TYPE_COMPLEX #ifdef __cplusplus } #endif #endif #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffi_x86_64.h ================================================ /* -----------------------------------------------------------------*-C-*- libffi 3.99999 - Copyright (c) 2011, 2014 Anthony Green - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ /* ------------------------------------------------------------------- Most of the API is documented in doc/libffi.texi. The raw API is designed to bypass some of the argument packing and unpacking on architectures for which it can be avoided. Routines are provided to emulate the raw API if the underlying platform doesn't allow faster implementation. More details on the raw API can be found in: http://gcc.gnu.org/ml/java/1999-q3/msg00138.html and http://gcc.gnu.org/ml/java/1999-q3/msg00174.html -------------------------------------------------------------------- */ #ifndef LIBFFI_H #define LIBFFI_H #ifdef __cplusplus extern "C" { #endif /* Specify which architecture libffi is configured for. */ #ifndef X86_64 #define X86_64 #endif /* ---- System configuration information --------------------------------- */ #include "ffitarget.h" #ifndef LIBFFI_ASM #if defined(_MSC_VER) && !defined(__clang__) #define __attribute__(X) #endif #include #include /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). But we can find it either under the correct ANSI name, or under GNU C's internal name. */ #define FFI_64_BIT_MAX 9223372036854775807 #ifdef LONG_LONG_MAX # define FFI_LONG_LONG_MAX LONG_LONG_MAX #else # ifdef LLONG_MAX # define FFI_LONG_LONG_MAX LLONG_MAX # ifdef _AIX52 /* or newer has C99 LLONG_MAX */ # undef FFI_64_BIT_MAX # define FFI_64_BIT_MAX 9223372036854775807LL # endif /* _AIX52 or newer */ # else # ifdef __GNUC__ # define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ # endif # ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */ # ifndef __PPC64__ # if defined (__IBMC__) || defined (__IBMCPP__) # define FFI_LONG_LONG_MAX LONGLONG_MAX # endif # endif /* __PPC64__ */ # undef FFI_64_BIT_MAX # define FFI_64_BIT_MAX 9223372036854775807LL # endif # endif #endif /* The closure code assumes that this works on pointers, i.e. a size_t can hold a pointer. */ typedef struct _ffi_type { size_t size; unsigned short alignment; unsigned short type; struct _ffi_type **elements; } ffi_type; #ifndef LIBFFI_HIDE_BASIC_TYPES #if SCHAR_MAX == 127 # define ffi_type_uchar ffi_type_uint8 # define ffi_type_schar ffi_type_sint8 #else #error "char size not supported" #endif #if SHRT_MAX == 32767 # define ffi_type_ushort ffi_type_uint16 # define ffi_type_sshort ffi_type_sint16 #elif SHRT_MAX == 2147483647 # define ffi_type_ushort ffi_type_uint32 # define ffi_type_sshort ffi_type_sint32 #else #error "short size not supported" #endif #if INT_MAX == 32767 # define ffi_type_uint ffi_type_uint16 # define ffi_type_sint ffi_type_sint16 #elif INT_MAX == 2147483647 # define ffi_type_uint ffi_type_uint32 # define ffi_type_sint ffi_type_sint32 #elif INT_MAX == 9223372036854775807 # define ffi_type_uint ffi_type_uint64 # define ffi_type_sint ffi_type_sint64 #else #error "int size not supported" #endif #if LONG_MAX == 2147483647 # if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX #error "no 64-bit data type supported" # endif #elif LONG_MAX != FFI_64_BIT_MAX #error "long size not supported" #endif #if LONG_MAX == 2147483647 # define ffi_type_ulong ffi_type_uint32 # define ffi_type_slong ffi_type_sint32 #elif LONG_MAX == FFI_64_BIT_MAX # define ffi_type_ulong ffi_type_uint64 # define ffi_type_slong ffi_type_sint64 #else #error "long size not supported" #endif /* Need minimal decorations for DLLs to works on Windows. GCC has autoimport and autoexport. Rely on Libtool to help MSVC export from a DLL, but always declare data to be imported for MSVC clients. This costs an extra indirection for MSVC clients using the static version of the library, but don't worry about that. Besides, as a workaround, they can define FFI_BUILDING if they *know* they are going to link with the static library. */ #if defined _MSC_VER && !defined FFI_BUILDING #define FFI_EXTERN extern __declspec(dllimport) #else #define FFI_EXTERN extern #endif /* These are defined in types.c. */ FFI_EXTERN ffi_type ffi_type_void; FFI_EXTERN ffi_type ffi_type_uint8; FFI_EXTERN ffi_type ffi_type_sint8; FFI_EXTERN ffi_type ffi_type_uint16; FFI_EXTERN ffi_type ffi_type_sint16; FFI_EXTERN ffi_type ffi_type_uint32; FFI_EXTERN ffi_type ffi_type_sint32; FFI_EXTERN ffi_type ffi_type_uint64; FFI_EXTERN ffi_type ffi_type_sint64; FFI_EXTERN ffi_type ffi_type_float; FFI_EXTERN ffi_type ffi_type_double; FFI_EXTERN ffi_type ffi_type_pointer; #if 1 FFI_EXTERN ffi_type ffi_type_longdouble; #else #define ffi_type_longdouble ffi_type_double #endif #ifdef FFI_TARGET_HAS_COMPLEX_TYPE FFI_EXTERN ffi_type ffi_type_complex_float; FFI_EXTERN ffi_type ffi_type_complex_double; #if 1 FFI_EXTERN ffi_type ffi_type_complex_longdouble; #else #define ffi_type_complex_longdouble ffi_type_complex_double #endif #endif #endif /* LIBFFI_HIDE_BASIC_TYPES */ typedef enum { FFI_OK = 0, FFI_BAD_TYPEDEF, FFI_BAD_ABI } ffi_status; typedef struct { ffi_abi abi; unsigned nargs; ffi_type **arg_types; ffi_type *rtype; unsigned bytes; unsigned flags; #ifdef FFI_EXTRA_CIF_FIELDS FFI_EXTRA_CIF_FIELDS; #endif } ffi_cif; /* ---- Definitions for the raw API -------------------------------------- */ #ifndef FFI_SIZEOF_ARG # if LONG_MAX == 2147483647 # define FFI_SIZEOF_ARG 4 # elif LONG_MAX == FFI_64_BIT_MAX # define FFI_SIZEOF_ARG 8 # endif #endif #ifndef FFI_SIZEOF_JAVA_RAW # define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG #endif typedef union { ffi_sarg sint; ffi_arg uint; float flt; char data[FFI_SIZEOF_ARG]; void* ptr; } ffi_raw; #if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8 /* This is a special case for mips64/n32 ABI (and perhaps others) where sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */ typedef union { signed int sint; unsigned int uint; float flt; char data[FFI_SIZEOF_JAVA_RAW]; void* ptr; } ffi_java_raw; #else typedef ffi_raw ffi_java_raw; #endif void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue); void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); size_t ffi_raw_size (ffi_cif *cif); /* This is analogous to the raw API, except it uses Java parameter packing, even on 64-bit machines. I.e. on 64-bit machines longs and doubles are followed by an empty 64-bit word. */ void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_java_raw *avalue); void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); size_t ffi_java_raw_size (ffi_cif *cif); /* ---- Definitions for closures ----------------------------------------- */ #if FFI_CLOSURES #ifdef _MSC_VER __declspec(align(8)) #endif typedef struct { #if 0 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; } ffi_closure #ifdef __GNUC__ __attribute__((aligned (8))) #endif ; #ifndef __GNUC__ # ifdef __sgi # pragma pack 0 # endif #endif void *ffi_closure_alloc (size_t size, void **code); void ffi_closure_free (void *); ffi_status ffi_prep_closure (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data) __attribute__((deprecated ("use ffi_prep_closure_loc instead"))); ffi_status ffi_prep_closure_loc (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void*codeloc); #ifdef __sgi # pragma pack 8 #endif typedef struct { #if 0 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* If this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the transaltion, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_raw*,void*); void *user_data; } ffi_raw_closure; typedef struct { #if 0 void *trampoline_table; void *trampoline_table_entry; #else char tramp[FFI_TRAMPOLINE_SIZE]; #endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* If this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the translation, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*); void *user_data; } ffi_java_raw_closure; ffi_status ffi_prep_raw_closure (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data); ffi_status ffi_prep_raw_closure_loc (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data, void *codeloc); ffi_status ffi_prep_java_raw_closure (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data); ffi_status ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), void *user_data, void *codeloc); #endif /* FFI_CLOSURES */ #if FFI_GO_CLOSURES typedef struct { void *tramp; ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); } ffi_go_closure; ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*)); void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue, void *closure); #endif /* FFI_GO_CLOSURES */ /* ---- Public interface definition -------------------------------------- */ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes); ffi_status ffi_prep_cif_var(ffi_cif *cif, ffi_abi abi, unsigned int nfixedargs, unsigned int ntotalargs, ffi_type *rtype, ffi_type **atypes); void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets); /* Useful for eliminating compiler warnings. */ #define FFI_FN(f) ((void (*)(void))f) /* ---- Definitions shared with assembly code ---------------------------- */ #endif /* If these change, update src/mips/ffitarget.h. */ #define FFI_TYPE_VOID 0 #define FFI_TYPE_INT 1 #define FFI_TYPE_FLOAT 2 #define FFI_TYPE_DOUBLE 3 #if 1 #define FFI_TYPE_LONGDOUBLE 4 #else #define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE #endif #define FFI_TYPE_UINT8 5 #define FFI_TYPE_SINT8 6 #define FFI_TYPE_UINT16 7 #define FFI_TYPE_SINT16 8 #define FFI_TYPE_UINT32 9 #define FFI_TYPE_SINT32 10 #define FFI_TYPE_UINT64 11 #define FFI_TYPE_SINT64 12 #define FFI_TYPE_STRUCT 13 #define FFI_TYPE_POINTER 14 #define FFI_TYPE_COMPLEX 15 /* This should always refer to the last type code (for sanity checks). */ #define FFI_TYPE_LAST FFI_TYPE_COMPLEX #ifdef __cplusplus } #endif #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffitarget.h ================================================ #ifdef __arm64__ #include "ffitarget_arm64.h" #endif #ifdef __i386__ #include "ffitarget_i386.h" #endif #ifdef __arm__ #include "ffitarget_arm.h" #endif #ifdef __x86_64__ #include "ffitarget_x86_64.h" #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffitarget_arm.h ================================================ /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012 Anthony Green Copyright (c) 2010 CodeSourcery Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for ARM. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_VFP, FFI_LAST_ABI, #ifdef __ARM_PCS_VFP FFI_DEFAULT_ABI = FFI_VFP, #else FFI_DEFAULT_ABI = FFI_SYSV, #endif } ffi_abi; #endif #define FFI_EXTRA_CIF_FIELDS \ int vfp_used; \ unsigned short vfp_reg_free, vfp_nargs; \ signed char vfp_args[16] \ #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_TARGET_HAS_COMPLEX_TYPE /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 12 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 12 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffitarget_arm64.h ================================================ /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif #ifndef LIBFFI_ASM #ifdef __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE #ifdef __MACH__ #define FFI_TRAMPOLINE_SIZE 16 #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 #else #error "No trampoline table implementation" #endif #else #define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE #endif /* ---- Internal ---- */ #if defined (__APPLE__) #define FFI_TARGET_SPECIFIC_VARIADIC #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs #else /* iOS reserves x18 for the system. Disable Go closures until a new static chain is chosen. */ #define FFI_GO_CLOSURES 1 #endif #define FFI_TARGET_HAS_COMPLEX_TYPE #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffitarget_i386.h ================================================ #ifdef __i386__ /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, Inc. Target configuration macros for x86 and x86-64. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #define FFI_TARGET_HAS_COMPLEX_TYPE /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, /* ---- Intel x86 Win32 ---------- */ #ifdef X86_WIN32 FFI_SYSV, FFI_STDCALL, FFI_THISCALL, FFI_FASTCALL, FFI_MS_CDECL, FFI_PASCAL, FFI_REGISTER, FFI_LAST_ABI, #ifdef _MSC_VER FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_DEFAULT_ABI = FFI_SYSV #endif #elif defined(X86_WIN64) FFI_WIN64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_WIN64 #else /* ---- Intel x86 and AMD x86-64 - */ FFI_SYSV, FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */ FFI_THISCALL, FFI_FASTCALL, FFI_STDCALL, FFI_PASCAL, FFI_REGISTER, FFI_LAST_ABI, #if defined(__i386__) || defined(__i386) FFI_DEFAULT_ABI = FFI_SYSV #else FFI_DEFAULT_ABI = FFI_UNIX64 #endif #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) #define FFI_TRAMPOLINE_SIZE 24 #define FFI_NATIVE_RAW_API 0 #else #ifdef X86_WIN32 #define FFI_TRAMPOLINE_SIZE 52 #else #ifdef X86_WIN64 #define FFI_TRAMPOLINE_SIZE 29 #define FFI_NATIVE_RAW_API 0 #define FFI_NO_RAW_API 1 #else #define FFI_TRAMPOLINE_SIZE 10 #endif #endif #ifndef X86_WIN64 #define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif #endif #endif ================================================ FILE: Extensions/JPLibffi/libffi/ffitarget_x86_64.h ================================================ /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2012, 2014 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, Inc. Target configuration macros for x86 and x86-64. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_H #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." #endif /* ---- System specific configurations ----------------------------------- */ /* For code common to all platforms on x86 and x86_64. */ #define X86_ANY #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif #ifdef X86_WIN64 #define FFI_SIZEOF_ARG 8 #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION #ifndef _MSC_VER #define FFI_TARGET_HAS_COMPLEX_TYPE #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM #ifdef X86_WIN64 #ifdef _MSC_VER typedef unsigned __int64 ffi_arg; typedef __int64 ffi_sarg; #else typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #endif #else #if defined __x86_64__ && defined __ILP32__ #define FFI_SIZEOF_ARG 8 #define FFI_SIZEOF_JAVA_RAW 4 typedef unsigned long long ffi_arg; typedef long long ffi_sarg; #else typedef unsigned long ffi_arg; typedef signed long ffi_sarg; #endif #endif typedef enum ffi_abi { #if defined(X86_WIN64) FFI_FIRST_ABI = 0, FFI_WIN64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_WIN64 #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) FFI_FIRST_ABI = 1, FFI_UNIX64, FFI_WIN64, FFI_EFI64 = FFI_WIN64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_UNIX64 #elif defined(X86_WIN32) FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_STDCALL = 2, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_MS_CDECL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_MS_CDECL #else FFI_FIRST_ABI = 0, FFI_SYSV = 1, FFI_THISCALL = 3, FFI_FASTCALL = 4, FFI_STDCALL = 5, FFI_PASCAL = 6, FFI_REGISTER = 7, FFI_MS_CDECL = 8, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_SYSV #endif } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_GO_CLOSURES 1 #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) #if defined (X86_64) || defined(X86_WIN64) \ || (defined (__x86_64__) && defined (X86_DARWIN)) # define FFI_TRAMPOLINE_SIZE 24 # define FFI_NATIVE_RAW_API 0 #else # define FFI_TRAMPOLINE_SIZE 12 # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif ================================================ FILE: Extensions/JPLocker.h ================================================ // // JPLocker.h // JSPatchDemo // // Created by bang on 3/22/16. // Copyright © 2016 bang. All rights reserved. // #import "JPEngine.h" @interface JPLocker : JPExtension @end ================================================ FILE: Extensions/JPLocker.m ================================================ // // JPLocker.m // JSPatchDemo // // Created by bang on 3/22/16. // Copyright © 2016 bang. All rights reserved. // #import "JPLocker.h" @implementation JPLocker + (void)main:(JSContext *)context { context[@"synchronized"] = ^void(JSValue *jsVal, JSValue *cb) { @synchronized([self formatJSToOC:jsVal]) { [cb callWithArguments:nil]; } }; } @end ================================================ FILE: Extensions/JPNumber.h ================================================ // // JPNumber.h // JSPatchDemo // // Created by pucheng on 16/7/5. // Copyright © 2016年 pucheng. All rights reserved. // #import "JPEngine.h" @interface JPNumber : JPExtension @end ================================================ FILE: Extensions/JPNumber.m ================================================ // // JPNumber.m // JSPatchDemo // // Created by pucheng on 16/7/5. // Copyright © 2016年 pucheng. All rights reserved. // #import "JPNumber.h" #import @implementation JPNumber + (void)main:(JSContext *)context { // for subclass of NSNumber, e.g. NSDecimalNumber context[@"OCNumber"] = ^ id (NSString *clsName, NSString *selName, JSValue *arguments) { Class cls = NSClassFromString(clsName); SEL sel = NSSelectorFromString(selName); if (!cls || !sel) return nil; Method m = class_getClassMethod(cls, sel); if (!m) return nil; NSMethodSignature *methodSignature = [cls methodSignatureForSelector:sel]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation setTarget:cls]; [invocation setSelector:sel]; id argumentsObj = [self formatJSToOC: arguments]; NSUInteger numberOfArguments = methodSignature.numberOfArguments; for (NSUInteger i = 2; i < numberOfArguments; i++) { const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; id valObj = argumentsObj[i-2]; switch (argumentType[0] == 'r' ? argumentType[1] : argumentType[0]) { #define JP_OCNumber_CASE(_typeString, _type, _selector) \ case _typeString: { \ _type value = [valObj _selector]; \ [invocation setArgument:&value atIndex:i]; \ break; \ } JP_OCNumber_CASE('c', char, charValue) JP_OCNumber_CASE('C', unsigned char, unsignedCharValue) JP_OCNumber_CASE('s', short, shortValue) JP_OCNumber_CASE('S', unsigned short, unsignedShortValue) JP_OCNumber_CASE('i', int, intValue) JP_OCNumber_CASE('I', unsigned int, unsignedIntValue) JP_OCNumber_CASE('l', long, longValue) JP_OCNumber_CASE('L', unsigned long, unsignedLongValue) JP_OCNumber_CASE('q', long long, longLongValue) JP_OCNumber_CASE('Q', unsigned long long, unsignedLongLongValue) JP_OCNumber_CASE('f', float, floatValue) JP_OCNumber_CASE('d', double, doubleValue) JP_OCNumber_CASE('B', BOOL, boolValue) default: [invocation setArgument:&valObj atIndex:i]; } } [invocation invoke]; void *result; [invocation getReturnValue:&result]; id returnValue = (__bridge id)result; /** * must be boxed in JPBoxing. * Otherwise when calling functions in JS, the number valued 0 which is considered as null will call a class function rather than a instance function in JSPatch.js */ JPBoxing *box = [[JPBoxing alloc] init]; box.obj = returnValue; return @{@"__obj": box, @"__clsName": clsName}; }; context[@"toOCNumber"] = ^ id (JSValue *value) { id obj = [value toObject]; if (!obj || ![obj isKindOfClass:[NSNumber class]]) { return nil; } JPBoxing *box = [[JPBoxing alloc] init]; box.obj = obj; return @{@"__obj": box, @"__clsName": NSStringFromClass([obj class])}; }; context[@"toJSNumber"] = ^ NSNumber *(JSValue *value) { NSDictionary *dict = [value toDictionary]; if (dict) { return [(JPBoxing *)dict[@"__obj"] unbox]; } return 0; }; } @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlayground.h ================================================ // // JPPlayground.h // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import @interface JPPlayground : NSObject +(void)startPlaygroundWithJSPath:(NSString *)path; +(void)setReloadCompleteHandler:(void(^)())complete; +(void)reload; @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlayground.m ================================================ // // JPPlayground.m // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import "JPPlayground.h" #import "JPKeyCommands.h" #import "JPDevErrorView.h" #import "JPDevMenu.h" #import "JPDevTipView.h" #import "SGDirWatchdog.h" @interface JPPlayground () @property (nonatomic,strong) NSString *rootPath; @property (nonatomic,strong) JPKeyCommands *keyManager; @property (nonatomic,strong) UIView *errorView; @property (nonatomic,strong) JPDevMenu *devMenu; @property (nonatomic,assign) BOOL isAutoReloading; @property (nonatomic,strong) NSMutableArray *watchDogs; @end static void (^_reloadCompleteHandler)(void) = ^void(void) { }; @implementation JPPlayground #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" + (instancetype)sharedInstance { #if TARGET_IPHONE_SIMULATOR static JPPlayground *sharedInstance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [self new]; }); return sharedInstance; #else return nil; #endif } - (instancetype)init { if ((self = [super init])) { #if TARGET_IPHONE_SIMULATOR _keyManager = [JPKeyCommands sharedInstance]; _devMenu = [[JPDevMenu alloc]init]; _devMenu.delegate = self; _isAutoReloading = NO; _watchDogs = [[NSMutableArray alloc] init]; #endif } return self; } +(void)setReloadCompleteHandler:(void (^)())complete { _reloadCompleteHandler = [complete copy]; } +(void)startPlaygroundWithJSPath:(NSString *)path { [[JPPlayground sharedInstance] startPlaygroundWithJSPath:path]; } -(void)startPlaygroundWithJSPath:(NSString *)mainScriptPath { #if TARGET_IPHONE_SIMULATOR self.rootPath = mainScriptPath; NSString *scriptRootPath = [mainScriptPath stringByDeletingLastPathComponent]; NSArray *contentOfFolder = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:scriptRootPath error:NULL]; [self watchFolder:scriptRootPath mainScriptPath:mainScriptPath]; if ([scriptRootPath rangeOfString:@".app"].location != NSNotFound) { NSString *apphomepath = [scriptRootPath stringByDeletingLastPathComponent]; [self watchFolder:apphomepath mainScriptPath:mainScriptPath]; } for (NSString *aPath in contentOfFolder) { NSString * fullPath = [scriptRootPath stringByAppendingPathComponent:aPath]; BOOL isDir; if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDir] && isDir) { [self watchFolder:fullPath mainScriptPath:mainScriptPath]; } } void(^exceptionhandler)(NSString *msg) = ^(NSString *msg){ JPDevErrorView *errV = [[JPDevErrorView alloc]initError:msg]; [[UIApplication sharedApplication].keyWindow addSubview:errV]; self.errorView = errV; [self.devMenu toggle]; }; id JPEngineClass = (id)NSClassFromString(@"JPEngine"); if (JPEngineClass && [JPEngineClass respondsToSelector:@selector(handleException:)]) { [JPEngineClass performSelector:@selector(handleException:) withObject:exceptionhandler]; }else{ NSCAssert(NO, @"can't find JPEngine handleException: Method"); } [self.keyManager registerKeyCommandWithInput:@"x" modifierFlags:UIKeyModifierCommand action:^(UIKeyCommand *command) { [self.devMenu toggle]; }]; [self.keyManager registerKeyCommandWithInput:@"r" modifierFlags:UIKeyModifierCommand action:^(UIKeyCommand *command) { [self reload]; }]; [self reload]; #endif } +(void)reload { [[JPPlayground sharedInstance]reload]; } -(void)reload { #if TARGET_IPHONE_SIMULATOR [JPDevTipView showJPDevTip:@"JSPatch Reloading ..."]; [self hideErrorView]; id JPCleanerClass = (id)NSClassFromString(@"JPCleaner"); if (JPCleanerClass && [JPCleanerClass respondsToSelector:@selector(cleanAll)]) { [JPCleanerClass performSelector:@selector(cleanAll)]; }else{ NSCAssert(NO, @"can't find JPCleaner cleanAll Method"); } NSString *script = [NSString stringWithContentsOfFile:self.rootPath encoding:NSUTF8StringEncoding error:nil]; id JPEngineClass = (id)NSClassFromString(@"JPEngine"); if (JPEngineClass && [JPEngineClass respondsToSelector:@selector(evaluateScript:)]) { [JPEngineClass performSelector:@selector(evaluateScript:) withObject:script]; }else{ NSCAssert(NO, @"can't find JPEngine evaluateScript: Method"); } _reloadCompleteHandler(); #endif } -(void)openInFinder { #if TARGET_IPHONE_SIMULATOR NSLog(@"%@\n",self.rootPath); NSLog(@"请打开以上路径的文件,事实编辑JS,事实刷新"); NSString *msg = [NSString stringWithFormat:@"JS文件路径:%@\n 编辑JS文件后保存,按Command+R刷新就可以看到最新的代码效果",self.rootPath]; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Edit JS File and Reload" message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; [UIPasteboard generalPasteboard].string = self.rootPath; #pragma clang diagnostic pop #endif } -(void)watchJSFile:(BOOL)watch { #if TARGET_IPHONE_SIMULATOR for (SGDirWatchdog *dog in self.watchDogs) { if (watch) { [dog start]; }else{ [dog stop]; } } #endif } - (void)watchFolder:(NSString *)folderPath mainScriptPath:(NSString *)mainScriptPath { #if TARGET_IPHONE_SIMULATOR SGDirWatchdog *watchDog = [[SGDirWatchdog alloc] initWithPath:folderPath update:^{ [self reload]; }]; [self.watchDogs addObject:watchDog]; #endif } -(void)hideErrorView { #if TARGET_IPHONE_SIMULATOR [self.errorView removeFromSuperview]; self.errorView = nil; #endif } -(void)devMenuDidAction:(JPDevMenuAction)action withValue:(id)value { #if TARGET_IPHONE_SIMULATOR switch (action) { case JPDevMenuActionReload:{ [self reload]; break; } case JPDevMenuActionAutoReload:{ BOOL select = [value boolValue]; [self watchJSFile:select]; break; } case JPDevMenuActionOpenJS:{ [self openInFinder]; break; } case JPDevMenuActionCancel:{ [self hideErrorView]; break; } default: break; } #endif } #pragma clang diagnostic pop @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundModule/JPKeyCommands.h ================================================ // // JPKeyCommands.h // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import @interface JPKeyCommands : NSObject + (instancetype)sharedInstance; - (void)registerKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags action:(void (^)(UIKeyCommand *))block; - (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags; - (BOOL)isKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags; @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundModule/JPKeyCommands.m ================================================ /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ #import "JPKeyCommands.h" #import #import static BOOL JPIsIOS8OrEarlier() { return [UIDevice currentDevice].systemVersion.floatValue < 9; } void JPSwapInstanceMethods(Class cls, SEL original, SEL replacement) { Method originalMethod = class_getInstanceMethod(cls, original); IMP originalImplementation = method_getImplementation(originalMethod); const char *originalArgTypes = method_getTypeEncoding(originalMethod); Method replacementMethod = class_getInstanceMethod(cls, replacement); IMP replacementImplementation = method_getImplementation(replacementMethod); const char *replacementArgTypes = method_getTypeEncoding(replacementMethod); if (class_addMethod(cls, original, replacementImplementation, replacementArgTypes)) { class_replaceMethod(cls, replacement, originalImplementation, originalArgTypes); } else { method_exchangeImplementations(originalMethod, replacementMethod); } } #if TARGET_IPHONE_SIMULATOR @interface JPKeyCommand : NSObject @property (nonatomic, strong) UIKeyCommand *keyCommand; @property (nonatomic, copy) void (^block)(UIKeyCommand *); @end @implementation JPKeyCommand - (instancetype)initWithKeyCommand:(UIKeyCommand *)keyCommand block:(void (^)(UIKeyCommand *))block { if ((self = [super init])) { _keyCommand = keyCommand; _block = block; } return self; } - (id)copyWithZone:(__unused NSZone *)zone { return self; } - (NSUInteger)hash { return _keyCommand.input.hash ^ _keyCommand.modifierFlags; } - (BOOL)isEqual:(JPKeyCommand *)object { if (![object isKindOfClass:[JPKeyCommand class]]) { return NO; } return [self matchesInput:object.keyCommand.input flags:object.keyCommand.modifierFlags]; } - (BOOL)matchesInput:(NSString *)input flags:(UIKeyModifierFlags)flags { return [_keyCommand.input isEqual:input] && _keyCommand.modifierFlags == flags; } - (NSString *)description { return [NSString stringWithFormat:@"<%@:%p input=\"%@\" flags=%zd hasBlock=%@>", [self class], self, _keyCommand.input, _keyCommand.modifierFlags, _block ? @"YES" : @"NO"]; } @end @interface JPKeyCommands () @property (nonatomic, strong) NSMutableSet *commands; @end @implementation UIResponder (RCTKeyCommands) - (NSArray *)JP_keyCommands { NSSet *commands = [JPKeyCommands sharedInstance].commands; return [[commands valueForKeyPath:@"keyCommand"] allObjects]; } - (void)JP_handleKeyCommand:(UIKeyCommand *)key { // NOTE: throttle the key handler because on iOS 9 the handleKeyCommand: // method gets called repeatedly if the command key is held down. static NSTimeInterval lastCommand = 0; if (JPIsIOS8OrEarlier() || CACurrentMediaTime() - lastCommand > 0.5) { for (JPKeyCommand *command in [JPKeyCommands sharedInstance].commands) { if ([command.keyCommand.input isEqualToString:key.input] && command.keyCommand.modifierFlags == key.modifierFlags) { if (command.block) { command.block(key); lastCommand = CACurrentMediaTime(); } } } } } @end @implementation UIApplication (JPKeyCommands) // Required for iOS 8.x - (BOOL)JP_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event { if (action == @selector(JP_handleKeyCommand:)) { [self JP_handleKeyCommand:sender]; return YES; } return [self JP_sendAction:action to:target from:sender forEvent:event]; } @end @implementation JPKeyCommands + (void)initialize { if (JPIsIOS8OrEarlier()) { //swizzle UIApplication JPSwapInstanceMethods([UIApplication class], @selector(keyCommands), @selector(JP_keyCommands)); JPSwapInstanceMethods([UIApplication class], @selector(sendAction:to:from:forEvent:), @selector(JP_sendAction:to:from:forEvent:)); } else { //swizzle UIResponder JPSwapInstanceMethods([UIResponder class], @selector(keyCommands), @selector(JP_keyCommands)); } } + (instancetype)sharedInstance { static JPKeyCommands *sharedInstance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [self new]; }); return sharedInstance; } - (instancetype)init { if ((self = [super init])) { _commands = [NSMutableSet new]; } return self; } - (void)registerKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags action:(void (^)(UIKeyCommand *))block { if (input.length && flags && JPIsIOS8OrEarlier()) { // Workaround around the first cmd not working: http://openradar.appspot.com/19613391 // You can register just the cmd key and do nothing. This ensures that // command-key modified commands will work first time. Fixed in iOS 9. [self registerKeyCommandWithInput:@"" modifierFlags:flags action:nil]; } UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:input modifierFlags:flags action:@selector(JP_handleKeyCommand:)]; JPKeyCommand *keyCommand = [[JPKeyCommand alloc] initWithKeyCommand:command block:block]; [_commands removeObject:keyCommand]; [_commands addObject:keyCommand]; } - (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags { for (JPKeyCommand *command in _commands.allObjects) { if ([command matchesInput:input flags:flags]) { [_commands removeObject:command]; break; } } } - (BOOL)isKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags { for (JPKeyCommand *command in _commands) { if ([command matchesInput:input flags:flags]) { return YES; } } return NO; } @end #else @implementation JPKeyCommands + (instancetype)sharedInstance { return nil; } - (void)registerKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags action:(void (^)(UIKeyCommand *))block { }; - (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags { }; - (BOOL)isKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags { return NO; } @end #endif ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundModule/SGDirWatchdog.h ================================================ // // SGDirObserver.h // DirectoryObserver // // Copyright (c) 2011 Simon Grätzer. // #import @interface SGDirWatchdog : NSObject @property (readonly, nonatomic) NSString *path; @property (copy, nonatomic) void (^update)(void); + (NSString *)documentsPath; + (id)watchtdogOnDocumentsDir:(void (^)(void))update; - (id)initWithPath:(NSString *)path update:(void (^)(void))update; - (void)start; - (void)stop; @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundModule/SGDirWatchdog.m ================================================ // // SGDirObserver.m // DirectoryObserver // // Copyright (c) 2011 Simon Grätzer. // #import "SGDirWatchdog.h" #import #import #import @interface SGDirWatchdog () @property (nonatomic, readonly) CFFileDescriptorRef kqRef; - (void)kqueueFired; @end static void KQCallback(CFFileDescriptorRef kqRef, CFOptionFlags callBackTypes, void *info) { // Pick up the object passed in the "info" member of the CFFileDescriptorContext passed to CFFileDescriptorCreate SGDirWatchdog* obj = (__bridge SGDirWatchdog*) info; if ([obj isKindOfClass:[SGDirWatchdog class]] && // If we can call back to the proper sort of object ... (kqRef == obj.kqRef) && // and the FD that issued the CB is the expected one ... (callBackTypes == kCFFileDescriptorReadCallBack) ) // and we're processing the proper sort of CB ... { [obj kqueueFired]; // Invoke the instance's CB handler } } @implementation SGDirWatchdog { int _dirFD; CFFileDescriptorRef _kqRef; } + (NSString *)documentsPath { NSArray *documentsPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); return documentsPaths[0]; // Path to the application's "Documents" directory } + (id)watchtdogOnDocumentsDir:(void (^)(void))update; { return [[SGDirWatchdog alloc]initWithPath:[self documentsPath] update:update]; } - (id)initWithPath:(NSString *)path update:(void (^)(void))update; { if ((self = [super init])) { _path = path; _update = [update copy]; } return self; } - (void)dealloc { [self stop]; } #pragma mark - #pragma mark Extension methods - (void)kqueueFired { // Pull the native FD around which the CFFileDescriptor was wrapped int kq = CFFileDescriptorGetNativeDescriptor(_kqRef); if (kq < 0) return; // If we pull a single available event out of the queue, assume the directory was updated struct kevent event; struct timespec timeout = {0, 0}; if (kevent(kq, NULL, 0, &event, 1, &timeout) == 1 && _update) { _update(); } // (Re-)Enable a one-shot (the only kind) callback CFFileDescriptorEnableCallBacks(_kqRef, kCFFileDescriptorReadCallBack); } - (void)start { // One ping only if (_kqRef != NULL) return; // Fetch pathname of the directory to monitor NSString* docPath = self.path; if (!docPath) return; // Open an event-only file descriptor associated with the directory int dirFD = open([docPath fileSystemRepresentation], O_EVTONLY); if (dirFD < 0) return; // Create a new kernel event queue int kq = kqueue(); if (kq < 0) { close(dirFD); return; } // Set up a kevent to monitor struct kevent eventToAdd; // Register an (ident, filter) pair with the kqueue eventToAdd.ident = dirFD; // The object to watch (the directory FD) eventToAdd.filter = EVFILT_VNODE; // Watch for certain events on the VNODE spec'd by ident eventToAdd.flags = EV_ADD | EV_CLEAR; // Add a resetting kevent eventToAdd.fflags = NOTE_WRITE; // The events to watch for on the VNODE spec'd by ident (writes) eventToAdd.data = 0; // No filter-specific data eventToAdd.udata = NULL; // No user data // Add a kevent to monitor if (kevent(kq, &eventToAdd, 1, NULL, 0, NULL)) { close(kq); close(dirFD); return; } // Wrap a CFFileDescriptor around a native FD CFFileDescriptorContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; _kqRef = CFFileDescriptorCreate(NULL, // Use the default allocator kq, // Wrap the kqueue true, // Close the CFFileDescriptor if kq is invalidated KQCallback, // Fxn to call on activity &context); // Supply a context to set the callback's "info" argument if (_kqRef == NULL) { close(kq); close(dirFD); return; } // Spin out a pluggable run loop source from the CFFileDescriptorRef // Add it to the current run loop, then release it CFRunLoopSourceRef rls = CFFileDescriptorCreateRunLoopSource(NULL, _kqRef, 0); if (rls == NULL) { CFRelease(_kqRef); _kqRef = NULL; close(kq); close(dirFD); return; } CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); CFRelease(rls); // Store the directory FD for later closing _dirFD = dirFD; // Enable a one-shot (the only kind) callback CFFileDescriptorEnableCallBacks(_kqRef, kCFFileDescriptorReadCallBack); } - (void)stop { if (_kqRef) { close(_dirFD); CFFileDescriptorInvalidate(_kqRef); CFRelease(_kqRef); _kqRef = NULL; } } @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundView/JPDevErrorView.h ================================================ // // JPErrorView.h // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import @interface JPDevErrorView : UIView - (instancetype)initError:(NSString *)errMsg; @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundView/JPDevErrorView.m ================================================ // // JPErrorView.m // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import "JPDevErrorView.h" @implementation JPDevErrorView - (instancetype)initError:(NSString *)errMsg { self = [super initWithFrame:[UIScreen mainScreen].bounds]; if (self) { self.backgroundColor = [UIColor redColor]; UITextView *text = [[UITextView alloc]initWithFrame:CGRectMake(0, 20, self.bounds.size.width, self.bounds.size.height-20)]; text.backgroundColor = [UIColor redColor]; text.textColor = [UIColor whiteColor]; text.font = [UIFont systemFontOfSize:20]; text.userInteractionEnabled = NO; text.text = errMsg; [self addSubview:text]; } return self; } @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundView/JPDevMenu.h ================================================ // // JPPlaygroundMenu.h // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import typedef enum : NSUInteger { JPDevMenuActionReload = 0, JPDevMenuActionAutoReload, JPDevMenuActionOpenJS, JPDevMenuActionCancel } JPDevMenuAction; @protocol JPDevMenuDelegate -(void)devMenuDidAction:(JPDevMenuAction)action withValue:(id)value; @end @interface JPDevMenu : NSObject @property (nonatomic,weak) id delegate; - (void)toggle; @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundView/JPDevMenu.m ================================================ // // JPPlaygroundMenu.m // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import "JPDevMenu.h" #import @interface JPDevMenuItem : NSObject /** * This creates an item with a simple push-button interface, used to trigger an * action. */ + (instancetype)buttonItemWithTitle:(NSString *)title handler:(void(^)(void))handler; /** * This creates an item with a toggle behavior. The key is used to store the * state of the toggle. For toggle items, the handler will be called immediately * after the item is added if the item was already selected when the module was * last loaded. */ + (instancetype)toggleItemWithKey:(NSString *)key title:(NSString *)title selectedTitle:(NSString *)selectedTitle handler:(void(^)(BOOL selected))handler; @end typedef NS_ENUM(NSInteger, JPDevMenuType) { JPDevMenuTypeButton, JPDevMenuTypeToggle }; @interface JPDevMenuItem () @property (nonatomic, assign, readonly) JPDevMenuType type; @property (nonatomic, copy, readonly) NSString *key; @property (nonatomic, copy, readonly) NSString *title; @property (nonatomic, copy, readonly) NSString *selectedTitle; @property (nonatomic, copy) id value; @end @implementation JPDevMenuItem { id _handler; // block } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - (instancetype)initWithType:(JPDevMenuType)type key:(NSString *)key title:(NSString *)title selectedTitle:(NSString *)selectedTitle handler:(id /* block */)handler { if ((self = [super init])) { _type = type; _key = [key copy]; _title = [title copy]; _selectedTitle = [selectedTitle copy]; _handler = [handler copy]; _value = nil; } return self; } + (instancetype)buttonItemWithTitle:(NSString *)title handler:(void (^)(void))handler { return [[self alloc] initWithType:JPDevMenuTypeButton key:nil title:title selectedTitle:nil handler:handler]; } + (instancetype)toggleItemWithKey:(NSString *)key title:(NSString *)title selectedTitle:(NSString *)selectedTitle handler:(void (^)(BOOL selected))handler { return [[self alloc] initWithType:JPDevMenuTypeToggle key:key title:title selectedTitle:selectedTitle handler:handler]; } - (void)callHandler { switch (_type) { case JPDevMenuTypeButton: { if (_handler) { ((void(^)())_handler)(); } break; } case JPDevMenuTypeToggle: { if (_handler) { ((void(^)(BOOL selected))_handler)([_value boolValue]); } break; } } } @end @interface JPDevMenu () @property (nonatomic,strong) UIActionSheet * actionSheet; @property (nonatomic,strong) NSMutableDictionary *settings; @property (nonatomic,strong) NSArray *presentedItems; @end @implementation JPDevMenu -(instancetype)init { self = [super init]; if (self) { _settings = [[NSMutableDictionary alloc]init]; } return self; } - (NSArray *)menuItems { NSMutableArray *items = [NSMutableArray new]; // Add built-in items [items addObject:[JPDevMenuItem buttonItemWithTitle:@"Reload JS (Command+R)" handler:^{ if (self.delegate && [self.delegate respondsToSelector:@selector(devMenuDidAction:withValue:)]) { [self.delegate devMenuDidAction:JPDevMenuActionReload withValue:nil]; } }]]; JPDevMenuItem *toggle = [JPDevMenuItem toggleItemWithKey:@"autoReloadJS" title:@"open Auto Reload JS" selectedTitle:@"Auto Reload JS Is Open" handler:^(BOOL selected) { if (self.delegate && [self.delegate respondsToSelector:@selector(devMenuDidAction:withValue:)]) { [self.delegate devMenuDidAction:JPDevMenuActionAutoReload withValue:@(selected)]; } }]; toggle.value = _settings[@"autoReloadJS"]; [items addObject:toggle]; [items addObject:[JPDevMenuItem buttonItemWithTitle:@"Help" handler:^{ if (self.delegate && [self.delegate respondsToSelector:@selector(devMenuDidAction:withValue:)]) { [self.delegate devMenuDidAction:JPDevMenuActionOpenJS withValue:nil]; } }]]; return items; } - (void)toggle { if (_actionSheet) { [_actionSheet dismissWithClickedButtonIndex:_actionSheet.cancelButtonIndex animated:YES]; _actionSheet = nil; } else { [self show]; } } -(void)show { UIActionSheet *actionSheet = [UIActionSheet new]; actionSheet.title = @"JPatch Playgournd : Command + X"; actionSheet.delegate = self; NSArray *items = [self menuItems]; for (JPDevMenuItem *item in items) { switch (item.type) { case JPDevMenuTypeButton: { [actionSheet addButtonWithTitle:item.title]; break; } case JPDevMenuTypeToggle: { BOOL selected = [item.value boolValue]; [actionSheet addButtonWithTitle:selected? item.selectedTitle : item.title]; break; } } } [actionSheet addButtonWithTitle:@"Cancel"]; actionSheet.cancelButtonIndex = actionSheet.numberOfButtons - 1; [actionSheet showInView:[UIApplication sharedApplication].keyWindow.rootViewController.view]; _actionSheet = actionSheet; _presentedItems = items; } - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { _actionSheet = nil; if (buttonIndex == actionSheet.cancelButtonIndex) { return; } JPDevMenuItem *item = _presentedItems[buttonIndex]; switch (item.type) { case JPDevMenuTypeButton: { [item callHandler]; break; } case JPDevMenuTypeToggle: { BOOL value = [_settings[item.key] boolValue]; [self updateSetting:item.key value:@(!value)]; // will call handler break; } } return; } - (void)updateSetting:(NSString *)name value:(id)value { // Fire handler for item whose values has changed for (JPDevMenuItem *item in _presentedItems) { if ([item.key isEqualToString:name]) { if (value != item.value && ![value isEqual:item.value]) { item.value = value; [item callHandler]; } break; } } // Save the setting id currentValue = _settings[name]; if (currentValue == value || [currentValue isEqual:value]) { return; } if (value) { _settings[name] = value; } else { [_settings removeObjectForKey:name]; } } -(void)actionSheetCancel:(UIActionSheet *)actionSheet { if (self.delegate && [self.delegate respondsToSelector:@selector(devMenuDidAction:withValue:)]) { [self.delegate devMenuDidAction:JPDevMenuActionCancel withValue:nil]; } } -(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { if (self.delegate && [self.delegate respondsToSelector:@selector(devMenuDidAction:withValue:)]) { [self.delegate devMenuDidAction:JPDevMenuActionCancel withValue:nil]; } } #pragma clang diagnostic pop @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundView/JPDevTipView.h ================================================ // // JPTipView.h // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import @interface JPDevTipView : UIView +(void)showJPDevTip:(NSString *)msg; -(instancetype)initWithMsg:(NSString*)msg; @end ================================================ FILE: Extensions/JPPlaygroundTool/JPPlaygroundView/JPDevTipView.m ================================================ // // JPTipView.m // JSPatchPlaygroundDemo // // Created by Awhisper on 16/8/7. // Copyright © 2016年 baidu. All rights reserved. // #import "JPDevTipView.h" @implementation JPDevTipView -(instancetype)initWithMsg:(NSString*)msg{ BOOL statusBarShow = [UIApplication sharedApplication].isStatusBarHidden; self = [super initWithFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,statusBarShow?20:40)]; if (self) { self.backgroundColor = [UIColor redColor]; UILabel *tip = [[UILabel alloc]initWithFrame:CGRectMake(0, statusBarShow?0:20, self.bounds.size.width, 20)]; tip.textColor = [UIColor whiteColor]; tip.font = [UIFont systemFontOfSize:18]; tip.textAlignment = NSTextAlignmentCenter; tip.text = msg; [self addSubview:tip]; } return self; } +(void)showJPDevTip:(NSString *)msg { JPDevTipView *tip = [[JPDevTipView alloc]initWithMsg:msg]; UIView *window = [UIApplication sharedApplication].keyWindow; [window addSubview:tip]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [UIView animateWithDuration:1 animations:^{ tip.alpha = 0; } completion:^(BOOL finished) { [tip removeFromSuperview]; }]; }); } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end ================================================ FILE: Extensions/JPPlaygroundTool/README.md ================================================ # JSPatchPlaygroundTool JSPatch天然能实现playground黑科技一样的效果,什么样的黑科技呢?我们改的每一行代码,每一个语句,完全无需重新运行app,直接能立刻看到效果。 并且bang哥已经给出了如何操作和说明 # JSPatch Playground [JSPatch Playground Github](https://github.com/bang590/JSPatch/tree/master/Demo/iOSPlayground) ![Screenshot](https://raw.github.com/bang590/JSPatch/master/Demo/iOSPlayground/Screenshot.gif) ## 介绍 JSPatch Playground 可以让你快速看到 JSPatch 代码执行效果,APP在模拟器运行后,每次修改脚本保存模拟器都会自动刷新,无需重启模拟器,即时看到效果。 你也可以仿照 JSPatch Playground 在你的项目里添加 JSPatch 脚本即时刷新功能,帮助你快速使用 JSPatch 开发功能模块。 Tips: 如果运行过程中脚本执行错误,会在状态栏里显示错误原因,点击状态栏可以看到更详细的错误提示。 # JSPatchPlaygroundTool bang哥的Playground工程下面,可以看到想要配置这样一个如此酷炫的黑科技,[JSPatch Playground Github](https://github.com/bang590/JSPatch/tree/master/Demo/iOSPlayground) 项目下的`JPRootViewController.m`文件里面的代码还是挺多的 由于前些日子搞了一阵子ReactNative,发现ReactNative下面的Debug,Reload工具很是方便,心想也给JSPatch弄一套,于是就有了这个`JSPatchPlaygroundTool` 初衷是,把一整套playground的思路以及环境代码配置,封装成工具,以简洁的API就能轻松运行。 ## JSPatchPlaygroundTool的使用 这段代码分成两部分,上半部分就是配置`JSPatchPlaygroundTool`,让JSPatch以Playground的模式进行工作。下半部分则是正常代码,正常的按既有方案加载JSPatch ```objectivec #if TARGET_IPHONE_SIMULATOR //playground调试 //JS测试包的本地绝对路径 NSString *rootPath = @"/Users/Awhisper/Desktop/Github/JSPatchPlaygroundTool/JSPatchPlaygroundDemo/JSPatchPlaygroundDemo"; NSString *scriptRootPath = [rootPath stringByAppendingPathComponent:@"js"]; NSString *mainScriptPath = [NSString stringWithFormat:@"%@/%@", scriptRootPath, @"demo.js"]; [JPPlayground setReloadCompleteHandler:^{ [self showController]; }]; [JPPlayground startPlaygroundWithJSPath:mainScriptPath]; #else //正常执行JSPatch //JS测试包的本地绝对路径 NSString *rootPath = [[NSBundle mainBundle] bundlePath]; NSString *scriptPath = [rootPath stringByAppendingPathComponent:@"demo.js"]; NSString *script = [NSString stringWithContentsOfFile:scriptPath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; #endif ``` 这里只讲解上半部分的API,`rootPath`此处切记输入Mac电脑的mainJS文件所在的路径,我的目录里在工程文件`JSPatchPlaygroundDemo`下专门放了个名字为JS的文件夹,里面放着核心的JS代码逻辑,所以我又补充了`\js\demo.js`作为后缀 - [JPPlayground setReloadCompleteHandler:block] 这个API的意义在于,每次重新刷新JS后,如果有一些额外的想要操作的东西就可以在此时执行,如果没有,这个API完全可以不使用 - [JPPlayground startPlaygroundWithJSPath:path] 这个API是核心API,输入mainJS的路径后,整个JSPatch将会以playground的模式进行运行 ## JSPatchPlaygroundTool的效果 __command + X__:可以打开操作菜单 ![menu](http://ww2.sinaimg.cn/mw690/678c3e91jw1f6lkzh8zwdj208n0fyaam.jpg) __command + R__:可以ReloadJS 当APP在保持运行的时候,我们可以任意修改main.js文件然后进行保存,然后按command+R的组合键,就可以立刻刷新 __JS Error__:当JS文件有错误,app并不会崩溃,保持持续运行,并且弹出红色界面,详细描述错误信息,当把js文件修改正确后,重新reload,自然就会顺利运行。 ![error](http://ww2.sinaimg.cn/mw690/678c3e91jw1f6lkzglfruj208n0fyq3t.jpg) __AutoReload JS__:Tool可以开启监听JS文件的变化,当你把menu中的这个开关打开,每一次修改js文件进行保存,都会自动触发reload。再次点击这个按钮,会关闭监听,(AutoReload默认不开启) __Todo List__:我还想尝试在菜单里面多做2个功能,但并未能找到办法 - 自动打开Finder,打开JS文件所在的目录,从而能快速找到要修改的JS文件,轻轻松松的开始畅快的JS代码之旅,从此告别编译,运行,重启app的烦躁过程 - 自动打开Safari的开发者模式,打开正在run的JSContext,从而能对js代码进行断点调试,就好像ReactNative能自动打开chrome一样 我没有找到很好的办法,能在iOS框架里面,在模拟器里面,打开Mac上的Mac app,太多的方法都是OSX开发才能使用的库,比如`NSWorkSpace`,这玩意没法在iOS项目里用。发愁 ## JSPatchPlaygroundTool的目标 当使用JSPatch进行一整个功能模块的开发,而不仅仅是只用来修改bug,能像ReactNative一样,run起app后,告别反锁的编译,运行,写出来的代码立刻就生效,代码出错也立刻报出来,丝毫不影响运行,重新修改好后,自然完美运作。 # JSPatchPlayground的原理 之前提到过JSPatch是天然支持这种playground的黑科技玩法的~ 原因就在于JSPatch的一个Extension`JPCleaner`,他可以让所有被JSPatch的hook的函数都恢复原样,这样将修改过最新的JS,重新执行以下,就实现了Reload的效果 ================================================ FILE: Extensions/JPProtocol.h ================================================ // // JPProtocol.h // JSPatchDemo // // Created by bang on 9/9/16. // Copyright © 2016 bang. All rights reserved. // #import #import "JPEngine.h" @interface JPProtocol : JPExtension @end ================================================ FILE: Extensions/JPProtocol.m ================================================ // // JPProtocol.m // JSPatchDemo // // Created by bang on 9/9/16. // Copyright © 2016 bang. All rights reserved. // #import "JPProtocol.h" #import @implementation JPProtocol + (void)main:(JSContext *)context { context[@"protocol"] = ^id(NSString *protocolName) { return objc_getProtocol([protocolName cStringUsingEncoding:NSUTF8StringEncoding]); }; } @end ================================================ FILE: Extensions/JPSpecialInit.h ================================================ // // JPSpecialInit.h // SwiftDemo // // Created by KouArlen on 16/2/25. // Copyright © 2016年 Arlen. All rights reserved. // #import #import /** handle the Init of some Special Class https://github.com/bang590/JSPatch/issues/248 */ @interface JPSpecialInit : NSObject + (NSCalendar *)calendarWithCalendarIdentifier:(NSString *)iden; #if TARGET_OS_IOS + (UIWebView *)newWebView; #endif @end ================================================ FILE: Extensions/JPSpecialInit.m ================================================ // // JPSpecialInit.m // SwiftDemo // // Created by KouArlen on 16/2/25. // Copyright © 2016年 Arlen. All rights reserved. // #import "JPSpecialInit.h" @implementation JPSpecialInit + (NSCalendar *)calendarWithCalendarIdentifier:(NSString *)iden { return [[NSCalendar alloc] initWithCalendarIdentifier:iden]; } #if TARGET_OS_IOS + (UIWebView *)newWebView { return [[UIWebView alloc] init]; } #endif @end ================================================ FILE: JSPatch/JPEngine.h ================================================ // // JPEngine.h // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015 bang. All rights reserved. // #import #import @interface JPEngine : NSObject /*! @method @discussion start the JSPatch engine, execute only once. !Deprecated! will be call automatically before evaluate script */ + (void)startEngine; /*! @method @description Evaluate Javascript code from a file Path. Call it after +startEngine. @param filePath: The filePath of the Javascript code. @result The last value generated by the script. */ + (JSValue *)evaluateScriptWithPath:(NSString *)filePath; /*! @method @description Evaluate a string of JavaScript code. Call it after +startEngine. The method will generate a default resouceURL named "main.js" to the Safari debugger. @param script: A string containing the JavaScript code to evaluate. @result The last value generated by the script. */ + (JSValue *)evaluateScript:(NSString *)script; /*! @method @description Return the JSPatch JavaScript execution environment. */ + (JSContext *)context; /*! @method @description Add JPExtension. @param extensions: An array containing class name string. */ + (void)addExtensions:(NSArray *)extensions; /*! @method @description add new struct type supporting to JS @param defineDict: the definition of struct, for Example: @{ @"name": @"CGAffineTransform", //struct name @"types": @"ffffff", //struct types @"keys": @[@"a", @"b", @"c", @"d", @"tx", @"ty"] //struct keys in JS } */ + (void)defineStruct:(NSDictionary *)defineDict; + (void)handleException:(void (^)(NSString *msg))exceptionBlock; @end @interface JPExtension : NSObject + (void)main:(JSContext *)context; + (void *)formatPointerJSToOC:(JSValue *)val; + (id)formatRetainedCFTypeOCToJS:(CFTypeRef)CF_CONSUMED type; + (id)formatPointerOCToJS:(void *)pointer; + (id)formatJSToOC:(JSValue *)val; + (id)formatOCToJS:(id)obj; + (int)sizeOfStructTypes:(NSString *)structTypes; + (void)getStructDataWidthDict:(void *)structData dict:(NSDictionary *)dict structDefine:(NSDictionary *)structDefine; + (NSDictionary *)getDictOfStruct:(void *)structData structDefine:(NSDictionary *)structDefine; /*! @method @description Return the registered struct definition in JSPatch, the key of dictionary is the struct name. */ + (NSMutableDictionary *)registeredStruct; + (NSDictionary *)overideMethods; + (NSMutableSet *)includedScriptPaths; @end @interface JPBoxing : NSObject @property (nonatomic) id obj; @property (nonatomic) void *pointer; @property (nonatomic) Class cls; @property (nonatomic, weak) id weakObj; @property (nonatomic, assign) id assignObj; - (id)unbox; - (void *)unboxPointer; - (Class)unboxClass; @end ================================================ FILE: JSPatch/JPEngine.m ================================================ // JPEngine.m // JSPatch // // Created by bang on 15/4/30. // Copyright (c) 2015 bang. All rights reserved. // #import "JPEngine.h" #import #import #if TARGET_OS_IPHONE #import #endif #if CGFLOAT_IS_DOUBLE #define CGFloatValue doubleValue #else #define CGFloatValue floatValue #endif @implementation JPBoxing #define JPBOXING_GEN(_name, _prop, _type) \ + (instancetype)_name:(_type)obj \ { \ JPBoxing *boxing = [[JPBoxing alloc] init]; \ boxing._prop = obj; \ return boxing; \ } JPBOXING_GEN(boxObj, obj, id) JPBOXING_GEN(boxPointer, pointer, void *) JPBOXING_GEN(boxClass, cls, Class) JPBOXING_GEN(boxWeakObj, weakObj, id) JPBOXING_GEN(boxAssignObj, assignObj, id) - (id)unbox { if (self.obj) return self.obj; if (self.weakObj) return self.weakObj; if (self.assignObj) return self.assignObj; if (self.cls) return self.cls; return self; } - (void *)unboxPointer { return self.pointer; } - (Class)unboxClass { return self.cls; } @end #pragma mark - Fix iOS7 NSInvocation fatal error // A fatal error of NSInvocation on iOS7.0. // A invocation return 0 when the return type is double/float. // http://stackoverflow.com/questions/19874502/nsinvocation-getreturnvalue-with-double-value-produces-0-unexpectedly typedef struct {double d;} JPDouble; typedef struct {float f;} JPFloat; static NSMethodSignature *fixSignature(NSMethodSignature *signature) { #if TARGET_OS_IPHONE #ifdef __LP64__ if (!signature) { return nil; } if ([[UIDevice currentDevice].systemVersion floatValue] < 7.09) { BOOL isReturnDouble = (strcmp([signature methodReturnType], "d") == 0); BOOL isReturnFloat = (strcmp([signature methodReturnType], "f") == 0); if (isReturnDouble || isReturnFloat) { NSMutableString *types = [NSMutableString stringWithFormat:@"%s@:", isReturnDouble ? @encode(JPDouble) : @encode(JPFloat)]; for (int i = 2; i < signature.numberOfArguments; i++) { const char *argType = [signature getArgumentTypeAtIndex:i]; [types appendFormat:@"%s", argType]; } signature = [NSMethodSignature signatureWithObjCTypes:[types UTF8String]]; } } #endif #endif return signature; } @interface NSObject (JPFix) - (NSMethodSignature *)jp_methodSignatureForSelector:(SEL)aSelector; + (void)jp_fixMethodSignature; @end @implementation NSObject (JPFix) const static void *JPFixedFlagKey = &JPFixedFlagKey; - (NSMethodSignature *)jp_methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *signature = [self jp_methodSignatureForSelector:aSelector]; return fixSignature(signature); } + (void)jp_fixMethodSignature { #if TARGET_OS_IPHONE #ifdef __LP64__ if ([[UIDevice currentDevice].systemVersion floatValue] < 7.1) { NSNumber *flag = objc_getAssociatedObject(self, JPFixedFlagKey); if (!flag.boolValue) { SEL originalSelector = @selector(methodSignatureForSelector:); SEL swizzledSelector = @selector(jp_methodSignatureForSelector:); Method originalMethod = class_getInstanceMethod(self, originalSelector); Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector); BOOL didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (didAddMethod) { class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } objc_setAssociatedObject(self, JPFixedFlagKey, @YES, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } #endif #endif } @end #pragma mark - static JSContext *_context; static NSString *_regexStr = @"(? 0 ? methodDict[@"returnType"] : @"void"; NSString *typeEncode = methodDict[@"typeEncode"]; NSArray *argStrArr = [paraString componentsSeparatedByString:@","]; NSString *selectorName = convertJPSelectorString(jpSelector); if ([selectorName componentsSeparatedByString:@":"].count - 1 < argStrArr.count) { selectorName = [selectorName stringByAppendingString:@":"]; } if (typeEncode) { addMethodToProtocol(protocol, selectorName, typeEncode, isInstance); } else { if (!_protocolTypeEncodeDict) { _protocolTypeEncodeDict = [[NSMutableDictionary alloc] init]; #define JP_DEFINE_TYPE_ENCODE_CASE(_type) \ [_protocolTypeEncodeDict setObject:[NSString stringWithUTF8String:@encode(_type)] forKey:@#_type];\ JP_DEFINE_TYPE_ENCODE_CASE(id); JP_DEFINE_TYPE_ENCODE_CASE(BOOL); JP_DEFINE_TYPE_ENCODE_CASE(int); JP_DEFINE_TYPE_ENCODE_CASE(void); JP_DEFINE_TYPE_ENCODE_CASE(char); JP_DEFINE_TYPE_ENCODE_CASE(short); JP_DEFINE_TYPE_ENCODE_CASE(unsigned short); JP_DEFINE_TYPE_ENCODE_CASE(unsigned int); JP_DEFINE_TYPE_ENCODE_CASE(long); JP_DEFINE_TYPE_ENCODE_CASE(unsigned long); JP_DEFINE_TYPE_ENCODE_CASE(long long); JP_DEFINE_TYPE_ENCODE_CASE(float); JP_DEFINE_TYPE_ENCODE_CASE(double); JP_DEFINE_TYPE_ENCODE_CASE(CGFloat); JP_DEFINE_TYPE_ENCODE_CASE(CGSize); JP_DEFINE_TYPE_ENCODE_CASE(CGRect); JP_DEFINE_TYPE_ENCODE_CASE(CGPoint); JP_DEFINE_TYPE_ENCODE_CASE(CGVector); JP_DEFINE_TYPE_ENCODE_CASE(NSRange); JP_DEFINE_TYPE_ENCODE_CASE(NSInteger); JP_DEFINE_TYPE_ENCODE_CASE(Class); JP_DEFINE_TYPE_ENCODE_CASE(SEL); JP_DEFINE_TYPE_ENCODE_CASE(void*); #if TARGET_OS_IPHONE JP_DEFINE_TYPE_ENCODE_CASE(UIEdgeInsets); #else JP_DEFINE_TYPE_ENCODE_CASE(NSEdgeInsets); #endif [_protocolTypeEncodeDict setObject:@"@?" forKey:@"block"]; [_protocolTypeEncodeDict setObject:@"^@" forKey:@"id*"]; } NSString *returnEncode = _protocolTypeEncodeDict[returnString]; if (returnEncode.length > 0) { NSMutableString *encode = [returnEncode mutableCopy]; [encode appendString:@"@:"]; for (NSInteger i = 0; i < argStrArr.count; i++) { NSString *argStr = trim([argStrArr objectAtIndex:i]); NSString *argEncode = _protocolTypeEncodeDict[argStr]; if (!argEncode) { NSString *argClassName = trim([argStr stringByReplacingOccurrencesOfString:@"*" withString:@""]); if (NSClassFromString(argClassName) != NULL) { argEncode = @"@"; } else { _exceptionBlock([NSString stringWithFormat:@"unreconized type %@", argStr]); return; } } [encode appendString:argEncode]; } addMethodToProtocol(protocol, selectorName, encode, isInstance); } } } } static void addMethodToProtocol(Protocol* protocol, NSString *selectorName, NSString *typeencoding, BOOL isInstance) { SEL sel = NSSelectorFromString(selectorName); const char* type = [typeencoding UTF8String]; protocol_addMethodDescription(protocol, sel, type, YES, isInstance); } static NSDictionary *defineClass(NSString *classDeclaration, JSValue *instanceMethods, JSValue *classMethods) { NSScanner *scanner = [NSScanner scannerWithString:classDeclaration]; NSString *className; NSString *superClassName; NSString *protocolNames; [scanner scanUpToString:@":" intoString:&className]; if (!scanner.isAtEnd) { scanner.scanLocation = scanner.scanLocation + 1; [scanner scanUpToString:@"<" intoString:&superClassName]; if (!scanner.isAtEnd) { scanner.scanLocation = scanner.scanLocation + 1; [scanner scanUpToString:@">" intoString:&protocolNames]; } } if (!superClassName) superClassName = @"NSObject"; className = trim(className); superClassName = trim(superClassName); NSArray *protocols = [protocolNames length] ? [protocolNames componentsSeparatedByString:@","] : nil; Class cls = NSClassFromString(className); if (!cls) { Class superCls = NSClassFromString(superClassName); if (!superCls) { _exceptionBlock([NSString stringWithFormat:@"can't find the super class %@", superClassName]); return @{@"cls": className}; } cls = objc_allocateClassPair(superCls, className.UTF8String, 0); objc_registerClassPair(cls); } if (protocols.count > 0) { for (NSString* protocolName in protocols) { Protocol *protocol = objc_getProtocol([trim(protocolName) cStringUsingEncoding:NSUTF8StringEncoding]); class_addProtocol (cls, protocol); } } for (int i = 0; i < 2; i ++) { BOOL isInstance = i == 0; JSValue *jsMethods = isInstance ? instanceMethods: classMethods; Class currCls = isInstance ? cls: objc_getMetaClass(className.UTF8String); NSDictionary *methodDict = [jsMethods toDictionary]; for (NSString *jsMethodName in methodDict.allKeys) { JSValue *jsMethodArr = [jsMethods valueForProperty:jsMethodName]; int numberOfArg = [jsMethodArr[0] toInt32]; NSString *selectorName = convertJPSelectorString(jsMethodName); if ([selectorName componentsSeparatedByString:@":"].count - 1 < numberOfArg) { selectorName = [selectorName stringByAppendingString:@":"]; } JSValue *jsMethod = jsMethodArr[1]; if (class_respondsToSelector(currCls, NSSelectorFromString(selectorName))) { overrideMethod(currCls, selectorName, jsMethod, !isInstance, NULL); } else { BOOL overrided = NO; for (NSString *protocolName in protocols) { char *types = methodTypesInProtocol(protocolName, selectorName, isInstance, YES); if (!types) types = methodTypesInProtocol(protocolName, selectorName, isInstance, NO); if (types) { overrideMethod(currCls, selectorName, jsMethod, !isInstance, types); free(types); overrided = YES; break; } } if (!overrided) { if (![[jsMethodName substringToIndex:1] isEqualToString:@"_"]) { NSMutableString *typeDescStr = [@"@@:" mutableCopy]; for (int i = 0; i < numberOfArg; i ++) { [typeDescStr appendString:@"@"]; } overrideMethod(currCls, selectorName, jsMethod, !isInstance, [typeDescStr cStringUsingEncoding:NSUTF8StringEncoding]); } } } } } class_addMethod(cls, @selector(getProp:), (IMP)getPropIMP, "@@:@"); class_addMethod(cls, @selector(setProp:forKey:), (IMP)setPropIMP, "v@:@@"); return @{@"cls": className, @"superCls": superClassName}; } static JSValue *getJSFunctionInObjectHierachy(id slf, NSString *selectorName) { Class cls = object_getClass(slf); if (_currInvokeSuperClsName[selectorName]) { cls = NSClassFromString(_currInvokeSuperClsName[selectorName]); selectorName = [selectorName stringByReplacingOccurrencesOfString:@"_JPSUPER_" withString:@"_JP"]; } JSValue *func = _JSOverideMethods[cls][selectorName]; while (!func) { cls = class_getSuperclass(cls); if (!cls) { return nil; } func = _JSOverideMethods[cls][selectorName]; } return func; } static void JPForwardInvocation(__unsafe_unretained id assignSlf, SEL selector, NSInvocation *invocation) { #ifdef DEBUG _JSLastCallStack = [NSThread callStackSymbols]; #endif BOOL deallocFlag = NO; id slf = assignSlf; BOOL isBlock = [[assignSlf class] isSubclassOfClass : NSClassFromString(@"NSBlock")]; NSMethodSignature *methodSignature = [invocation methodSignature]; NSInteger numberOfArguments = [methodSignature numberOfArguments]; NSString *selectorName = isBlock ? @"" : NSStringFromSelector(invocation.selector); NSString *JPSelectorName = [NSString stringWithFormat:@"_JP%@", selectorName]; JSValue *jsFunc = isBlock ? objc_getAssociatedObject(assignSlf, "_JSValue")[@"cb"] : getJSFunctionInObjectHierachy(slf, JPSelectorName); if (!jsFunc) { JPExecuteORIGForwardInvocation(slf, selector, invocation); return; } NSMutableArray *argList = [[NSMutableArray alloc] init]; if (!isBlock) { if ([slf class] == slf) { [argList addObject:[JSValue valueWithObject:@{@"__clsName": NSStringFromClass([slf class])} inContext:_context]]; } else if ([selectorName isEqualToString:@"dealloc"]) { [argList addObject:[JPBoxing boxAssignObj:slf]]; deallocFlag = YES; } else { [argList addObject:[JPBoxing boxWeakObj:slf]]; } } for (NSUInteger i = isBlock ? 1 : 2; i < numberOfArguments; i++) { const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; switch(argumentType[0] == 'r' ? argumentType[1] : argumentType[0]) { #define JP_FWD_ARG_CASE(_typeChar, _type) \ case _typeChar: { \ _type arg; \ [invocation getArgument:&arg atIndex:i]; \ [argList addObject:@(arg)]; \ break; \ } JP_FWD_ARG_CASE('c', char) JP_FWD_ARG_CASE('C', unsigned char) JP_FWD_ARG_CASE('s', short) JP_FWD_ARG_CASE('S', unsigned short) JP_FWD_ARG_CASE('i', int) JP_FWD_ARG_CASE('I', unsigned int) JP_FWD_ARG_CASE('l', long) JP_FWD_ARG_CASE('L', unsigned long) JP_FWD_ARG_CASE('q', long long) JP_FWD_ARG_CASE('Q', unsigned long long) JP_FWD_ARG_CASE('f', float) JP_FWD_ARG_CASE('d', double) JP_FWD_ARG_CASE('B', BOOL) case '@': { __unsafe_unretained id arg; [invocation getArgument:&arg atIndex:i]; if ([arg isKindOfClass:NSClassFromString(@"NSBlock")]) { [argList addObject:(arg ? [arg copy]: _nilObj)]; } else { [argList addObject:(arg ? arg: _nilObj)]; } break; } case '{': { NSString *typeString = extractStructName([NSString stringWithUTF8String:argumentType]); #define JP_FWD_ARG_STRUCT(_type, _transFunc) \ if ([typeString rangeOfString:@#_type].location != NSNotFound) { \ _type arg; \ [invocation getArgument:&arg atIndex:i]; \ [argList addObject:[JSValue _transFunc:arg inContext:_context]]; \ break; \ } JP_FWD_ARG_STRUCT(CGRect, valueWithRect) JP_FWD_ARG_STRUCT(CGPoint, valueWithPoint) JP_FWD_ARG_STRUCT(CGSize, valueWithSize) JP_FWD_ARG_STRUCT(NSRange, valueWithRange) @synchronized (_context) { NSDictionary *structDefine = _registeredStruct[typeString]; if (structDefine) { size_t size = sizeOfStructTypes(structDefine[@"types"]); if (size) { void *ret = malloc(size); [invocation getArgument:ret atIndex:i]; NSDictionary *dict = getDictOfStruct(ret, structDefine); [argList addObject:[JSValue valueWithObject:dict inContext:_context]]; free(ret); break; } } } break; } case ':': { SEL selector; [invocation getArgument:&selector atIndex:i]; NSString *selectorName = NSStringFromSelector(selector); [argList addObject:(selectorName ? selectorName: _nilObj)]; break; } case '^': case '*': { void *arg; [invocation getArgument:&arg atIndex:i]; [argList addObject:[JPBoxing boxPointer:arg]]; break; } case '#': { Class arg; [invocation getArgument:&arg atIndex:i]; [argList addObject:[JPBoxing boxClass:arg]]; break; } default: { NSLog(@"error type %s", argumentType); break; } } } if (_currInvokeSuperClsName[selectorName]) { Class cls = NSClassFromString(_currInvokeSuperClsName[selectorName]); NSString *tmpSelectorName = [[selectorName stringByReplacingOccurrencesOfString:@"_JPSUPER_" withString:@"_JP"] stringByReplacingOccurrencesOfString:@"SUPER_" withString:@"_JP"]; if (!_JSOverideMethods[cls][tmpSelectorName]) { NSString *ORIGSelectorName = [selectorName stringByReplacingOccurrencesOfString:@"SUPER_" withString:@"ORIG"]; [argList removeObjectAtIndex:0]; id retObj = callSelector(_currInvokeSuperClsName[selectorName], ORIGSelectorName, [JSValue valueWithObject:argList inContext:_context], [JSValue valueWithObject:@{@"__obj": slf, @"__realClsName": @""} inContext:_context], NO); id __autoreleasing ret = formatJSToOC([JSValue valueWithObject:retObj inContext:_context]); [invocation setReturnValue:&ret]; return; } } NSArray *params = _formatOCToJSList(argList); char returnType[255]; strcpy(returnType, [methodSignature methodReturnType]); // Restore the return type if (strcmp(returnType, @encode(JPDouble)) == 0) { strcpy(returnType, @encode(double)); } if (strcmp(returnType, @encode(JPFloat)) == 0) { strcpy(returnType, @encode(float)); } switch (returnType[0] == 'r' ? returnType[1] : returnType[0]) { #define JP_FWD_RET_CALL_JS \ JSValue *jsval; \ [_JSMethodForwardCallLock lock]; \ jsval = [jsFunc callWithArguments:params]; \ [_JSMethodForwardCallLock unlock]; \ while (![jsval isNull] && ![jsval isUndefined] && [jsval hasProperty:@"__isPerformInOC"]) { \ NSArray *args = nil; \ JSValue *cb = jsval[@"cb"]; \ if ([jsval hasProperty:@"sel"]) { \ id callRet = callSelector(![jsval[@"clsName"] isUndefined] ? [jsval[@"clsName"] toString] : nil, [jsval[@"sel"] toString], jsval[@"args"], ![jsval[@"obj"] isUndefined] ? jsval[@"obj"] : nil, NO); \ args = @[[_context[@"_formatOCToJS"] callWithArguments:callRet ? @[callRet] : _formatOCToJSList(@[_nilObj])]]; \ } \ [_JSMethodForwardCallLock lock]; \ jsval = [cb callWithArguments:args]; \ [_JSMethodForwardCallLock unlock]; \ } #define JP_FWD_RET_CASE_RET(_typeChar, _type, _retCode) \ case _typeChar : { \ JP_FWD_RET_CALL_JS \ _retCode \ [invocation setReturnValue:&ret];\ break; \ } #define JP_FWD_RET_CASE(_typeChar, _type, _typeSelector) \ JP_FWD_RET_CASE_RET(_typeChar, _type, _type ret = [[jsval toObject] _typeSelector];) \ #define JP_FWD_RET_CODE_ID \ id __autoreleasing ret = formatJSToOC(jsval); \ if (ret == _nilObj || \ ([ret isKindOfClass:[NSNumber class]] && strcmp([ret objCType], "c") == 0 && ![ret boolValue])) ret = nil; \ #define JP_FWD_RET_CODE_POINTER \ void *ret; \ id obj = formatJSToOC(jsval); \ if ([obj isKindOfClass:[JPBoxing class]]) { \ ret = [((JPBoxing *)obj) unboxPointer]; \ } #define JP_FWD_RET_CODE_CLASS \ Class ret; \ ret = formatJSToOC(jsval); #define JP_FWD_RET_CODE_SEL \ SEL ret; \ id obj = formatJSToOC(jsval); \ if ([obj isKindOfClass:[NSString class]]) { \ ret = NSSelectorFromString(obj); \ } JP_FWD_RET_CASE_RET('@', id, JP_FWD_RET_CODE_ID) JP_FWD_RET_CASE_RET('^', void*, JP_FWD_RET_CODE_POINTER) JP_FWD_RET_CASE_RET('*', void*, JP_FWD_RET_CODE_POINTER) JP_FWD_RET_CASE_RET('#', Class, JP_FWD_RET_CODE_CLASS) JP_FWD_RET_CASE_RET(':', SEL, JP_FWD_RET_CODE_SEL) JP_FWD_RET_CASE('c', char, charValue) JP_FWD_RET_CASE('C', unsigned char, unsignedCharValue) JP_FWD_RET_CASE('s', short, shortValue) JP_FWD_RET_CASE('S', unsigned short, unsignedShortValue) JP_FWD_RET_CASE('i', int, intValue) JP_FWD_RET_CASE('I', unsigned int, unsignedIntValue) JP_FWD_RET_CASE('l', long, longValue) JP_FWD_RET_CASE('L', unsigned long, unsignedLongValue) JP_FWD_RET_CASE('q', long long, longLongValue) JP_FWD_RET_CASE('Q', unsigned long long, unsignedLongLongValue) JP_FWD_RET_CASE('f', float, floatValue) JP_FWD_RET_CASE('d', double, doubleValue) JP_FWD_RET_CASE('B', BOOL, boolValue) case 'v': { JP_FWD_RET_CALL_JS break; } case '{': { NSString *typeString = extractStructName([NSString stringWithUTF8String:returnType]); #define JP_FWD_RET_STRUCT(_type, _funcSuffix) \ if ([typeString rangeOfString:@#_type].location != NSNotFound) { \ JP_FWD_RET_CALL_JS \ _type ret = [jsval _funcSuffix]; \ [invocation setReturnValue:&ret];\ break; \ } JP_FWD_RET_STRUCT(CGRect, toRect) JP_FWD_RET_STRUCT(CGPoint, toPoint) JP_FWD_RET_STRUCT(CGSize, toSize) JP_FWD_RET_STRUCT(NSRange, toRange) @synchronized (_context) { NSDictionary *structDefine = _registeredStruct[typeString]; if (structDefine) { size_t size = sizeOfStructTypes(structDefine[@"types"]); JP_FWD_RET_CALL_JS void *ret = malloc(size); NSDictionary *dict = formatJSToOC(jsval); getStructDataWithDict(ret, dict, structDefine); [invocation setReturnValue:ret]; free(ret); } } break; } default: { break; } } if (_pointersToRelease) { for (NSValue *val in _pointersToRelease) { void *pointer = NULL; [val getValue:&pointer]; CFRelease(pointer); } _pointersToRelease = nil; } if (deallocFlag) { slf = nil; Class instClass = object_getClass(assignSlf); Method deallocMethod = class_getInstanceMethod(instClass, NSSelectorFromString(@"ORIGdealloc")); void (*originalDealloc)(__unsafe_unretained id, SEL) = (__typeof__(originalDealloc))method_getImplementation(deallocMethod); originalDealloc(assignSlf, NSSelectorFromString(@"dealloc")); } } static void JPExecuteORIGForwardInvocation(id slf, SEL selector, NSInvocation *invocation) { SEL origForwardSelector = @selector(ORIGforwardInvocation:); if ([slf respondsToSelector:origForwardSelector]) { NSMethodSignature *methodSignature = [slf methodSignatureForSelector:origForwardSelector]; if (!methodSignature) { _exceptionBlock([NSString stringWithFormat:@"unrecognized selector -ORIGforwardInvocation: for instance %@", slf]); return; } NSInvocation *forwardInv= [NSInvocation invocationWithMethodSignature:methodSignature]; [forwardInv setTarget:slf]; [forwardInv setSelector:origForwardSelector]; [forwardInv setArgument:&invocation atIndex:2]; [forwardInv invoke]; } else { Class superCls = [[slf class] superclass]; Method superForwardMethod = class_getInstanceMethod(superCls, @selector(forwardInvocation:)); void (*superForwardIMP)(id, SEL, NSInvocation *); superForwardIMP = (void (*)(id, SEL, NSInvocation *))method_getImplementation(superForwardMethod); superForwardIMP(slf, @selector(forwardInvocation:), invocation); } } static void _initJPOverideMethods(Class cls) { if (!_JSOverideMethods) { _JSOverideMethods = [[NSMutableDictionary alloc] init]; } if (!_JSOverideMethods[cls]) { _JSOverideMethods[(id)cls] = [[NSMutableDictionary alloc] init]; } } static void overrideMethod(Class cls, NSString *selectorName, JSValue *function, BOOL isClassMethod, const char *typeDescription) { SEL selector = NSSelectorFromString(selectorName); if (!typeDescription) { Method method = class_getInstanceMethod(cls, selector); typeDescription = (char *)method_getTypeEncoding(method); } IMP originalImp = class_respondsToSelector(cls, selector) ? class_getMethodImplementation(cls, selector) : NULL; IMP msgForwardIMP = _objc_msgForward; #if !defined(__arm64__) if (typeDescription[0] == '{') { //In some cases that returns struct, we should use the '_stret' API: //http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html //NSMethodSignature knows the detail but has no API to return, we can only get the info from debugDescription. NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:typeDescription]; if ([methodSignature.debugDescription rangeOfString:@"is special struct return? YES"].location != NSNotFound) { msgForwardIMP = (IMP)_objc_msgForward_stret; } } #endif if (class_getMethodImplementation(cls, @selector(forwardInvocation:)) != (IMP)JPForwardInvocation) { IMP originalForwardImp = class_replaceMethod(cls, @selector(forwardInvocation:), (IMP)JPForwardInvocation, "v@:@"); if (originalForwardImp) { class_addMethod(cls, @selector(ORIGforwardInvocation:), originalForwardImp, "v@:@"); } } [cls jp_fixMethodSignature]; if (class_respondsToSelector(cls, selector)) { NSString *originalSelectorName = [NSString stringWithFormat:@"ORIG%@", selectorName]; SEL originalSelector = NSSelectorFromString(originalSelectorName); if(!class_respondsToSelector(cls, originalSelector)) { class_addMethod(cls, originalSelector, originalImp, typeDescription); } } NSString *JPSelectorName = [NSString stringWithFormat:@"_JP%@", selectorName]; _initJPOverideMethods(cls); _JSOverideMethods[cls][JPSelectorName] = function; // Replace the original selector at last, preventing threading issus when // the selector get called during the execution of `overrideMethod` class_replaceMethod(cls, selector, msgForwardIMP, typeDescription); } #pragma mark - static id callSelector(NSString *className, NSString *selectorName, JSValue *arguments, JSValue *instance, BOOL isSuper) { NSString *realClsName = [[instance valueForProperty:@"__realClsName"] toString]; if (instance) { instance = formatJSToOC(instance); if (class_isMetaClass(object_getClass(instance))) { className = NSStringFromClass((Class)instance); instance = nil; } else if (!instance || instance == _nilObj || [instance isKindOfClass:[JPBoxing class]]) { return @{@"__isNil": @(YES)}; } } id argumentsObj = formatJSToOC(arguments); if (instance && [selectorName isEqualToString:@"toJS"]) { if ([instance isKindOfClass:[NSString class]] || [instance isKindOfClass:[NSDictionary class]] || [instance isKindOfClass:[NSArray class]] || [instance isKindOfClass:[NSDate class]]) { return _unboxOCObjectToJS(instance); } } Class cls = instance ? [instance class] : NSClassFromString(className); SEL selector = NSSelectorFromString(selectorName); NSString *superClassName = nil; if (isSuper) { NSString *superSelectorName = [NSString stringWithFormat:@"SUPER_%@", selectorName]; SEL superSelector = NSSelectorFromString(superSelectorName); Class superCls; if (realClsName.length) { Class defineClass = NSClassFromString(realClsName); superCls = defineClass ? [defineClass superclass] : [cls superclass]; } else { superCls = [cls superclass]; } Method superMethod = class_getInstanceMethod(superCls, selector); IMP superIMP = method_getImplementation(superMethod); class_addMethod(cls, superSelector, superIMP, method_getTypeEncoding(superMethod)); NSString *JPSelectorName = [NSString stringWithFormat:@"_JP%@", selectorName]; JSValue *overideFunction = _JSOverideMethods[superCls][JPSelectorName]; if (overideFunction) { overrideMethod(cls, superSelectorName, overideFunction, NO, NULL); } selector = superSelector; superClassName = NSStringFromClass(superCls); } NSMutableArray *_markArray; NSInvocation *invocation; NSMethodSignature *methodSignature; if (!_JSMethodSignatureCache) { _JSMethodSignatureCache = [[NSMutableDictionary alloc]init]; } if (instance) { [_JSMethodSignatureLock lock]; if (!_JSMethodSignatureCache[cls]) { _JSMethodSignatureCache[(id)cls] = [[NSMutableDictionary alloc]init]; } methodSignature = _JSMethodSignatureCache[cls][selectorName]; if (!methodSignature) { methodSignature = [cls instanceMethodSignatureForSelector:selector]; methodSignature = fixSignature(methodSignature); _JSMethodSignatureCache[cls][selectorName] = methodSignature; } [_JSMethodSignatureLock unlock]; if (!methodSignature) { _exceptionBlock([NSString stringWithFormat:@"unrecognized selector %@ for instance %@", selectorName, instance]); return nil; } invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation setTarget:instance]; } else { methodSignature = [cls methodSignatureForSelector:selector]; methodSignature = fixSignature(methodSignature); if (!methodSignature) { _exceptionBlock([NSString stringWithFormat:@"unrecognized selector %@ for class %@", selectorName, className]); return nil; } invocation= [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation setTarget:cls]; } [invocation setSelector:selector]; NSUInteger numberOfArguments = methodSignature.numberOfArguments; NSInteger inputArguments = [(NSArray *)argumentsObj count]; if (inputArguments > numberOfArguments - 2) { // calling variable argument method, only support parameter type `id` and return type `id` id sender = instance != nil ? instance : cls; id result = invokeVariableParameterMethod(argumentsObj, methodSignature, sender, selector); return formatOCToJS(result); } for (NSUInteger i = 2; i < numberOfArguments; i++) { const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; id valObj = argumentsObj[i-2]; switch (argumentType[0] == 'r' ? argumentType[1] : argumentType[0]) { #define JP_CALL_ARG_CASE(_typeString, _type, _selector) \ case _typeString: { \ _type value = [valObj _selector]; \ [invocation setArgument:&value atIndex:i];\ break; \ } JP_CALL_ARG_CASE('c', char, charValue) JP_CALL_ARG_CASE('C', unsigned char, unsignedCharValue) JP_CALL_ARG_CASE('s', short, shortValue) JP_CALL_ARG_CASE('S', unsigned short, unsignedShortValue) JP_CALL_ARG_CASE('i', int, intValue) JP_CALL_ARG_CASE('I', unsigned int, unsignedIntValue) JP_CALL_ARG_CASE('l', long, longValue) JP_CALL_ARG_CASE('L', unsigned long, unsignedLongValue) JP_CALL_ARG_CASE('q', long long, longLongValue) JP_CALL_ARG_CASE('Q', unsigned long long, unsignedLongLongValue) JP_CALL_ARG_CASE('f', float, floatValue) JP_CALL_ARG_CASE('d', double, doubleValue) JP_CALL_ARG_CASE('B', BOOL, boolValue) case ':': { SEL value = nil; if (valObj != _nilObj) { value = NSSelectorFromString(valObj); } [invocation setArgument:&value atIndex:i]; break; } case '{': { NSString *typeString = extractStructName([NSString stringWithUTF8String:argumentType]); JSValue *val = arguments[i-2]; #define JP_CALL_ARG_STRUCT(_type, _methodName) \ if ([typeString rangeOfString:@#_type].location != NSNotFound) { \ _type value = [val _methodName]; \ [invocation setArgument:&value atIndex:i]; \ break; \ } JP_CALL_ARG_STRUCT(CGRect, toRect) JP_CALL_ARG_STRUCT(CGPoint, toPoint) JP_CALL_ARG_STRUCT(CGSize, toSize) JP_CALL_ARG_STRUCT(NSRange, toRange) @synchronized (_context) { NSDictionary *structDefine = _registeredStruct[typeString]; if (structDefine) { size_t size = sizeOfStructTypes(structDefine[@"types"]); void *ret = malloc(size); getStructDataWithDict(ret, valObj, structDefine); [invocation setArgument:ret atIndex:i]; free(ret); break; } } break; } case '*': case '^': { if ([valObj isKindOfClass:[JPBoxing class]]) { void *value = [((JPBoxing *)valObj) unboxPointer]; if (argumentType[1] == '@') { if (!_TMPMemoryPool) { _TMPMemoryPool = [[NSMutableDictionary alloc] init]; } if (!_markArray) { _markArray = [[NSMutableArray alloc] init]; } memset(value, 0, sizeof(id)); [_markArray addObject:valObj]; } [invocation setArgument:&value atIndex:i]; break; } } case '#': { if ([valObj isKindOfClass:[JPBoxing class]]) { Class value = [((JPBoxing *)valObj) unboxClass]; [invocation setArgument:&value atIndex:i]; break; } } default: { if (valObj == _nullObj) { valObj = [NSNull null]; [invocation setArgument:&valObj atIndex:i]; break; } if (valObj == _nilObj || ([valObj isKindOfClass:[NSNumber class]] && strcmp([valObj objCType], "c") == 0 && ![valObj boolValue])) { valObj = nil; [invocation setArgument:&valObj atIndex:i]; break; } if ([(JSValue *)arguments[i-2] hasProperty:@"__isBlock"]) { JSValue *blkJSVal = arguments[i-2]; Class JPBlockClass = NSClassFromString(@"JPBlock"); if (JPBlockClass && ![blkJSVal[@"blockObj"] isUndefined]) { __autoreleasing id cb = [JPBlockClass performSelector:@selector(blockWithBlockObj:) withObject:[blkJSVal[@"blockObj"] toObject]]; [invocation setArgument:&cb atIndex:i]; Block_release((__bridge void *)cb); } else { __autoreleasing id cb = genCallbackBlock(arguments[i-2]); [invocation setArgument:&cb atIndex:i]; } } else { [invocation setArgument:&valObj atIndex:i]; } } } } if (superClassName) _currInvokeSuperClsName[selectorName] = superClassName; [invocation invoke]; if (superClassName) [_currInvokeSuperClsName removeObjectForKey:selectorName]; if ([_markArray count] > 0) { for (JPBoxing *box in _markArray) { void *pointer = [box unboxPointer]; id obj = *((__unsafe_unretained id *)pointer); if (obj) { @synchronized(_TMPMemoryPool) { [_TMPMemoryPool setObject:obj forKey:[NSNumber numberWithInteger:[(NSObject*)obj hash]]]; } } } } char returnType[255]; strcpy(returnType, [methodSignature methodReturnType]); // Restore the return type if (strcmp(returnType, @encode(JPDouble)) == 0) { strcpy(returnType, @encode(double)); } if (strcmp(returnType, @encode(JPFloat)) == 0) { strcpy(returnType, @encode(float)); } id returnValue; if (strncmp(returnType, "v", 1) != 0) { if (strncmp(returnType, "@", 1) == 0) { void *result; [invocation getReturnValue:&result]; //For performance, ignore the other methods prefix with alloc/new/copy/mutableCopy if ([selectorName isEqualToString:@"alloc"] || [selectorName isEqualToString:@"new"] || [selectorName isEqualToString:@"copy"] || [selectorName isEqualToString:@"mutableCopy"]) { returnValue = (__bridge_transfer id)result; } else { returnValue = (__bridge id)result; } return formatOCToJS(returnValue); } else { switch (returnType[0] == 'r' ? returnType[1] : returnType[0]) { #define JP_CALL_RET_CASE(_typeString, _type) \ case _typeString: { \ _type tempResultSet; \ [invocation getReturnValue:&tempResultSet];\ returnValue = @(tempResultSet); \ break; \ } JP_CALL_RET_CASE('c', char) JP_CALL_RET_CASE('C', unsigned char) JP_CALL_RET_CASE('s', short) JP_CALL_RET_CASE('S', unsigned short) JP_CALL_RET_CASE('i', int) JP_CALL_RET_CASE('I', unsigned int) JP_CALL_RET_CASE('l', long) JP_CALL_RET_CASE('L', unsigned long) JP_CALL_RET_CASE('q', long long) JP_CALL_RET_CASE('Q', unsigned long long) JP_CALL_RET_CASE('f', float) JP_CALL_RET_CASE('d', double) JP_CALL_RET_CASE('B', BOOL) case '{': { NSString *typeString = extractStructName([NSString stringWithUTF8String:returnType]); #define JP_CALL_RET_STRUCT(_type, _methodName) \ if ([typeString rangeOfString:@#_type].location != NSNotFound) { \ _type result; \ [invocation getReturnValue:&result]; \ return [JSValue _methodName:result inContext:_context]; \ } JP_CALL_RET_STRUCT(CGRect, valueWithRect) JP_CALL_RET_STRUCT(CGPoint, valueWithPoint) JP_CALL_RET_STRUCT(CGSize, valueWithSize) JP_CALL_RET_STRUCT(NSRange, valueWithRange) @synchronized (_context) { NSDictionary *structDefine = _registeredStruct[typeString]; if (structDefine) { size_t size = sizeOfStructTypes(structDefine[@"types"]); void *ret = malloc(size); [invocation getReturnValue:ret]; NSDictionary *dict = getDictOfStruct(ret, structDefine); free(ret); return dict; } } break; } case '*': case '^': { void *result; [invocation getReturnValue:&result]; returnValue = formatOCToJS([JPBoxing boxPointer:result]); if (strncmp(returnType, "^{CG", 4) == 0) { if (!_pointersToRelease) { _pointersToRelease = [[NSMutableArray alloc] init]; } [_pointersToRelease addObject:[NSValue valueWithPointer:result]]; CFRetain(result); } break; } case '#': { Class result; [invocation getReturnValue:&result]; returnValue = formatOCToJS([JPBoxing boxClass:result]); break; } } return returnValue; } } return nil; } static id (*new_msgSend1)(id, SEL, id,...) = (id (*)(id, SEL, id,...)) objc_msgSend; static id (*new_msgSend2)(id, SEL, id, id,...) = (id (*)(id, SEL, id, id,...)) objc_msgSend; static id (*new_msgSend3)(id, SEL, id, id, id,...) = (id (*)(id, SEL, id, id, id,...)) objc_msgSend; static id (*new_msgSend4)(id, SEL, id, id, id, id,...) = (id (*)(id, SEL, id, id, id, id,...)) objc_msgSend; static id (*new_msgSend5)(id, SEL, id, id, id, id, id,...) = (id (*)(id, SEL, id, id, id, id, id,...)) objc_msgSend; static id (*new_msgSend6)(id, SEL, id, id, id, id, id, id,...) = (id (*)(id, SEL, id, id, id, id, id, id,...)) objc_msgSend; static id (*new_msgSend7)(id, SEL, id, id, id, id, id, id, id,...) = (id (*)(id, SEL, id, id, id, id, id, id,id,...)) objc_msgSend; static id (*new_msgSend8)(id, SEL, id, id, id, id, id, id, id, id,...) = (id (*)(id, SEL, id, id, id, id, id, id, id, id,...)) objc_msgSend; static id (*new_msgSend9)(id, SEL, id, id, id, id, id, id, id, id, id,...) = (id (*)(id, SEL, id, id, id, id, id, id, id, id, id, ...)) objc_msgSend; static id (*new_msgSend10)(id, SEL, id, id, id, id, id, id, id, id, id, id,...) = (id (*)(id, SEL, id, id, id, id, id, id, id, id, id, id,...)) objc_msgSend; static id invokeVariableParameterMethod(NSMutableArray *origArgumentsList, NSMethodSignature *methodSignature, id sender, SEL selector) { NSInteger inputArguments = [(NSArray *)origArgumentsList count]; NSUInteger numberOfArguments = methodSignature.numberOfArguments; NSMutableArray *argumentsList = [[NSMutableArray alloc] init]; for (NSUInteger j = 0; j < inputArguments; j++) { NSInteger index = MIN(j + 2, numberOfArguments - 1); const char *argumentType = [methodSignature getArgumentTypeAtIndex:index]; id valObj = origArgumentsList[j]; char argumentTypeChar = argumentType[0] == 'r' ? argumentType[1] : argumentType[0]; if (argumentTypeChar == '@') { [argumentsList addObject:valObj]; } else { return nil; } } id results = nil; numberOfArguments = numberOfArguments - 2; //If you want to debug the macro code below, replace it to the expanded code: //https://gist.github.com/bang590/ca3720ae1da594252a2e #define JP_G_ARG(_idx) getArgument(argumentsList[_idx]) #define JP_CALL_MSGSEND_ARG1(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0)); #define JP_CALL_MSGSEND_ARG2(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1)); #define JP_CALL_MSGSEND_ARG3(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2)); #define JP_CALL_MSGSEND_ARG4(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2), JP_G_ARG(3)); #define JP_CALL_MSGSEND_ARG5(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2), JP_G_ARG(3), JP_G_ARG(4)); #define JP_CALL_MSGSEND_ARG6(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2), JP_G_ARG(3), JP_G_ARG(4), JP_G_ARG(5)); #define JP_CALL_MSGSEND_ARG7(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2), JP_G_ARG(3), JP_G_ARG(4), JP_G_ARG(5), JP_G_ARG(6)); #define JP_CALL_MSGSEND_ARG8(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2), JP_G_ARG(3), JP_G_ARG(4), JP_G_ARG(5), JP_G_ARG(6), JP_G_ARG(7)); #define JP_CALL_MSGSEND_ARG9(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2), JP_G_ARG(3), JP_G_ARG(4), JP_G_ARG(5), JP_G_ARG(6), JP_G_ARG(7), JP_G_ARG(8)); #define JP_CALL_MSGSEND_ARG10(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2), JP_G_ARG(3), JP_G_ARG(4), JP_G_ARG(5), JP_G_ARG(6), JP_G_ARG(7), JP_G_ARG(8), JP_G_ARG(9)); #define JP_CALL_MSGSEND_ARG11(_num) results = new_msgSend##_num(sender, selector, JP_G_ARG(0), JP_G_ARG(1), JP_G_ARG(2), JP_G_ARG(3), JP_G_ARG(4), JP_G_ARG(5), JP_G_ARG(6), JP_G_ARG(7), JP_G_ARG(8), JP_G_ARG(9), JP_G_ARG(10)); #define JP_IF_REAL_ARG_COUNT(_num) if([argumentsList count] == _num) #define JP_DEAL_MSGSEND(_realArgCount, _defineArgCount) \ if(numberOfArguments == _defineArgCount) { \ JP_CALL_MSGSEND_ARG##_realArgCount(_defineArgCount) \ } JP_IF_REAL_ARG_COUNT(1) { JP_CALL_MSGSEND_ARG1(1) } JP_IF_REAL_ARG_COUNT(2) { JP_DEAL_MSGSEND(2, 1) JP_DEAL_MSGSEND(2, 2) } JP_IF_REAL_ARG_COUNT(3) { JP_DEAL_MSGSEND(3, 1) JP_DEAL_MSGSEND(3, 2) JP_DEAL_MSGSEND(3, 3) } JP_IF_REAL_ARG_COUNT(4) { JP_DEAL_MSGSEND(4, 1) JP_DEAL_MSGSEND(4, 2) JP_DEAL_MSGSEND(4, 3) JP_DEAL_MSGSEND(4, 4) } JP_IF_REAL_ARG_COUNT(5) { JP_DEAL_MSGSEND(5, 1) JP_DEAL_MSGSEND(5, 2) JP_DEAL_MSGSEND(5, 3) JP_DEAL_MSGSEND(5, 4) JP_DEAL_MSGSEND(5, 5) } JP_IF_REAL_ARG_COUNT(6) { JP_DEAL_MSGSEND(6, 1) JP_DEAL_MSGSEND(6, 2) JP_DEAL_MSGSEND(6, 3) JP_DEAL_MSGSEND(6, 4) JP_DEAL_MSGSEND(6, 5) JP_DEAL_MSGSEND(6, 6) } JP_IF_REAL_ARG_COUNT(7) { JP_DEAL_MSGSEND(7, 1) JP_DEAL_MSGSEND(7, 2) JP_DEAL_MSGSEND(7, 3) JP_DEAL_MSGSEND(7, 4) JP_DEAL_MSGSEND(7, 5) JP_DEAL_MSGSEND(7, 6) JP_DEAL_MSGSEND(7, 7) } JP_IF_REAL_ARG_COUNT(8) { JP_DEAL_MSGSEND(8, 1) JP_DEAL_MSGSEND(8, 2) JP_DEAL_MSGSEND(8, 3) JP_DEAL_MSGSEND(8, 4) JP_DEAL_MSGSEND(8, 5) JP_DEAL_MSGSEND(8, 6) JP_DEAL_MSGSEND(8, 7) JP_DEAL_MSGSEND(8, 8) } JP_IF_REAL_ARG_COUNT(9) { JP_DEAL_MSGSEND(9, 1) JP_DEAL_MSGSEND(9, 2) JP_DEAL_MSGSEND(9, 3) JP_DEAL_MSGSEND(9, 4) JP_DEAL_MSGSEND(9, 5) JP_DEAL_MSGSEND(9, 6) JP_DEAL_MSGSEND(9, 7) JP_DEAL_MSGSEND(9, 8) JP_DEAL_MSGSEND(9, 9) } JP_IF_REAL_ARG_COUNT(10) { JP_DEAL_MSGSEND(10, 1) JP_DEAL_MSGSEND(10, 2) JP_DEAL_MSGSEND(10, 3) JP_DEAL_MSGSEND(10, 4) JP_DEAL_MSGSEND(10, 5) JP_DEAL_MSGSEND(10, 6) JP_DEAL_MSGSEND(10, 7) JP_DEAL_MSGSEND(10, 8) JP_DEAL_MSGSEND(10, 9) JP_DEAL_MSGSEND(10, 10) } return results; } NSMethodSignature *block_methodSignatureForSelector(id self, SEL _cmd, SEL aSelector) { uint8_t *p = (uint8_t *)((__bridge void *)self); p += sizeof(void *) * 2 + sizeof(int32_t) *2 + sizeof(uintptr_t) * 2; const char **signature = (const char **)p; return [NSMethodSignature signatureWithObjCTypes:*signature]; } static id getArgument(id valObj){ if (valObj == _nilObj || ([valObj isKindOfClass:[NSNumber class]] && strcmp([valObj objCType], "c") == 0 && ![valObj boolValue])) { return nil; } return valObj; } #pragma mark - static id genCallbackBlock(JSValue *jsVal) { void (^block)(void) = ^(void){}; uint8_t *p = (uint8_t *)((__bridge void *)block); p += sizeof(void *) + sizeof(int32_t) *2; void(**invoke)(void) = (void (**)(void))p; p += sizeof(void *) + sizeof(uintptr_t) * 2; const char **signature = (const char **)p; static NSMutableDictionary *typeSignatureDict; if (!typeSignatureDict) { typeSignatureDict = [NSMutableDictionary new]; #define JP_DEFINE_TYPE_SIGNATURE(_type) \ [typeSignatureDict setObject:@[[NSString stringWithUTF8String:@encode(_type)], @(sizeof(_type))] forKey:@#_type];\ JP_DEFINE_TYPE_SIGNATURE(id); JP_DEFINE_TYPE_SIGNATURE(BOOL); JP_DEFINE_TYPE_SIGNATURE(int); JP_DEFINE_TYPE_SIGNATURE(void); JP_DEFINE_TYPE_SIGNATURE(char); JP_DEFINE_TYPE_SIGNATURE(short); JP_DEFINE_TYPE_SIGNATURE(unsigned short); JP_DEFINE_TYPE_SIGNATURE(unsigned int); JP_DEFINE_TYPE_SIGNATURE(long); JP_DEFINE_TYPE_SIGNATURE(unsigned long); JP_DEFINE_TYPE_SIGNATURE(long long); JP_DEFINE_TYPE_SIGNATURE(unsigned long long); JP_DEFINE_TYPE_SIGNATURE(float); JP_DEFINE_TYPE_SIGNATURE(double); JP_DEFINE_TYPE_SIGNATURE(bool); JP_DEFINE_TYPE_SIGNATURE(size_t); JP_DEFINE_TYPE_SIGNATURE(CGFloat); JP_DEFINE_TYPE_SIGNATURE(CGSize); JP_DEFINE_TYPE_SIGNATURE(CGRect); JP_DEFINE_TYPE_SIGNATURE(CGPoint); JP_DEFINE_TYPE_SIGNATURE(CGVector); JP_DEFINE_TYPE_SIGNATURE(NSRange); JP_DEFINE_TYPE_SIGNATURE(NSInteger); JP_DEFINE_TYPE_SIGNATURE(Class); JP_DEFINE_TYPE_SIGNATURE(SEL); JP_DEFINE_TYPE_SIGNATURE(void*); JP_DEFINE_TYPE_SIGNATURE(void *); } NSString *types = [jsVal[@"args"] toString]; NSArray *lt = [types componentsSeparatedByString:@","]; NSString *funcSignature = @"@?0"; NSInteger size = sizeof(void *); for (NSInteger i = 1; i < lt.count;) { NSString *t = trim(lt[i]); NSString *tpe = typeSignatureDict[typeSignatureDict[t] ? t : @"id"][0]; if (i == 0) { funcSignature =[[NSString stringWithFormat:@"%@%@",tpe, [@(size) stringValue]] stringByAppendingString:funcSignature]; break; } funcSignature = [funcSignature stringByAppendingString:[NSString stringWithFormat:@"%@%@", tpe, [@(size) stringValue]]]; size += [typeSignatureDict[typeSignatureDict[t] ? t : @"id"][1] integerValue]; i = (i != lt.count - 1) ? i + 1 : 0; } IMP msgForwardIMP = _objc_msgForward; #if !defined(__arm64__) if ([funcSignature UTF8String][0] == '{') { //In some cases that returns struct, we should use the '_stret' API: //http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html //NSMethodSignature knows the detail but has no API to return, we can only get the info from debugDescription. NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:[funcSignature UTF8String]]; if ([methodSignature.debugDescription rangeOfString:@"is special struct return? YES"].location != NSNotFound) { msgForwardIMP = (IMP)_objc_msgForward_stret; } } #endif *invoke = (void *)msgForwardIMP; const char *fs = [funcSignature UTF8String]; char *s = malloc(strlen(fs)); strcpy(s, fs); *signature = s; objc_setAssociatedObject(block, "_JSValue", jsVal, OBJC_ASSOCIATION_RETAIN_NONATOMIC); static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class cls = NSClassFromString(@"NSBlock"); #define JP_HOOK_METHOD(selector, func) {Method method = class_getInstanceMethod([NSObject class], selector); \ BOOL success = class_addMethod(cls, selector, (IMP)func, method_getTypeEncoding(method)); \ if (!success) { class_replaceMethod(cls, selector, (IMP)func, method_getTypeEncoding(method));}} JP_HOOK_METHOD(@selector(methodSignatureForSelector:), block_methodSignatureForSelector); JP_HOOK_METHOD(@selector(forwardInvocation:), JPForwardInvocation); }); return block; } #pragma mark - Struct static int sizeOfStructTypes(NSString *structTypes) { const char *types = [structTypes cStringUsingEncoding:NSUTF8StringEncoding]; int index = 0; int size = 0; while (types[index]) { switch (types[index]) { #define JP_STRUCT_SIZE_CASE(_typeChar, _type) \ case _typeChar: \ size += sizeof(_type); \ break; JP_STRUCT_SIZE_CASE('c', char) JP_STRUCT_SIZE_CASE('C', unsigned char) JP_STRUCT_SIZE_CASE('s', short) JP_STRUCT_SIZE_CASE('S', unsigned short) JP_STRUCT_SIZE_CASE('i', int) JP_STRUCT_SIZE_CASE('I', unsigned int) JP_STRUCT_SIZE_CASE('l', long) JP_STRUCT_SIZE_CASE('L', unsigned long) JP_STRUCT_SIZE_CASE('q', long long) JP_STRUCT_SIZE_CASE('Q', unsigned long long) JP_STRUCT_SIZE_CASE('f', float) JP_STRUCT_SIZE_CASE('F', CGFloat) JP_STRUCT_SIZE_CASE('N', NSInteger) JP_STRUCT_SIZE_CASE('U', NSUInteger) JP_STRUCT_SIZE_CASE('d', double) JP_STRUCT_SIZE_CASE('B', BOOL) JP_STRUCT_SIZE_CASE('*', void *) JP_STRUCT_SIZE_CASE('^', void *) case '{': { NSString *structTypeStr = [structTypes substringFromIndex:index]; NSUInteger end = [structTypeStr rangeOfString:@"}"].location; if (end != NSNotFound) { NSString *subStructName = [structTypeStr substringWithRange:NSMakeRange(1, end - 1)]; NSDictionary *subStructDefine = [JPExtension registeredStruct][subStructName]; NSString *subStructTypes = subStructDefine[@"types"]; size += sizeOfStructTypes(subStructTypes); index += (int)end; break; } } default: break; } index ++; } return size; } static void getStructDataWithDict(void *structData, NSDictionary *dict, NSDictionary *structDefine) { NSArray *itemKeys = structDefine[@"keys"]; const char *structTypes = [structDefine[@"types"] cStringUsingEncoding:NSUTF8StringEncoding]; int position = 0; for (NSString *itemKey in itemKeys) { switch(*structTypes) { #define JP_STRUCT_DATA_CASE(_typeStr, _type, _transMethod) \ case _typeStr: { \ int size = sizeof(_type); \ _type val = [dict[itemKey] _transMethod]; \ memcpy(structData + position, &val, size); \ position += size; \ break; \ } JP_STRUCT_DATA_CASE('c', char, charValue) JP_STRUCT_DATA_CASE('C', unsigned char, unsignedCharValue) JP_STRUCT_DATA_CASE('s', short, shortValue) JP_STRUCT_DATA_CASE('S', unsigned short, unsignedShortValue) JP_STRUCT_DATA_CASE('i', int, intValue) JP_STRUCT_DATA_CASE('I', unsigned int, unsignedIntValue) JP_STRUCT_DATA_CASE('l', long, longValue) JP_STRUCT_DATA_CASE('L', unsigned long, unsignedLongValue) JP_STRUCT_DATA_CASE('q', long long, longLongValue) JP_STRUCT_DATA_CASE('Q', unsigned long long, unsignedLongLongValue) JP_STRUCT_DATA_CASE('f', float, floatValue) JP_STRUCT_DATA_CASE('F', CGFloat, CGFloatValue) JP_STRUCT_DATA_CASE('d', double, doubleValue) JP_STRUCT_DATA_CASE('B', BOOL, boolValue) JP_STRUCT_DATA_CASE('N', NSInteger, integerValue) JP_STRUCT_DATA_CASE('U', NSUInteger, unsignedIntegerValue) case '*': case '^': { int size = sizeof(void *); void *val = [(JPBoxing *)dict[itemKey] unboxPointer]; memcpy(structData + position, &val, size); break; } case '{': { NSString *subStructName = [NSString stringWithCString:structTypes encoding:NSASCIIStringEncoding]; NSUInteger end = [subStructName rangeOfString:@"}"].location; if (end != NSNotFound) { subStructName = [subStructName substringWithRange:NSMakeRange(1, end - 1)]; NSDictionary *subStructDefine = [JPExtension registeredStruct][subStructName]; NSDictionary *subDict = dict[itemKey]; int size = sizeOfStructTypes(subStructDefine[@"types"]); getStructDataWithDict(structData + position, subDict, subStructDefine); position += size; structTypes += end; break; } } default: break; } structTypes ++; } } static NSDictionary *getDictOfStruct(void *structData, NSDictionary *structDefine) { NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; NSArray *itemKeys = structDefine[@"keys"]; const char *structTypes = [structDefine[@"types"] cStringUsingEncoding:NSUTF8StringEncoding]; int position = 0; for (NSString *itemKey in itemKeys) { switch(*structTypes) { #define JP_STRUCT_DICT_CASE(_typeName, _type) \ case _typeName: { \ size_t size = sizeof(_type); \ _type *val = malloc(size); \ memcpy(val, structData + position, size); \ [dict setObject:@(*val) forKey:itemKey]; \ free(val); \ position += size; \ break; \ } JP_STRUCT_DICT_CASE('c', char) JP_STRUCT_DICT_CASE('C', unsigned char) JP_STRUCT_DICT_CASE('s', short) JP_STRUCT_DICT_CASE('S', unsigned short) JP_STRUCT_DICT_CASE('i', int) JP_STRUCT_DICT_CASE('I', unsigned int) JP_STRUCT_DICT_CASE('l', long) JP_STRUCT_DICT_CASE('L', unsigned long) JP_STRUCT_DICT_CASE('q', long long) JP_STRUCT_DICT_CASE('Q', unsigned long long) JP_STRUCT_DICT_CASE('f', float) JP_STRUCT_DICT_CASE('F', CGFloat) JP_STRUCT_DICT_CASE('N', NSInteger) JP_STRUCT_DICT_CASE('U', NSUInteger) JP_STRUCT_DICT_CASE('d', double) JP_STRUCT_DICT_CASE('B', BOOL) case '*': case '^': { size_t size = sizeof(void *); void *val = malloc(size); memcpy(val, structData + position, size); [dict setObject:[JPBoxing boxPointer:val] forKey:itemKey]; position += size; break; } case '{': { NSString *subStructName = [NSString stringWithCString:structTypes encoding:NSASCIIStringEncoding]; NSUInteger end = [subStructName rangeOfString:@"}"].location; if (end != NSNotFound) { subStructName = [subStructName substringWithRange:NSMakeRange(1, end - 1)]; NSDictionary *subStructDefine = [JPExtension registeredStruct][subStructName]; int size = sizeOfStructTypes(subStructDefine[@"types"]); NSDictionary *subDict = getDictOfStruct(structData + position, subStructDefine); [dict setObject:subDict forKey:itemKey]; position += size; structTypes += end; break; } } } structTypes ++; } return dict; } static NSString *extractStructName(NSString *typeEncodeString) { NSArray *array = [typeEncodeString componentsSeparatedByString:@"="]; NSString *typeString = array[0]; int firstValidIndex = 0; for (int i = 0; i< typeString.length; i++) { char c = [typeString characterAtIndex:i]; if (c == '{' || c=='_') { firstValidIndex++; }else { break; } } return [typeString substringFromIndex:firstValidIndex]; } #pragma mark - Utils static NSString *trim(NSString *string) { return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; } static BOOL blockTypeIsObject(NSString *typeString) { return [typeString rangeOfString:@"*"].location != NSNotFound || [typeString isEqualToString:@"id"]; } static BOOL blockTypeIsScalarPointer(NSString *typeString) { NSUInteger location = [typeString rangeOfString:@"*"].location; NSString *typeWithoutAsterisk = trim([typeString stringByReplacingOccurrencesOfString:@"*" withString:@""]); return (location == typeString.length-1 && !NSClassFromString(typeWithoutAsterisk)); } static NSString *convertJPSelectorString(NSString *selectorString) { NSString *tmpJSMethodName = [selectorString stringByReplacingOccurrencesOfString:@"__" withString:@"-"]; NSString *selectorName = [tmpJSMethodName stringByReplacingOccurrencesOfString:@"_" withString:@":"]; return [selectorName stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; } #pragma mark - Object format static id formatOCToJS(id obj) { if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSDate class]]) { return _autoConvert ? obj: _wrapObj([JPBoxing boxObj:obj]); } if ([obj isKindOfClass:[NSNumber class]]) { return _convertOCNumberToString ? [(NSNumber*)obj stringValue] : obj; } if ([obj isKindOfClass:NSClassFromString(@"NSBlock")] || [obj isKindOfClass:[JSValue class]]) { return obj; } return _wrapObj(obj); } static id formatJSToOC(JSValue *jsval) { id obj = [jsval toObject]; if (!obj || [obj isKindOfClass:[NSNull class]]) return _nilObj; if ([obj isKindOfClass:[JPBoxing class]]) return [obj unbox]; if ([obj isKindOfClass:[NSArray class]]) { NSMutableArray *newArr = [[NSMutableArray alloc] init]; for (int i = 0; i < [(NSArray*)obj count]; i ++) { [newArr addObject:formatJSToOC(jsval[i])]; } return newArr; } if ([obj isKindOfClass:[NSDictionary class]]) { if (obj[@"__obj"]) { id ocObj = [obj objectForKey:@"__obj"]; if ([ocObj isKindOfClass:[JPBoxing class]]) return [ocObj unbox]; return ocObj; } else if (obj[@"__clsName"]) { return NSClassFromString(obj[@"__clsName"]); } if (obj[@"__isBlock"]) { Class JPBlockClass = NSClassFromString(@"JPBlock"); if (JPBlockClass && ![jsval[@"blockObj"] isUndefined]) { return [JPBlockClass performSelector:@selector(blockWithBlockObj:) withObject:[jsval[@"blockObj"] toObject]]; } else { return genCallbackBlock(jsval); } } NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init]; for (NSString *key in [obj allKeys]) { [newDict setObject:formatJSToOC(jsval[key]) forKey:key]; } return newDict; } return obj; } static id _formatOCToJSList(NSArray *list) { NSMutableArray *arr = [NSMutableArray new]; for (id obj in list) { [arr addObject:formatOCToJS(obj)]; } return arr; } static NSDictionary *_wrapObj(id obj) { if (!obj || obj == _nilObj) { return @{@"__isNil": @(YES)}; } return @{@"__obj": obj, @"__clsName": NSStringFromClass([obj isKindOfClass:[JPBoxing class]] ? [[((JPBoxing *)obj) unbox] class]: [obj class])}; } static id _unboxOCObjectToJS(id obj) { if ([obj isKindOfClass:[NSArray class]]) { NSMutableArray *newArr = [[NSMutableArray alloc] init]; for (int i = 0; i < [(NSArray*)obj count]; i ++) { [newArr addObject:_unboxOCObjectToJS(obj[i])]; } return newArr; } if ([obj isKindOfClass:[NSDictionary class]]) { NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init]; for (NSString *key in [obj allKeys]) { [newDict setObject:_unboxOCObjectToJS(obj[key]) forKey:key]; } return newDict; } if ([obj isKindOfClass:[NSString class]] ||[obj isKindOfClass:[NSNumber class]] || [obj isKindOfClass:NSClassFromString(@"NSBlock")] || [obj isKindOfClass:[NSDate class]]) { return obj; } return _wrapObj(obj); } #pragma clang diagnostic pop @end @implementation JPExtension + (void)main:(JSContext *)context{} + (void *)formatPointerJSToOC:(JSValue *)val { id obj = [val toObject]; if ([obj isKindOfClass:[NSDictionary class]]) { if (obj[@"__obj"] && [obj[@"__obj"] isKindOfClass:[JPBoxing class]]) { return [(JPBoxing *)(obj[@"__obj"]) unboxPointer]; } else { return NULL; } } else if (![val toBool]) { return NULL; } else{ return [((JPBoxing *)[val toObject]) unboxPointer]; } } + (id)formatRetainedCFTypeOCToJS:(CFTypeRef)CF_CONSUMED type { return formatOCToJS([JPBoxing boxPointer:(void *)type]); } + (id)formatPointerOCToJS:(void *)pointer { return formatOCToJS([JPBoxing boxPointer:pointer]); } + (id)formatJSToOC:(JSValue *)val { if (![val toBool]) { return nil; } return formatJSToOC(val); } + (id)formatOCToJS:(id)obj { JSContext *context = [JSContext currentContext] ? [JSContext currentContext]: _context; return [context[@"_formatOCToJS"] callWithArguments:@[formatOCToJS(obj)]]; } + (int)sizeOfStructTypes:(NSString *)structTypes { return sizeOfStructTypes(structTypes); } + (void)getStructDataWidthDict:(void *)structData dict:(NSDictionary *)dict structDefine:(NSDictionary *)structDefine { return getStructDataWithDict(structData, dict, structDefine); } + (NSDictionary *)getDictOfStruct:(void *)structData structDefine:(NSDictionary *)structDefine { return getDictOfStruct(structData, structDefine); } + (NSMutableDictionary *)registeredStruct { return _registeredStruct; } + (NSDictionary *)overideMethods { return _JSOverideMethods; } + (NSMutableSet *)includedScriptPaths { return _runnedScript; } @end ================================================ FILE: JSPatch/JSPatch.js ================================================ var global = this ;(function() { var _ocCls = {}; var _jsCls = {}; var _formatOCToJS = function(obj) { if (obj === undefined || obj === null) return false if (typeof obj == "object") { if (obj.__obj) return obj if (obj.__isNil) return false } if (obj instanceof Array) { var ret = [] obj.forEach(function(o) { ret.push(_formatOCToJS(o)) }) return ret } if (obj instanceof Function) { return function() { var args = Array.prototype.slice.call(arguments) var formatedArgs = _OC_formatJSToOC(args) for (var i = 0; i < args.length; i++) { if (args[i] === null || args[i] === undefined || args[i] === false) { formatedArgs.splice(i, 1, undefined) } else if (args[i] == nsnull) { formatedArgs.splice(i, 1, null) } } return _OC_formatOCToJS(obj.apply(obj, formatedArgs)) } } if (obj instanceof Object) { var ret = {} for (var key in obj) { ret[key] = _formatOCToJS(obj[key]) } return ret } return obj } var _methodFunc = function(instance, clsName, methodName, args, isSuper, isPerformSelector) { var selectorName = methodName if (!isPerformSelector) { methodName = methodName.replace(/__/g, "-") selectorName = methodName.replace(/_/g, ":").replace(/-/g, "_") var marchArr = selectorName.match(/:/g) var numOfArgs = marchArr ? marchArr.length : 0 if (args.length > numOfArgs) { selectorName += ":" } } var ret = instance ? _OC_callI(instance, selectorName, args, isSuper): _OC_callC(clsName, selectorName, args) return _formatOCToJS(ret) } var _customMethods = { __c: function(methodName) { var slf = this if (slf instanceof Boolean) { return function() { return false } } if (slf[methodName]) { return slf[methodName].bind(slf); } if (!slf.__obj && !slf.__clsName) { throw new Error(slf + '.' + methodName + ' is undefined') } if (slf.__isSuper && slf.__clsName) { slf.__clsName = _OC_superClsName(slf.__obj.__realClsName ? slf.__obj.__realClsName: slf.__clsName); } var clsName = slf.__clsName if (clsName && _ocCls[clsName]) { var methodType = slf.__obj ? 'instMethods': 'clsMethods' if (_ocCls[clsName][methodType][methodName]) { slf.__isSuper = 0; return _ocCls[clsName][methodType][methodName].bind(slf) } } return function(){ var args = Array.prototype.slice.call(arguments) return _methodFunc(slf.__obj, slf.__clsName, methodName, args, slf.__isSuper) } }, super: function() { var slf = this if (slf.__obj) { slf.__obj.__realClsName = slf.__realClsName; } return {__obj: slf.__obj, __clsName: slf.__clsName, __isSuper: 1} }, performSelectorInOC: function() { var slf = this var args = Array.prototype.slice.call(arguments) return {__isPerformInOC:1, obj:slf.__obj, clsName:slf.__clsName, sel: args[0], args: args[1], cb: args[2]} }, performSelector: function() { var slf = this var args = Array.prototype.slice.call(arguments) return _methodFunc(slf.__obj, slf.__clsName, args[0], args.splice(1), slf.__isSuper, true) } } for (var method in _customMethods) { if (_customMethods.hasOwnProperty(method)) { Object.defineProperty(Object.prototype, method, {value: _customMethods[method], configurable:false, enumerable: false}) } } var _require = function(clsName) { if (!global[clsName]) { global[clsName] = { __clsName: clsName } } return global[clsName] } global.require = function() { var lastRequire for (var i = 0; i < arguments.length; i ++) { arguments[i].split(',').forEach(function(clsName) { lastRequire = _require(clsName.trim()) }) } return lastRequire } var _formatDefineMethods = function(methods, newMethods, realClsName) { for (var methodName in methods) { if (!(methods[methodName] instanceof Function)) return; (function(){ var originMethod = methods[methodName] newMethods[methodName] = [originMethod.length, function() { try { var args = _formatOCToJS(Array.prototype.slice.call(arguments)) var lastSelf = global.self global.self = args[0] if (global.self) global.self.__realClsName = realClsName args.splice(0,1) var ret = originMethod.apply(originMethod, args) global.self = lastSelf return ret } catch(e) { _OC_catch(e.message, e.stack) } }] })() } } var _wrapLocalMethod = function(methodName, func, realClsName) { return function() { var lastSelf = global.self global.self = this this.__realClsName = realClsName var ret = func.apply(this, arguments) global.self = lastSelf return ret } } var _setupJSMethod = function(className, methods, isInst, realClsName) { for (var name in methods) { var key = isInst ? 'instMethods': 'clsMethods', func = methods[name] _ocCls[className][key][name] = _wrapLocalMethod(name, func, realClsName) } } var _propertiesGetFun = function(name){ return function(){ var slf = this; if (!slf.__ocProps) { var props = _OC_getCustomProps(slf.__obj) if (!props) { props = {} _OC_setCustomProps(slf.__obj, props) } slf.__ocProps = props; } return slf.__ocProps[name]; }; } var _propertiesSetFun = function(name){ return function(jval){ var slf = this; if (!slf.__ocProps) { var props = _OC_getCustomProps(slf.__obj) if (!props) { props = {} _OC_setCustomProps(slf.__obj, props) } slf.__ocProps = props; } slf.__ocProps[name] = jval; }; } global.defineClass = function(declaration, properties, instMethods, clsMethods) { var newInstMethods = {}, newClsMethods = {} if (!(properties instanceof Array)) { clsMethods = instMethods instMethods = properties properties = null } if (properties) { properties.forEach(function(name){ if (!instMethods[name]) { instMethods[name] = _propertiesGetFun(name); } var nameOfSet = "set"+ name.substr(0,1).toUpperCase() + name.substr(1); if (!instMethods[nameOfSet]) { instMethods[nameOfSet] = _propertiesSetFun(name); } }); } var realClsName = declaration.split(':')[0].trim() _formatDefineMethods(instMethods, newInstMethods, realClsName) _formatDefineMethods(clsMethods, newClsMethods, realClsName) var ret = _OC_defineClass(declaration, newInstMethods, newClsMethods) var className = ret['cls'] var superCls = ret['superCls'] _ocCls[className] = { instMethods: {}, clsMethods: {}, } if (superCls.length && _ocCls[superCls]) { for (var funcName in _ocCls[superCls]['instMethods']) { _ocCls[className]['instMethods'][funcName] = _ocCls[superCls]['instMethods'][funcName] } for (var funcName in _ocCls[superCls]['clsMethods']) { _ocCls[className]['clsMethods'][funcName] = _ocCls[superCls]['clsMethods'][funcName] } } _setupJSMethod(className, instMethods, 1, realClsName) _setupJSMethod(className, clsMethods, 0, realClsName) return require(className) } global.defineProtocol = function(declaration, instProtos , clsProtos) { var ret = _OC_defineProtocol(declaration, instProtos,clsProtos); return ret } global.block = function(args, cb) { var that = this var slf = global.self if (args instanceof Function) { cb = args args = '' } var callback = function() { var args = Array.prototype.slice.call(arguments) global.self = slf return cb.apply(that, _formatOCToJS(args)) } var ret = {args: args, cb: callback, argCount: cb.length, __isBlock: 1} if (global.__genBlock) { ret['blockObj'] = global.__genBlock(args, cb) } return ret } if (global.console) { var jsLogger = console.log; global.console.log = function() { global._OC_log.apply(global, arguments); if (jsLogger) { jsLogger.apply(global.console, arguments); } } } else { global.console = { log: global._OC_log } } global.defineJSClass = function(declaration, instMethods, clsMethods) { var o = function() {}, a = declaration.split(':'), clsName = a[0].trim(), superClsName = a[1] ? a[1].trim() : null o.prototype = { init: function() { if (this.super()) this.super().init() return this; }, super: function() { return superClsName ? _jsCls[superClsName].prototype : null } } var cls = { alloc: function() { return new o; } } for (var methodName in instMethods) { o.prototype[methodName] = instMethods[methodName]; } for (var methodName in clsMethods) { cls[methodName] = clsMethods[methodName]; } global[clsName] = cls _jsCls[clsName] = o } global.YES = 1 global.NO = 0 global.nsnull = _OC_null global._formatOCToJS = _formatOCToJS })() ================================================ FILE: JSPatch.podspec ================================================ Pod::Spec.new do |s| s.name = "JSPatch" s.version = "1.1.3" s.summary = "JSPatch bridge Objective-C and JavaScript. You can call any" \ " Objective-C class and method in JavaScript by just" \ " including a small engine." s.description = <<-DESC JSPatch bridges Objective-C and JavaScript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. That makes the APP obtaining the power of script language: add modules or replacing Objective-C codes to fix bugs dynamically. DESC s.homepage = "https://github.com/bang590/JSPatch" s.license = { :type => "MIT", :file => "LICENSE" } s.author = { "bang" => "bang590@gmail.com" } s.social_media_url = "https://twitter.com/bang590" s.ios.deployment_target = '6.0' s.tvos.deployment_target = '9.0' s.osx.deployment_target = '10.9' s.source = { :git => "https://github.com/bang590/JSPatch.git", :tag => s.version } s.frameworks = "Foundation" s.weak_framework = "JavaScriptCore" s.default_subspec = 'Core' s.subspec 'Core' do |ss| ss.ios.source_files = "JSPatch/*.{h,m}" ss.tvos.source_files = "JSPatch/*.{h,m}" ss.osx.source_files = "JSPatch/*.{h,m}" ss.public_header_files = "JSPatch/*.h" ss.resources = "JSPatch/*.js" end s.subspec "Extensions" do |ss| ss.ios.source_files = "Extensions/*" ss.ios.public_header_files = "Extensions/*.h" ss.dependency 'JSPatch/Core' end s.subspec "JPCFunction" do |ss| ss.ios.source_files = "Extensions/JPCFunction/**/*", "Extensions/JPLibffi/**/*.{h,m}" ss.ios.public_header_files = "Extensions/JPCFunction/**/*.h", "Extensions/JPLibffi/**/*.h" ss.vendored_libraries = 'Extensions/JPLibffi/libffi/libffi.a' ss.dependency 'JSPatch/Core' end s.subspec "JPBlock" do |ss| ss.ios.source_files = "Extensions/JPBlock/**/*", "Extensions/JPLibffi/**/*.{h,m}" ss.ios.public_header_files = "Extensions/JPBlock/**/*.h", "Extensions/JPLibffi/**/*.h" ss.vendored_libraries = 'Extensions/JPLibffi/libffi/libffi.a' ss.dependency 'JSPatch/Core' end s.subspec "JPCFunctionBinder" do |ss| ss.ios.source_files = "Extensions/JPCFunctionBinder/**/*" ss.ios.public_header_files = "Extensions/JPCFunctionBinder/**/*.h" ss.dependency 'JSPatch/Core' end s.subspec 'Loader' do |ss| ss.ios.source_files = "Loader/**/*.{h,m,c}" ss.tvos.source_files = "Loader/**/*.{h,m,c}" ss.ios.public_header_files = "Loader/*.h" ss.tvos.public_header_files = "Loader/*.h" ss.dependency 'JSPatch/Core' ss.library = 'z' end end ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 bang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Loader/JPLoader.h ================================================ // // JSPatch.h // JSPatch // // Created by bang on 15/11/14. // Copyright (c) 2015 bang. All rights reserved. // #import const static NSString *rootUrl = @""; static NSString *publicKey = @"-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+1xcYsEE+ab/Ame1/HHAgfBRh\nD67I9mBYCiOJqC3lJX5RKFvtOTcF5Sf5Bz3NL/2QWPLu40+yt4EvjZ3HOUAHrVgo\n2Fjo4vpaRoEaEtaccOziPH/ASScOfL+uppNGOa0glTCZLKVZI3Go8zoutr8VDw2d\nNT7rDM/4TvPjwMYd3QIDAQAB\n-----END PUBLIC KEY-----"; typedef void (^JPUpdateCallback)(NSError *error); typedef enum { JPUpdateErrorUnzipFailed = -1001, JPUpdateErrorVerifyFailed = -1002, } JPUpdateError; @interface JPLoader : NSObject + (BOOL)run; + (void)updateToVersion:(NSInteger)version callback:(JPUpdateCallback)callback; + (void)runTestScriptInBundle; + (void)setLogger:(void(^)(NSString *log))logger; + (NSInteger)currentVersion; @end ================================================ FILE: Loader/JPLoader.m ================================================ // // JSPatch.m // JSPatch // // Created by bang on 15/11/14. // Copyright (c) 2015 bang. All rights reserved. // #import "JPLoader.h" #import "JPEngine.h" #import "ZipArchive.h" #import "RSA.h" #import #define kJSPatchVersion(appVersion) [NSString stringWithFormat:@"JSPatchVersion_%@", appVersion] void (^JPLogger)(NSString *log); #pragma mark - Extension @interface JPLoaderInclude : JPExtension @end @implementation JPLoaderInclude + (void)main:(JSContext *)context { context[@"include"] = ^(NSString *filePath) { if (!filePath.length || [filePath rangeOfString:@".js"].location == NSNotFound) { return; } NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject]; NSString *scriptPath = [libraryDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"JSPatch/%@/%@", appVersion, filePath]]; if ([[NSFileManager defaultManager] fileExistsAtPath:scriptPath]) { [JPEngine startEngine]; [JPEngine evaluateScriptWithPath:scriptPath]; } }; } @end @interface JPLoaderTestInclude : JPExtension @end @implementation JPLoaderTestInclude + (void)main:(JSContext *)context { context[@"include"] = ^(NSString *filePath) { NSArray *component = [filePath componentsSeparatedByString:@"."]; if (component.count > 1) { NSString *testPath = [[NSBundle bundleForClass:[self class]] pathForResource:component[0] ofType:component[1]]; [JPEngine evaluateScriptWithPath:testPath]; } }; } @end #pragma mark - Loader @implementation JPLoader + (BOOL)run { if (JPLogger) JPLogger(@"JSPatch: runScript"); NSString *scriptDirectory = [self fetchScriptDirectory]; NSString *scriptPath = [scriptDirectory stringByAppendingPathComponent:@"main.js"]; if ([[NSFileManager defaultManager] fileExistsAtPath:scriptPath]) { [JPEngine startEngine]; [JPEngine addExtensions:@[@"JPLoaderInclude"]]; [JPEngine evaluateScriptWithPath:scriptPath]; if (JPLogger) JPLogger([NSString stringWithFormat:@"JSPatch: evaluated script %@", scriptPath]); return YES; } else { return NO; } } + (void)updateToVersion:(NSInteger)version callback:(JPUpdateCallback)callback { NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; if (JPLogger) JPLogger([NSString stringWithFormat:@"JSPatch: updateToVersion: %@", @(version)]); // create url request NSString *downloadKey = [NSString stringWithFormat:@"/%@/v%@.zip", appVersion, @(version)]; NSURL *downloadURL = [NSURL URLWithString:[rootUrl stringByAppendingString:downloadKey]]; NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0]; if (JPLogger) JPLogger([NSString stringWithFormat:@"JSPatch: request file %@", downloadURL]); // create task NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (!error) { if (JPLogger) JPLogger([NSString stringWithFormat:@"JSPatch: request file success, data length:%@", @(data.length)]); // script directory NSString *scriptDirectory = [self fetchScriptDirectory]; // temporary files and directories NSString *downloadTmpPath = [NSString stringWithFormat:@"%@patch_%@_%@", NSTemporaryDirectory(), appVersion, @(version)]; NSString *unzipVerifyDirectory = [NSString stringWithFormat:@"%@patch_%@_%@_unzipTest/", NSTemporaryDirectory(), appVersion, @(version)]; NSString *unzipTmpDirectory = [NSString stringWithFormat:@"%@patch_%@_%@_unzip/", NSTemporaryDirectory(), appVersion, @(version)]; // save data [data writeToFile:downloadTmpPath atomically:YES]; // is the processing flow failed BOOL isFailed = NO; // 1. unzip encrypted md5 file and script file NSString *keyFilePath; NSString *scriptZipFilePath; ZipArchive *verifyZipArchive = [[ZipArchive alloc] init]; [verifyZipArchive UnzipOpenFile:downloadTmpPath]; BOOL verifyUnzipSucc = [verifyZipArchive UnzipFileTo:unzipVerifyDirectory overWrite:YES]; if (verifyUnzipSucc) { for (NSString *filePath in verifyZipArchive.unzippedFiles) { NSString *filename = [filePath lastPathComponent]; if ([filename isEqualToString:@"key"]) { // encrypted md5 file keyFilePath = filePath; } else if ([[filename pathExtension] isEqualToString:@"zip"]) { // script file scriptZipFilePath = filePath; } } } else { if (JPLogger) JPLogger(@"JSPatch: fail to unzip file"); isFailed = YES; if (callback) { callback([NSError errorWithDomain:@"org.jspatch" code:JPUpdateErrorUnzipFailed userInfo:nil]); } } // 2. decrypt and verify md5 file if (!isFailed) { NSData *md5Data = [RSA decryptData:[NSData dataWithContentsOfFile:keyFilePath] publicKey:publicKey]; NSString *decryptMD5 = [[NSString alloc] initWithData:md5Data encoding:NSUTF8StringEncoding]; NSString *md5 = [self fileMD5:scriptZipFilePath]; if (![decryptMD5 isEqualToString:md5]) { if (JPLogger) JPLogger([NSString stringWithFormat:@"JSPatch: decompress error, md5 didn't match, decrypt:%@ md5:%@", decryptMD5, md5]); isFailed = YES; if (callback) { callback([NSError errorWithDomain:@"org.jspatch" code:JPUpdateErrorVerifyFailed userInfo:nil]); } } } // 3. unzip script file and save if (!isFailed) { ZipArchive *zipArchive = [[ZipArchive alloc] init]; [zipArchive UnzipOpenFile:scriptZipFilePath]; BOOL unzipSucc = [zipArchive UnzipFileTo:unzipTmpDirectory overWrite:YES]; if (unzipSucc) { for (NSString *filePath in zipArchive.unzippedFiles) { NSString *filename = [filePath lastPathComponent]; if ([[filename pathExtension] isEqualToString:@"js"]) { [[NSFileManager defaultManager] createDirectoryAtPath:scriptDirectory withIntermediateDirectories:YES attributes:nil error:nil]; NSString *newFilePath = [scriptDirectory stringByAppendingPathComponent:filename]; [[NSData dataWithContentsOfFile:filePath] writeToFile:newFilePath atomically:YES]; } } } else { if (JPLogger) JPLogger(@"JSPatch: fail to unzip script file"); isFailed = YES; if (callback) { callback([NSError errorWithDomain:@"org.jspatch" code:JPUpdateErrorUnzipFailed userInfo:nil]); } } } // success if (!isFailed) { if (JPLogger) JPLogger([NSString stringWithFormat:@"JSPatch: updateToVersion: %@ success", @(version)]); [[NSUserDefaults standardUserDefaults] setInteger:version forKey:kJSPatchVersion(appVersion)]; [[NSUserDefaults standardUserDefaults] synchronize]; if (callback) callback(nil); } // clear temporary files [[NSFileManager defaultManager] removeItemAtPath:downloadTmpPath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:unzipVerifyDirectory error:nil]; [[NSFileManager defaultManager] removeItemAtPath:unzipTmpDirectory error:nil]; } else { if (JPLogger) JPLogger([NSString stringWithFormat:@"JSPatch: request error %@", error]); if (callback) callback(error); } }]; [task resume]; } + (void)runTestScriptInBundle { [JPEngine startEngine]; [JPEngine addExtensions:@[@"JPLoaderTestInclude"]]; NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"main" ofType:@"js"]; NSAssert(path, @"can't find main.js"); NSString *script = [[NSString alloc] initWithData:[[NSFileManager defaultManager] contentsAtPath:path] encoding:NSUTF8StringEncoding]; [JPEngine evaluateScript:script]; } + (void)setLogger:(void (^)(NSString *))logger { JPLogger = [logger copy]; } + (NSInteger)currentVersion { NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; return [[NSUserDefaults standardUserDefaults] integerForKey:kJSPatchVersion(appVersion)]; } + (NSString *)fetchScriptDirectory { NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject]; NSString *scriptDirectory = [libraryDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"JSPatch/%@/", appVersion]]; return scriptDirectory; } #pragma mark utils + (NSString *)fileMD5:(NSString *)filePath { NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:filePath]; if(!handle) { return nil; } CC_MD5_CTX md5; CC_MD5_Init(&md5); BOOL done = NO; while (!done) { NSData *fileData = [handle readDataOfLength:256]; CC_MD5_Update(&md5, [fileData bytes], (CC_LONG)[fileData length]); if([fileData length] == 0) done = YES; } unsigned char digest[CC_MD5_DIGEST_LENGTH]; CC_MD5_Final(digest, &md5); NSString *result = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]]; return result; } @end ================================================ FILE: Loader/libs/RSA.h ================================================ /* @author: ideawu @link: https://github.com/ideawu/Objective-C-RSA */ #import @interface RSA : NSObject // return base64 encoded string + (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey; // return raw data + (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey; // decrypt base64 encoded string, convert result to string(not base64 encoded) + (NSString *)decryptString:(NSString *)str publicKey:(NSString *)pubKey; + (NSData *)decryptData:(NSData *)data publicKey:(NSString *)pubKey; @end ================================================ FILE: Loader/libs/RSA.m ================================================ /* @author: ideawu @link: https://github.com/ideawu/Objective-C-RSA */ #import "RSA.h" #import @implementation RSA static NSString *base64_encode_data(NSData *data){ data = [data base64EncodedDataWithOptions:0]; NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return ret; } static NSData *base64_decode(NSString *str){ NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters]; return data; } + (NSData *)stripPublicKeyHeader:(NSData *)d_key{ // Skip ASN.1 public key header if (d_key == nil) return(nil); unsigned long len = [d_key length]; if (!len) return(nil); unsigned char *c_key = (unsigned char *)[d_key bytes]; unsigned int idx = 0; if (c_key[idx++] != 0x30) return(nil); if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; else idx++; // PKCS #1 rsaEncryption szOID_RSA_RSA static unsigned char seqiod[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00 }; if (memcmp(&c_key[idx], seqiod, 15)) return(nil); idx += 15; if (c_key[idx++] != 0x03) return(nil); if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; else idx++; if (c_key[idx++] != '\0') return(nil); // Now make a new NSData from this buffer return([NSData dataWithBytes:&c_key[idx] length:len - idx]); } + (SecKeyRef)addPublicKey:(NSString *)key{ NSRange spos = [key rangeOfString:@"-----BEGIN PUBLIC KEY-----"]; NSRange epos = [key rangeOfString:@"-----END PUBLIC KEY-----"]; if(spos.location != NSNotFound && epos.location != NSNotFound){ NSUInteger s = spos.location + spos.length; NSUInteger e = epos.location; NSRange range = NSMakeRange(s, e-s); key = [key substringWithRange:range]; } key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""]; key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""]; key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""]; key = [key stringByReplacingOccurrencesOfString:@" " withString:@""]; // This will be base64 encoded, decode it. NSData *data = base64_decode(key); data = [RSA stripPublicKeyHeader:data]; if(!data){ return nil; } NSString *tag = @"what_the_fuck_is_this"; NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; // Delete any old lingering key with the same tag NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init]; [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass]; [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag]; SecItemDelete((__bridge CFDictionaryRef)publicKey); // Add persistent version of the key to system keychain [publicKey setObject:data forKey:(__bridge id)kSecValueData]; [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id) kSecAttrKeyClass]; [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) kSecReturnPersistentRef]; CFTypeRef persistKey = nil; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey); if (persistKey != nil){ CFRelease(persistKey); } if ((status != noErr) && (status != errSecDuplicateItem)) { return nil; } [publicKey removeObjectForKey:(__bridge id)kSecValueData]; [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef]; [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef]; [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; // Now fetch the SecKeyRef version of the key SecKeyRef keyRef = nil; status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef); if(status != noErr){ return nil; } return keyRef; } + (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey{ NSData *data = [RSA encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey]; NSString *ret = base64_encode_data(data); return ret; } + (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{ if(!data || !pubKey){ return nil; } SecKeyRef keyRef = [RSA addPublicKey:pubKey]; if(!keyRef){ return nil; } const uint8_t *srcbuf = (const uint8_t *)[data bytes]; size_t srclen = (size_t)data.length; size_t outlen = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); if(srclen > outlen - 11){ CFRelease(keyRef); return nil; } void *outbuf = malloc(outlen); OSStatus status = noErr; status = SecKeyEncrypt(keyRef, kSecPaddingPKCS1, srcbuf, srclen, outbuf, &outlen ); NSData *ret = nil; if (status != 0) { //NSLog(@"SecKeyEncrypt fail. Error Code: %ld", status); }else{ ret = [NSData dataWithBytes:outbuf length:outlen]; } free(outbuf); CFRelease(keyRef); return ret; } + (NSString *)decryptString:(NSString *)str publicKey:(NSString *)pubKey{ NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters]; data = [RSA decryptData:data publicKey:pubKey]; NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return ret; } + (NSData *)decryptData:(NSData *)data publicKey:(NSString *)pubKey{ if(!data || !pubKey){ return nil; } SecKeyRef keyRef = [RSA addPublicKey:pubKey]; if(!keyRef){ return nil; } const uint8_t *srcbuf = (const uint8_t *)[data bytes]; size_t srclen = (size_t)data.length; size_t outlen = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); // if(srclen != outlen){ // //TODO currently we are able to decrypt only one block! // CFRelease(keyRef); // return nil; // } UInt8 *outbuf = malloc(outlen); //use kSecPaddingNone in decryption mode OSStatus status = noErr; status = SecKeyDecrypt(keyRef, kSecPaddingNone, srcbuf, srclen, outbuf, &outlen ); NSData *result = nil; if (status != 0) { //NSLog(@"SecKeyEncrypt fail. Error Code: %ld", status); }else{ //the actual decrypted data is in the middle, locate it! int idxFirstZero = -1; int idxNextZero = (int)outlen; for ( int i = 0; i < outlen; i++ ) { if ( outbuf[i] == 0 ) { if ( idxFirstZero < 0 ) { idxFirstZero = i; } else { idxNextZero = i; break; } } } result = [NSData dataWithBytes:&outbuf[idxFirstZero+1] length:idxNextZero-idxFirstZero-1]; } free(outbuf); CFRelease(keyRef); return result; } @end ================================================ FILE: Loader/libs/ZipArchive.h ================================================ /** // @header ZipArchive.h // // An objective C wrapper for minizip and libz for creating and exanding ZIP files. // // @author Created by aish on 08-9-11. // acsolu@gmail.com // @copyright Copyright 2008 Inc. All rights reserved. // */ #import /** a block that is called from UnzipFileTo:overwrite:withProgressBlock: where the percentage of files processed (as an integer from 0 to 100), the number of files processed so far and the total number of files in the archive is called after each file is processed. */ typedef void(^ZipArchiveProgressUpdateBlock)(int percentage, int filesProcessed, unsigned long numFiles); /** @protocol @discussion methods for a delegate to receive error notifications and control overwriting of files */ @protocol ZipArchiveDelegate @optional /** @brief Delegate method to be notified of errors ZipArchive calls this selector on the delegate when errors are encountered. @param msg a string describing the error. @result void */ -(void) ErrorMessage:(NSString*) msg; /** @brief Delegate method to determine if a file should be replaced When an zip file is being expanded and a file is about to be replaced, this selector is called on the delegate to notify that file is about to be replaced. The delegate method should return YES to overwrite the file, or NO to skip it. @param file - path to the file to be overwritten. @result a BOOL - YES to replace, NO to skip */ -(BOOL) OverWriteOperation:(NSString*) file; @end /** @class @brief An object that can create zip files and expand existing ones. This class provides methods to create a zip file (optionally with a password) and add files to that zip archive. It also provides methods to expand an existing archive file (optionally with a password), and extract the files. */ @interface ZipArchive : NSObject { @private void* _zipFile; void* _unzFile; unsigned long _numFiles; NSString* _password; __weak id _delegate; ZipArchiveProgressUpdateBlock _progressBlock; NSArray* _unzippedFiles; NSFileManager* _fileManager; NSStringEncoding _stringEncoding; } /** a delegate object conforming to ZipArchiveDelegate protocol */ @property (nonatomic, weak) id delegate; @property (nonatomic, readonly) unsigned long numFiles; @property (nonatomic, copy) ZipArchiveProgressUpdateBlock progressBlock; /** @brief String encoding to be used when interpreting file names in the zip file. */ @property (nonatomic, assign) NSStringEncoding stringEncoding; /** an array of files that were successfully expanded. Available after calling UnzipFileTo:overWrite: */ @property (nonatomic, readonly,strong) NSArray *unzippedFiles; -(id) initWithFileManager:(NSFileManager*) fileManager; -(BOOL) CreateZipFile2:(NSString*) zipFile; -(BOOL) CreateZipFile2:(NSString*) zipFile Password:(NSString*) password; -(BOOL) addFileToZip:(NSString*) file newname:(NSString*) newname; -(BOOL) CloseZipFile2; -(BOOL) UnzipOpenFile:(NSString*) zipFile; -(BOOL) UnzipOpenFile:(NSString*) zipFile Password:(NSString*) password; -(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite; -(BOOL) UnzipCloseFile; -(NSArray*) getZipFileContents; // list the contents of the zip archive. must be called after UnzipOpenFile @end ================================================ FILE: Loader/libs/ZipArchive.m ================================================ /** // ZipArchive.m // // // Created by aish on 08-9-11. // acsolu@gmail.com // Copyright 2008 Inc. All rights reserved. // */ #import "ZipArchive.h" #import "zlib.h" #import "zconf.h" #include "zip.h" #include "unzip.h" @interface NSFileManager(ZipArchive) - (NSDictionary *)_attributesOfItemAtPath:(NSString *)path followingSymLinks:(BOOL)followingSymLinks error:(NSError **)error; @end @interface ZipArchive () -(void) OutputErrorMessage:(NSString*) msg; -(BOOL) OverWrite:(NSString*) file; -(NSDate*) Date1980; @property (nonatomic,copy) NSString* password; @end @implementation ZipArchive @synthesize delegate = _delegate; @synthesize numFiles = _numFiles; @synthesize password = _password; @synthesize unzippedFiles = _unzippedFiles; @synthesize progressBlock = _progressBlock; @synthesize stringEncoding = _stringEncoding; -(id) init { return [self initWithFileManager:[NSFileManager defaultManager]]; } -(id) initWithFileManager:(NSFileManager*) fileManager { if( self=[super init] ) { _zipFile = NULL; _fileManager = fileManager; self.stringEncoding = NSUTF8StringEncoding; } return self; } -(void) dealloc { // close any open file operations [self CloseZipFile2]; [self UnzipCloseFile]; // release retained/copied properties. } /** * Create a new zip file at the specified path, ready for new files to be added. * * @param zipFile the path of the zip file to create * @returns BOOL YES on success */ -(BOOL) CreateZipFile2:(NSString*) zipFile { _zipFile = zipOpen( (const char*)[zipFile UTF8String], 0 ); if( !_zipFile ) return NO; return YES; } /** * Create a new zip file at the specified path, ready for new files to be added. * * @param zipFile the path of the zip file to create * @param password a password used to encrypt the zip file * @returns BOOL YES on success */ -(BOOL) CreateZipFile2:(NSString*) zipFile Password:(NSString*) password { self.password = password; return [self CreateZipFile2:zipFile]; } /** * add an existing file on disk to the zip archive, compressing it. * * @param file the path to the file to compress * @param newname the name of the file in the zip archive, ie: path relative to the zip archive root. * @returns BOOL YES on success */ -(BOOL) addFileToZip:(NSString*) file newname:(NSString*) newname; { if( !_zipFile ) return NO; // tm_zip filetime; zip_fileinfo zipInfo = {{0}}; NSDate* fileDate = nil; NSError* error = nil; NSDictionary* attr = [_fileManager _attributesOfItemAtPath:file followingSymLinks:YES error:&error]; if( attr ) fileDate = (NSDate*)[attr objectForKey:NSFileModificationDate]; if( fileDate == nil ) fileDate = [NSDate date]; NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; NSDateComponents* components = [gregorianCalendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:fileDate]; zipInfo.tmz_date.tm_sec = (uInt)components.second; zipInfo.tmz_date.tm_min = (uInt)components.minute; zipInfo.tmz_date.tm_hour = (uInt)components.hour; zipInfo.tmz_date.tm_mday = (uInt)components.day; zipInfo.tmz_date.tm_mon = (uInt)components.month; zipInfo.tmz_date.tm_year = (uInt)components.year; int ret ; NSData* data = nil; if( [_password length] == 0 ) { ret = zipOpenNewFileInZip( _zipFile, (const char*) [newname cStringUsingEncoding:self.stringEncoding], &zipInfo, NULL,0, NULL,0, NULL,//comment Z_DEFLATED, Z_DEFAULT_COMPRESSION ); } else { data = [ NSData dataWithContentsOfFile:file]; uLong crcValue = crc32( 0L,NULL, 0L ); crcValue = crc32( crcValue, (const Bytef*)[data bytes], (unsigned int)[data length] ); ret = zipOpenNewFileInZip3( _zipFile, (const char*) [newname cStringUsingEncoding:self.stringEncoding], &zipInfo, NULL,0, NULL,0, NULL,//comment Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, 15, 8, Z_DEFAULT_STRATEGY, [_password cStringUsingEncoding:NSASCIIStringEncoding], crcValue ); } if( ret!=Z_OK ) { return NO; } if( data==nil ) { data = [ NSData dataWithContentsOfFile:file]; } unsigned int dataLen = (unsigned int)[data length]; ret = zipWriteInFileInZip( _zipFile, (const void*)[data bytes], dataLen); if( ret!=Z_OK ) { return NO; } ret = zipCloseFileInZip( _zipFile ); if( ret!=Z_OK ) return NO; return YES; } /** * Close a zip file after creating and added files to it. * * @returns BOOL YES on success */ -(BOOL) CloseZipFile2 { self.password = nil; if( _zipFile==NULL ) return NO; BOOL ret = zipClose( _zipFile,NULL )==Z_OK?YES:NO; _zipFile = NULL; return ret; } /** * open an existing zip file ready for expanding. * * @param zipFile the path to a zip file to be opened. * @returns BOOL YES on success */ -(BOOL) UnzipOpenFile:(NSString*) zipFile { // create an array to receive the list of unzipped files. _unzippedFiles = [[NSMutableArray alloc] initWithCapacity:1]; _unzFile = unzOpen( (const char*)[zipFile UTF8String] ); if( _unzFile ) { unz_global_info globalInfo = {0}; if( unzGetGlobalInfo(_unzFile, &globalInfo )==UNZ_OK ) { _numFiles = globalInfo.number_entry; NSLog(@"%lu entries in the zip file", globalInfo.number_entry); } } return _unzFile!=NULL; } /** * open an existing zip file with a password ready for expanding. * * @param zipFile the path to a zip file to be opened. * @param password the password to use decrpyting the file. * @returns BOOL YES on success */ -(BOOL) UnzipOpenFile:(NSString*) zipFile Password:(NSString*) password { self.password = password; return [self UnzipOpenFile:zipFile]; } /** * Expand all files in the zip archive into the specified directory. * * If a delegate has been set and responds to OverWriteOperation: it can * return YES to overwrite a file, or NO to skip that file. * * On completion, the property `unzippedFiles` will be an array populated * with the full paths of each file that was successfully expanded. * * @param path the directory where expanded files will be created * @param overwrite should existing files be overwritten * @returns BOOL YES on success */ -(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite { BOOL success = YES; int index = 0; int progress = -1; int ret = unzGoToFirstFile( _unzFile ); unsigned char buffer[4096] = {0}; if( ret!=UNZ_OK ) { [self OutputErrorMessage:@"Failed"]; } const char* password = [_password cStringUsingEncoding:NSASCIIStringEncoding]; do{ @autoreleasepool { if( [_password length]==0 ) ret = unzOpenCurrentFile( _unzFile ); else ret = unzOpenCurrentFilePassword( _unzFile, password ); if( ret!=UNZ_OK ) { [self OutputErrorMessage:@"Error occurs"]; success = NO; break; } // reading data and write to file int read ; unz_file_info fileInfo ={0}; ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0); if( ret!=UNZ_OK ) { [self OutputErrorMessage:@"Error occurs while getting file info"]; success = NO; unzCloseCurrentFile( _unzFile ); break; } char* filename = (char*) malloc( fileInfo.size_filename +1 ); unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0); filename[fileInfo.size_filename] = '\0'; // check if it contains directory NSString * strPath = [NSString stringWithCString:filename encoding:self.stringEncoding]; BOOL isDirectory = NO; if( filename[fileInfo.size_filename-1]=='/' || filename[fileInfo.size_filename-1]=='\\') isDirectory = YES; free( filename ); if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound ) {// contains a path strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; } NSString* fullPath = [path stringByAppendingPathComponent:strPath]; if( isDirectory ) [_fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil]; else [_fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil]; FILE* fp = NULL; do { read = unzReadCurrentFile(_unzFile, buffer, 4096); if (read >= 0) { if (fp == NULL) { if( [_fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite ) { if( ![self OverWrite:fullPath] ) { // don't process any more of the file, but continue break; } } if (!isDirectory) { fp = fopen( (const char*)[fullPath UTF8String], "wb"); if (fp == NULL) { [self OutputErrorMessage:@"Failed to open output file for writing"]; break; } } } fwrite(buffer, read, 1, fp ); } else // if (read < 0) { ret = read; // result will be an error code success = NO; [self OutputErrorMessage:@"Failed to read zip file"]; } } while (read > 0); if (fp) { fclose( fp ); // add the full path of this file to the output array [(NSMutableArray*)_unzippedFiles addObject:fullPath]; // set the orignal datetime property if( fileInfo.tmu_date.tm_year!=0 ) { NSDateComponents* components = [[NSDateComponents alloc] init]; components.second = fileInfo.tmu_date.tm_sec; components.minute = fileInfo.tmu_date.tm_min; components.hour = fileInfo.tmu_date.tm_hour; components.day = fileInfo.tmu_date.tm_mday; components.month = fileInfo.tmu_date.tm_mon; components.year = fileInfo.tmu_date.tm_year; NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; NSDate* orgDate = [gregorianCalendar dateFromComponents:components]; NSDictionary* attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; //[_fileManager fileAttributesAtPath:fullPath traverseLink:YES]; if( attr ) { // [attr setValue:orgDate forKey:NSFileCreationDate]; if( ![_fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] ) { // cann't set attributes NSLog(@"Failed to set attributes"); } } orgDate = nil; } } if (ret == UNZ_OK) { ret = unzCloseCurrentFile( _unzFile ); if (ret != UNZ_OK) { [self OutputErrorMessage:@"file was unzipped but failed crc check"]; success = NO; } } if (ret == UNZ_OK) { ret = unzGoToNextFile( _unzFile ); } if (_progressBlock && _numFiles) { index++; int p = index*100/_numFiles; progress = p; _progressBlock(progress, index, _numFiles); } } } while (ret==UNZ_OK && ret!=UNZ_END_OF_LIST_OF_FILE); return success; } /** * Close the zip file. * * @returns BOOL YES on success */ -(BOOL) UnzipCloseFile { self.password = nil; if( _unzFile ) { int err = unzClose( _unzFile ); _unzFile = nil; return err ==UNZ_OK; } return YES; } /** * Return a list of filenames that are in the zip archive. * No path information is available as this can be called before the zip is expanded. * * @returns NSArray list of filenames in the zip archive. */ -(NSArray*) getZipFileContents // list the contents of the zip archive. must be called after UnzipOpenFile { int ret = unzGoToFirstFile( _unzFile ); NSMutableArray * allFilenames = [NSMutableArray arrayWithCapacity:40]; if( ret!=UNZ_OK ) { [self OutputErrorMessage:@"Failed"]; } const char* password = [_password cStringUsingEncoding:NSASCIIStringEncoding]; do{ if( [_password length]==0 ) ret = unzOpenCurrentFile( _unzFile ); else ret = unzOpenCurrentFilePassword( _unzFile, password ); if( ret!=UNZ_OK ) { [self OutputErrorMessage:@"Error occured"]; break; } // reading data and write to file unz_file_info fileInfo ={0}; ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0); if( ret!=UNZ_OK ) { [self OutputErrorMessage:@"Error occurs while getting file info"]; unzCloseCurrentFile( _unzFile ); break; } char* filename = (char*) malloc( fileInfo.size_filename +1 ); unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0); filename[fileInfo.size_filename] = '\0'; // check if it contains directory NSString * strPath = [NSString stringWithCString:filename encoding:NSASCIIStringEncoding]; free( filename ); if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound ) {// contains a path strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; } // Copy name to array [allFilenames addObject:strPath]; unzCloseCurrentFile( _unzFile ); ret = unzGoToNextFile( _unzFile ); } while( ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE ); // return an immutable array. return [NSArray arrayWithArray:allFilenames]; } #pragma mark wrapper for delegate /** * send the ErrorMessage: to the delegate if it responds to it. */ -(void) OutputErrorMessage:(NSString*) msg { if( _delegate && [_delegate respondsToSelector:@selector(ErrorMessage:)] ) [_delegate ErrorMessage:msg]; } /** * send the OverWriteOperation: selector to the delegate if it responds to it, * returning the result, or YES by default. */ -(BOOL) OverWrite:(NSString*) file { if( _delegate && [_delegate respondsToSelector:@selector(OverWriteOperation:)] ) return [_delegate OverWriteOperation:file]; return YES; } #pragma mark get NSDate object for 1980-01-01 -(NSDate*) Date1980 { NSDateComponents *comps = [[NSDateComponents alloc] init]; [comps setDay:1]; [comps setMonth:1]; [comps setYear:1980]; NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; NSDate *date = [gregorian dateFromComponents:comps]; return date; } @end @implementation NSFileManager(ZipArchive) - (NSDictionary *)_attributesOfItemAtPath:(NSString *)path followingSymLinks:(BOOL)followingSymLinks error:(NSError **)error { // call file manager default action, which is to not follow symlinks NSDictionary* results = [self attributesOfItemAtPath:path error:error]; if (followingSymLinks && results && (error ? *error == nil : YES)) { if ([[results fileType] isEqualToString:NSFileTypeSymbolicLink]) { // follow the symlink NSString* realPath = [self destinationOfSymbolicLinkAtPath:path error:error]; if (realPath && (error ? *error == nil : YES)) { return [self _attributesOfItemAtPath:realPath followingSymLinks:followingSymLinks error:error]; } else { // failure to resolve symlink should be an error returning nil and error will already be set. return nil; } } } return results; } @end ================================================ FILE: Loader/libs/minizip/crypt.h ================================================ /* crypt.h -- base code for crypt/uncrypt ZIPfile Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This code is a modified version of crypting code in Infozip distribution The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). If you don't need crypting in your application, just define symbols NOCRYPT and NOUNCRYPT. This code support the "Traditional PKWARE Encryption". The new AES encryption added on Zip format by Winzip (see the page http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong Encryption is not supported. */ #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } /*********************************************************************** * Update the encryption keys with the next byte of plain text */ static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; { register int keyshift = (int)((*(pkeys+1)) >> 24); (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); } return c; } /*********************************************************************** * Initialize the encryption keys and the random header according to * the given password. */ static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; while (*passwd != '\0') { update_keys(pkeys,pcrc_32_tab,(int)*passwd); passwd++; } } #define zdecode(pkeys,pcrc_32_tab,c) \ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif static int crypthead(const char* passwd, /* password string */ unsigned char* buf, /* where to write header */ int bufSize, unsigned long* pkeys, const unsigned long* pcrc_32_tab, unsigned long crcForCrypting) { int n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN-2]; /* random header */ static unsigned calls = 0; /* ensure different random header each time */ if (bufSize> 7) & 0xff; header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); } /* Encrypt random header (last two bytes is high word of crc) */ init_keys(passwd, pkeys, pcrc_32_tab); for (n = 0; n < RAND_HEAD_LEN-2; n++) { buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); } buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); return n; } #endif ================================================ FILE: Loader/libs/minizip/ioapi.c ================================================ /* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt */ #if (defined(_WIN32)) #define _CRT_SECURE_NO_WARNINGS #endif #include "ioapi.h" voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) { if (pfilefunc->zfile_func64.zopen64_file != NULL) return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); else { return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); } } long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); else { uLong offsetTruncated = (uLong)offset; if (offsetTruncated != offset) return -1; else return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); } } ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); else { uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); if ((tell_uLong) == ((uLong)-1)) return (ZPOS64_T)-1; else return tell_uLong; } } void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) { p_filefunc64_32->zfile_func64.zopen64_file = NULL; p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; p_filefunc64_32->zfile_func64.ztell64_file = NULL; p_filefunc64_32->zfile_func64.zseek64_file = NULL; p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; } static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = fopen(filename, mode_fopen); return file; } static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = fopen((const char*)filename, mode_fopen); return file; } static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) { uLong ret; ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); return ret; } static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) { uLong ret; ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); return ret; } static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) { long ret; ret = ftell((FILE *)stream); return ret; } static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) { ZPOS64_T ret; ret = ftello((FILE *)stream); return ret; } static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) { int fseek_origin=0; long ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; if (fseek((FILE *)stream, offset, fseek_origin) != 0) ret = -1; return ret; } static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) { int fseek_origin=0; long ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; if(fseeko((FILE *)stream, offset, fseek_origin) != 0) ret = -1; return ret; } static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) { int ret; ret = fclose((FILE *)stream); return ret; } static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) { int ret; ret = ferror((FILE *)stream); return ret; } void fill_fopen_filefunc (pzlib_filefunc_def) zlib_filefunc_def* pzlib_filefunc_def; { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell_file = ftell_file_func; pzlib_filefunc_def->zseek_file = fseek_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = fopen64_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell64_file = ftell64_file_func; pzlib_filefunc_def->zseek64_file = fseek64_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } ================================================ FILE: Loader/libs/minizip/ioapi.h ================================================ /* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt Changes Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. More if/def section may be needed to support other platforms Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. (but you should use iowin32.c for windows instead) */ #ifndef _ZLIBIOAPI64_H #define _ZLIBIOAPI64_H #if (!defined(_WIN32)) && (!defined(WIN32)) // Linux needs this to support file operation on files larger then 4+GB // But might need better if/def to select just the platforms that needs them. #ifndef __USE_FILE_OFFSET64 #define __USE_FILE_OFFSET64 #endif #ifndef __USE_LARGEFILE64 #define __USE_LARGEFILE64 #endif #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif #include #include #include "zlib.h" #if defined(USE_FILE32API) #define fopen64 fopen #define ftello64 ftell #define fseeko64 fseek #else #ifdef _MSC_VER #define fopen64 fopen #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) #define ftello64 _ftelli64 #define fseeko64 _fseeki64 #else // old MSC #define ftello64 ftell #define fseeko64 fseek #endif #endif #endif /* #ifndef ZPOS64_T #ifdef _WIN32 #define ZPOS64_T fpos_t #else #include #define ZPOS64_T uint64_t #endif #endif */ #ifdef HAVE_MINIZIP64_CONF_H #include "mz64conf.h" #endif /* a type choosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else #ifdef HAS_STDINT_H #include "stdint.h" typedef uint64_t ZPOS64_T; #else #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ZPOS64_T; #else typedef unsigned long long int ZPOS64_T; #endif #endif #endif #ifdef __cplusplus extern "C" { #endif #define ZLIB_FILEFUNC_SEEK_CUR (1) #define ZLIB_FILEFUNC_SEEK_END (2) #define ZLIB_FILEFUNC_SEEK_SET (0) #define ZLIB_FILEFUNC_MODE_READ (1) #define ZLIB_FILEFUNC_MODE_WRITE (2) #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) #define ZLIB_FILEFUNC_MODE_EXISTING (4) #define ZLIB_FILEFUNC_MODE_CREATE (8) #ifndef ZCALLBACK #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) #define ZCALLBACK CALLBACK #else #define ZCALLBACK #endif #endif typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); /* here is the "old" 32 bits structure structure */ typedef struct zlib_filefunc_def_s { open_file_func zopen_file; read_file_func zread_file; write_file_func zwrite_file; tell_file_func ztell_file; seek_file_func zseek_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc_def; typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); typedef struct zlib_filefunc64_def_s { open64_file_func zopen64_file; read_file_func zread_file; write_file_func zwrite_file; tell64_file_func ztell64_file; seek64_file_func zseek64_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc64_def; void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); /* now internal definition, only for zip.c and unzip.h */ typedef struct zlib_filefunc64_32_def_s { zlib_filefunc64_def zfile_func64; open_file_func zopen32_file; tell_file_func ztell32_file; seek_file_func zseek32_file; } zlib_filefunc64_32_def; #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) //#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) //#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) #ifdef __cplusplus } #endif #endif ================================================ FILE: Loader/libs/minizip/mztools.c ================================================ /* Additional tools for Minizip Code: Xavier Roche '2004 License: Same as ZLIB (www.gzip.org) */ /* Code */ #include #include #include #include "zlib.h" #include "unzip.h" #define READ_8(adr) ((unsigned char)*(adr)) #define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) #define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) #define WRITE_8(buff, n) do { \ *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ } while(0) #define WRITE_16(buff, n) do { \ WRITE_8((unsigned char*)(buff), n); \ WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ } while(0) #define WRITE_32(buff, n) do { \ WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ } while(0) extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) const char* file; const char* fileOut; const char* fileOutTmp; uLong* nRecovered; uLong* bytesRecovered; { int err = Z_OK; FILE* fpZip = fopen(file, "rb"); FILE* fpOut = fopen(fileOut, "wb"); FILE* fpOutCD = fopen(fileOutTmp, "wb"); if (fpZip != NULL && fpOut != NULL) { int entries = 0; uLong totalBytes = 0; char header[30]; char filename[256]; char extra[1024]; int offset = 0; int offsetCD = 0; while ( fread(header, 1, 30, fpZip) == 30 ) { int currentOffset = offset; /* File entry */ if (READ_32(header) == 0x04034b50) { unsigned int version = READ_16(header + 4); unsigned int gpflag = READ_16(header + 6); unsigned int method = READ_16(header + 8); unsigned int filetime = READ_16(header + 10); unsigned int filedate = READ_16(header + 12); unsigned int crc = READ_32(header + 14); /* crc */ unsigned int cpsize = READ_32(header + 18); /* compressed size */ unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ unsigned int fnsize = READ_16(header + 26); /* file name length */ unsigned int extsize = READ_16(header + 28); /* extra field length */ filename[0] = extra[0] = '\0'; /* Header */ if (fwrite(header, 1, 30, fpOut) == 30) { offset += 30; } else { err = Z_ERRNO; break; } /* Filename */ if (fnsize > 0) { if (fread(filename, 1, fnsize, fpZip) == fnsize) { if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { offset += fnsize; } else { err = Z_ERRNO; break; } } else { err = Z_ERRNO; break; } } else { err = Z_STREAM_ERROR; break; } /* Extra field */ if (extsize > 0) { if (fread(extra, 1, extsize, fpZip) == extsize) { if (fwrite(extra, 1, extsize, fpOut) == extsize) { offset += extsize; } else { err = Z_ERRNO; break; } } else { err = Z_ERRNO; break; } } /* Data */ { int dataSize = cpsize; if (dataSize == 0) { dataSize = uncpsize; } if (dataSize > 0) { char* data = malloc(dataSize); if (data != NULL) { if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { offset += dataSize; totalBytes += dataSize; } else { err = Z_ERRNO; } } else { err = Z_ERRNO; } free(data); if (err != Z_OK) { break; } } else { err = Z_MEM_ERROR; break; } } } /* Central directory entry */ { char header[46]; char* comment = ""; int comsize = (int) strlen(comment); WRITE_32(header, 0x02014b50); WRITE_16(header + 4, version); WRITE_16(header + 6, version); WRITE_16(header + 8, gpflag); WRITE_16(header + 10, method); WRITE_16(header + 12, filetime); WRITE_16(header + 14, filedate); WRITE_32(header + 16, crc); WRITE_32(header + 20, cpsize); WRITE_32(header + 24, uncpsize); WRITE_16(header + 28, fnsize); WRITE_16(header + 30, extsize); WRITE_16(header + 32, comsize); WRITE_16(header + 34, 0); /* disk # */ WRITE_16(header + 36, 0); /* int attrb */ WRITE_32(header + 38, 0); /* ext attrb */ WRITE_32(header + 42, currentOffset); /* Header */ if (fwrite(header, 1, 46, fpOutCD) == 46) { offsetCD += 46; /* Filename */ if (fnsize > 0) { if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { offsetCD += fnsize; } else { err = Z_ERRNO; break; } } else { err = Z_STREAM_ERROR; break; } /* Extra field */ if (extsize > 0) { if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { offsetCD += extsize; } else { err = Z_ERRNO; break; } } /* Comment field */ if (comsize > 0) { if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { offsetCD += comsize; } else { err = Z_ERRNO; break; } } } else { err = Z_ERRNO; break; } } /* Success */ entries++; } else { break; } } /* Final central directory */ { int entriesZip = entries; char header[22]; char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; int comsize = (int) strlen(comment); if (entriesZip > 0xffff) { entriesZip = 0xffff; } WRITE_32(header, 0x06054b50); WRITE_16(header + 4, 0); /* disk # */ WRITE_16(header + 6, 0); /* disk # */ WRITE_16(header + 8, entriesZip); /* hack */ WRITE_16(header + 10, entriesZip); /* hack */ WRITE_32(header + 12, offsetCD); /* size of CD */ WRITE_32(header + 16, offset); /* offset to CD */ WRITE_16(header + 20, comsize); /* comment */ /* Header */ if (fwrite(header, 1, 22, fpOutCD) == 22) { /* Comment field */ if (comsize > 0) { if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { err = Z_ERRNO; } } } else { err = Z_ERRNO; } } /* Final merge (file + central directory) */ fclose(fpOutCD); if (err == Z_OK) { fpOutCD = fopen(fileOutTmp, "rb"); if (fpOutCD != NULL) { int nRead; char buffer[8192]; while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { err = Z_ERRNO; break; } } fclose(fpOutCD); } } /* Close */ fclose(fpZip); fclose(fpOut); /* Wipe temporary file */ (void)remove(fileOutTmp); /* Number of recovered entries */ if (err == Z_OK) { if (nRecovered != NULL) { *nRecovered = entries; } if (bytesRecovered != NULL) { *bytesRecovered = totalBytes; } } } else { err = Z_STREAM_ERROR; } return err; } ================================================ FILE: Loader/libs/minizip/mztools.h ================================================ /* Additional tools for Minizip Code: Xavier Roche '2004 License: Same as ZLIB (www.gzip.org) */ #ifndef _zip_tools_H #define _zip_tools_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #include "unzip.h" /* Repair a ZIP file (missing central directory) file: file to recover fileOut: output file after recovery fileOutTmp: temporary file name used for recovery */ extern int ZEXPORT unzRepair(const char* file, const char* fileOut, const char* fileOutTmp, uLong* nRecovered, uLong* bytesRecovered); #endif ================================================ FILE: Loader/libs/minizip/unzip.c ================================================ /* unzip.c -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt ------------------------------------------------------------------------------------ Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of compatibility with older software. The following is from the original crypt.c. Code woven in by Terry Thorsen 1/2003. Copyright (c) 1990-2000 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2000-Apr-09 or later (the contents of which are also included in zip.h) for terms of use. If, for some reason, all these files are missing, the Info-ZIP license also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). ------------------------------------------------------------------------------------ Changes in unzip.c 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* 2007-2008 - Even Rouault - Remove old C style function prototypes 2007-2008 - Even Rouault - Add unzip support for ZIP64 Copyright (C) 2007-2008 Even Rouault Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G should only read the compressed/uncompressed size from the Zip64 format if the size from normal header was 0xFFFFFFFF Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) Patch created by Daniel Borca Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson */ #include #include #include // Matt Connolly 2013-09-12: this was defined in minizip 1.1. // @see http://www.winimage.com/zLibDll/minizip.html // Defining it defeats the ability to unzip password protected zip files, so this // is commented out so that existing tests pass. //#ifndef NOUNCRYPT // #define NOUNCRYPT //#endif #include "zlib.h" #include "unzip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef CASESENSITIVITYDEFAULT_NO # if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) # define CASESENSITIVITYDEFAULT_NO # endif #endif #ifndef UNZ_BUFSIZE #define UNZ_BUFSIZE (16384) #endif #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; /* unz_file_info_interntal contain internal info about a file in zipfile*/ typedef struct unz_file_info64_internal_s { ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ } unz_file_info64_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile, when reading and decompress it */ typedef struct { char *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ uLong stream_initialised; /* flag set if stream structure is initialised*/ ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ uInt size_local_extrafield;/* size of the local extra field */ ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ ZPOS64_T total_out_64; uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ uLong compression_method; /* compression method (0==store) */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; } file_in_zip64_read_info_s; /* unz64_s contain internal information about the zipfile */ typedef struct { zlib_filefunc64_32_def z_filefunc; int is64bitOpenFunction; voidpf filestream; /* io structore of the zipfile */ unz_global_info64 gi; /* public global information */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T num_file; /* number of the current file in the zipfile*/ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ ZPOS64_T central_pos; /* position of the beginning of the central dir*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory with respect to the starting disk number */ unz_file_info64 cur_file_info; /* public info about the current file in zip*/ unz_file_info64_internal cur_file_info_internal; /* private info about it*/ file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current file if we are decompressing it */ int encrypted; int isZip64; # ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const unsigned long* pcrc_32_tab; # endif } unz64_s; #ifndef NOUNCRYPT #include "crypt.h" #endif /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. */ local int unz64local_getByte OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int unz64local_getShort OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<8; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<16; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong64 OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (ZPOS64_T)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<8; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<16; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<24; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<32; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<40; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<48; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<56; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } /* My own strcmpi / strcasecmp */ local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= 0x20; if ((c2>='a') && (c2<='z')) c2 -= 0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } #ifdef CASESENSITIVITYDEFAULT_NO #define CASESENSITIVITYDEFAULTVALUE 2 #else #define CASESENSITIVITYDEFAULTVALUE 1 #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity) { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir64 OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; uLong uL; ZPOS64_T relativeOffset; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); if (uPosFound == 0) return 0; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature, already checked */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 0) return 0; /* relative offset of the zip64 end of central directory record */ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) return 0; /* total number of disks */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 1) return 0; /* Goto end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 0x06064b50) return 0; return relativeOffset; } /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer "zlib/zlib114.zip". If the zipfile cannot be opened (file doesn't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ local unzFile unzOpenInternal (const void *path, zlib_filefunc64_32_def* pzlib_filefunc64_32_def, int is64bitOpenFunction) { unz64_s us; unz64_s *s; ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ int err=UNZ_OK; if (unz_copyright[0]!=' ') return NULL; us.z_filefunc.zseek32_file = NULL; us.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def==NULL) fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); else us.z_filefunc = *pzlib_filefunc64_32_def; us.is64bitOpenFunction = is64bitOpenFunction; us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream==NULL) return NULL; central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); if (central_pos) { uLong uS; ZPOS64_T uL64; us.isZip64 = 1; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* size of zip64 end of central directory record */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) err=UNZ_ERRNO; /* version made by */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) err=UNZ_ERRNO; /* version needed to extract */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central directory on this disk */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; us.gi.size_comment = 0; } else { central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); if (central_pos==0) err=UNZ_ERRNO; us.isZip64 = 0; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir on this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.gi.number_entry = uL; /* total number of entries in the central dir */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; number_entry_CD = uL; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.offset_central_dir = uL; /* zipfile comment length */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; } if ((central_pospfile_in_zip_read!=NULL) unzCloseCurrentFile(file); ZCLOSE64(s->z_filefunc, s->filestream); TRYFREE(s); return UNZ_OK; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; *pglobal_info=s->gi; return UNZ_OK; } extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* to do : check if number_entry is not truncated */ pglobal_info32->number_entry = (uLong)s->gi.number_entry; pglobal_info32->size_comment = s->gi.size_comment; return UNZ_OK; } /* Translate date/time from Dos format to tm_unz (readable more easilty) */ local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) { ZPOS64_T uDate; uDate = (ZPOS64_T)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); local int unz64local_GetCurrentFileInfoInternal (unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz64_s* s; unz_file_info64 file_info; unz_file_info64_internal file_info_internal; int err=UNZ_OK; uLong uMagic; long lSeek=0; uLong uL; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (ZSEEK64(s->z_filefunc, s->filestream, s->pos_in_central_dir+s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* we check the magic */ if (err==UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info.compressed_size = uL; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info.uncompressed_size = uL; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; // relative offset of local header if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info_internal.offset_curfile = uL; lSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek -= uSizeRead; } // Read extrafield if ((err==UNZ_OK) && (extraField!=NULL)) { ZPOS64_T uSizeRead ; if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek += file_info.size_file_extra - (uLong)uSizeRead; } else lSeek += file_info.size_file_extra; if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) { uLong acc = 0; // since lSeek now points to after the extra field we need to move back lSeek -= file_info.size_file_extra; if (lSeek!=0) { if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } while(acc < file_info.size_file_extra) { uLong headerId; uLong dataSize; if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) err=UNZ_ERRNO; /* ZIP64 extra fields */ if (headerId == 0x0001) { uLong uL; if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) { /* Relative Header offset */ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.disk_num_start == (unsigned long)-1) { /* Disk Start Number */ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; } } else { if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) err=UNZ_ERRNO; } acc += 2 + 2 + dataSize; } } if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek+=file_info.size_file_comment - uSizeRead; } else lSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, unz_file_info64 * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, unz_file_info * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { int err; unz_file_info64 file_info64; err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); if (err==UNZ_OK) { pfile_info->version = file_info64.version; pfile_info->version_needed = file_info64.version_needed; pfile_info->flag = file_info64.flag; pfile_info->compression_method = file_info64.compression_method; pfile_info->dosDate = file_info64.dosDate; pfile_info->crc = file_info64.crc; pfile_info->size_filename = file_info64.size_filename; pfile_info->size_file_extra = file_info64.size_file_extra; pfile_info->size_file_comment = file_info64.size_file_comment; pfile_info->disk_num_start = file_info64.disk_num_start; pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; pfile_info->tmu_date = file_info64.tmu_date, pfile_info->compressed_size = (uLong)file_info64.compressed_size; pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; } return err; } /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToFirstFile (unzFile file) { int err=UNZ_OK; unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzGoToNextFile (unzFile file) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzipStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) { unz64_s* s; int err; /* We remember the 'current' position in the file so that we can jump * back there if we fail. */ unz_file_info64 cur_file_infoSaved; unz_file_info64_internal cur_file_info_internalSaved; ZPOS64_T num_fileSaved; ZPOS64_T pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; /* Save the current state */ num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; cur_file_infoSaved = s->cur_file_info; cur_file_info_internalSaved = s->cur_file_info_internal; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; err = unzGetCurrentFileInfo64(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (err == UNZ_OK) { if (unzStringFileNameCompare(szCurrentFileName, szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } } /* We failed, so restore the state of the 'current file' to where we * were. */ s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; s->cur_file_info = cur_file_infoSaved; s->cur_file_info_internal = cur_file_info_internalSaved; return err; } /* /////////////////////////////////////////// // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) // I need random access // // Further optimization could be realized by adding an ability // to cache the directory in memory. The goal being a single // comprehensive file read to put the file I need in a memory. */ /* typedef struct unz_file_pos_s { ZPOS64_T pos_in_zip_directory; // offset in file ZPOS64_T num_of_file; // # of file } unz_file_pos; */ extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) { unz64_s* s; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; file_pos->pos_in_zip_directory = s->pos_in_central_dir; file_pos->num_of_file = s->num_file; return UNZ_OK; } extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; int err = unzGetFilePos64(file,&file_pos64); if (err==UNZ_OK) { file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; file_pos->num_of_file = (uLong)file_pos64.num_of_file; } return err; } extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) { unz64_s* s; int err; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* jump to the right spot */ s->pos_in_central_dir = file_pos->pos_in_zip_directory; s->num_file = file_pos->num_of_file; /* set the current file */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); /* return results */ s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; if (file_pos == NULL) return UNZ_PARAMERROR; file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; file_pos64.num_of_file = file_pos->num_of_file; return unzGoToFilePos64(file,&file_pos64); } /* // Unzip Helper Functions - should be here? /////////////////////////////////////////// */ /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, ZPOS64_T * poffset_local_extrafield, uInt * psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; /* else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) err=UNZ_BADZIPFILE; */ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && /* #ifdef HAVE_BZIP2 */ (s->cur_file_info.compression_method!=Z_BZIP2ED) && /* #endif */ (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ err=UNZ_ERRNO; else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ err=UNZ_ERRNO; else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, int* level, int raw, const char* password) { int err=UNZ_OK; uInt iSizeVar; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ # ifndef NOUNCRYPT char source[12]; # else if (password != NULL) return UNZ_PARAMERROR; # endif if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; pfile_in_zip_read_info->raw=raw; if (pfile_in_zip_read_info->read_buffer==NULL) { TRYFREE(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if (method!=NULL) *method = (int)s->cur_file_info.compression_method; if (level!=NULL) { *level = 6; switch (s->cur_file_info.flag & 0x06) { case 6 : *level = 1; break; case 4 : *level = 2; break; case 2 : *level = 9; break; } } if ((s->cur_file_info.compression_method!=0) && /* #ifdef HAVE_BZIP2 */ (s->cur_file_info.compression_method!=Z_BZIP2ED) && /* #endif */ (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->total_out_64=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->filestream=s->filestream; pfile_in_zip_read_info->z_filefunc=s->z_filefunc; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) { #ifdef HAVE_BZIP2 pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; pfile_in_zip_read_info->bstream.bzfree = (free_func)0; pfile_in_zip_read_info->bstream.opaque = (voidpf)0; pfile_in_zip_read_info->bstream.state = (voidpf)0; pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = (voidpf)0; pfile_in_zip_read_info->stream.avail_in = 0; err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; else { TRYFREE(pfile_in_zip_read_info); return err; } #else pfile_in_zip_read_info->raw=1; #endif } else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = NULL; pfile_in_zip_read_info->stream.avail_in = 0; err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; else { TRYFREE(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the * size of both compressed and uncompressed data */ } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; s->encrypted = 0; # ifndef NOUNCRYPT if (password != NULL) { int i; s->pcrc_32_tab = get_crc_table(); init_keys(password,s->keys,s->pcrc_32_tab); if (ZSEEK64(s->z_filefunc, s->filestream, s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, SEEK_SET)!=0) return UNZ_INTERNALERROR; if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) return UNZ_INTERNALERROR; for (i = 0; i<12; i++) zdecode(s->keys,s->pcrc_32_tab,source[i]); s->pfile_in_zip_read->pos_in_zipfile+=12; s->encrypted=1; } # endif return UNZ_OK; } extern int ZEXPORT unzOpenCurrentFile (unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; s=(unz64_s*)file; if (file==NULL) return 0; //UNZ_PARAMERROR; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return 0; //UNZ_PARAMERROR; return pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile; } /** Addition for GDAL : END */ /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) { int err=UNZ_OK; uInt iRead = 0; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && (!(pfile_in_zip_read_info->raw))) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; if ((len>pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in) && (pfile_in_zip_read_info->raw)) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in; while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) return UNZ_EOF; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->read_buffer, uReadThis)!=uReadThis) return UNZ_ERRNO; # ifndef NOUNCRYPT if(s->encrypted) { uInt i; for(i=0;iread_buffer[i] = zdecode(s->keys,s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); } # endif pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; } if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) { uInt uDoCopy,i ; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (iRead==0) ? UNZ_EOF : iRead; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) { #ifdef HAVE_BZIP2 uLong uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; uLong uOutThis; pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; pfile_in_zip_read_info->bstream.total_in_hi32 = 0; pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; pfile_in_zip_read_info->bstream.total_out_hi32 = 0; uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; if (err==BZ_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=BZ_OK) break; #endif } // end Z_BZIP2ED else { ZPOS64_T uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; ZPOS64_T uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; /* if ((pfile_in_zip_read_info->rest_read_uncompressed == pfile_in_zip_read_info->stream.avail_out) && (pfile_in_zip_read_info->rest_read_compressed == 0)) flush = Z_FINISH; */ err=inflate(&pfile_in_zip_read_info->stream,flush); if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } /* Give the current position in uncompressed data */ extern z_off_t ZEXPORT unztell (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } extern ZPOS64_T ZEXPORT unztell64 (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return (ZPOS64_T)-1; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return (ZPOS64_T)-1; return pfile_in_zip_read_info->total_out_64; } /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzeof (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; uInt read_now; ZPOS64_T size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf,read_now)!=read_now) return UNZ_ERRNO; return (int)read_now; } /* Close the file in zip opened with unzipOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile (unzFile file) { int err=UNZ_OK; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } TRYFREE(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) inflateEnd(&pfile_in_zip_read_info->stream); #ifdef HAVE_BZIP2 else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); #endif pfile_in_zip_read_info->stream_initialised = 0; TRYFREE(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; return err; } /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) { unz64_s* s; uLong uReadThis ; if (file==NULL) return (int)UNZ_PARAMERROR; s=(unz64_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } /* Additions by RX '2004 */ extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) { unz64_s* s; if (file==NULL) return 0; //UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return 0; if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file==s->gi.number_entry) return 0; return s->pos_in_central_dir; } extern uLong ZEXPORT unzGetOffset (unzFile file) { ZPOS64_T offset64; if (file==NULL) return 0; //UNZ_PARAMERROR; offset64 = unzGetOffset64(file); return (uLong)offset64; } extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir = pos; s->num_file = s->gi.number_entry; /* hack */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) { return unzSetOffset64(file,pos); } ================================================ FILE: Loader/libs/minizip/unzip.h ================================================ /* unzip.h -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt --------------------------------------------------------------------------------- Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. --------------------------------------------------------------------------------- Changes See header of unzip64.c */ #ifndef _unz64_H #define _unz64_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #ifdef HAVE_BZIP2 #include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagunzFile__ { int unused; } unzFile__; typedef unzFile__ *unzFile; #else typedef voidp unzFile; #endif #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile These data comes from the end of central dir */ typedef struct unz_global_info64_s { ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info64; typedef struct unz_global_info_s { uLong number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info; /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_info64_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ ZPOS64_T compressed_size; /* compressed size 8 bytes */ ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info64; typedef struct unz_file_info_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ uLong compressed_size; /* compressed size 4 bytes */ uLong uncompressed_size; /* uncompressed size 4 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, const char* fileName2, int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern unzFile ZEXPORT unzOpen OF((const char *path)); extern unzFile ZEXPORT unzOpen64 OF((const void *path)); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. the "64" function take a const void* pointer, because the path is just the value passed to the open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def)); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, zlib_filefunc64_def* pzlib_filefunc_def)); /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzipCloseCurrentFile before call unzipClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *szComment, uLong uSizeBuf)); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzLocateFile OF((unzFile file, const char *szFileName, int iCaseSensitivity)); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ /* ****************************************** */ /* Ryan supplied functions */ /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_pos_s { uLong pos_in_zip_directory; /* offset in zip file directory */ uLong num_of_file; /* # of file */ } unz_file_pos; extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos); typedef struct unz64_file_pos_s { ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ ZPOS64_T num_of_file; /* # of file */ } unz64_file_pos; extern int ZEXPORT unzGetFilePos64( unzFile file, unz64_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos64( unzFile file, const unz64_file_pos* file_pos); /* ****************************************** */ extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain somes info about the current file if szFileName!=NULL, the filemane string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). This is the Central-header version of the extra field if szComment!=NULL, the comment string of the file will be copied in szComment (commentBufferSize is the size of the buffer) */ /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); /** Addition for GDAL : END */ /***************************************************************************/ /* for reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern z_off_t ZEXPORT unztell OF((unzFile file)); extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); /* Give the current position in uncompressed data */ extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ /***************************************************************************/ /* Get the current file offset */ extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); extern uLong ZEXPORT unzGetOffset (unzFile file); /* Set the current file offset */ extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); #ifdef __cplusplus } #endif #endif /* _unz64_H */ ================================================ FILE: Loader/libs/minizip/zip.c ================================================ /* zip.c -- IO on .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt Changes Oct-2009 - Mathias Svensson - Remove old C style function prototypes Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data It is used when recreting zip archive with RAW when deleting items from a zip. ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer */ #include #include #include #include #include "zlib.h" #include "zip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef VERSIONMADEBY # define VERSIONMADEBY (0x0) /* platform depedent */ #endif #ifndef Z_BUFSIZE #define Z_BUFSIZE (64*1024) //(16384) #endif #ifndef Z_MAXFILENAMEINZIP #define Z_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif /* #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) */ /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ // NOT sure that this work on ALL platform #define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef DEF_MEM_LEVEL #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif #endif const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; #define SIZEDATA_INDATABLOCK (4096-(4*4)) #define LOCALHEADERMAGIC (0x04034b50) #define CENTRALHEADERMAGIC (0x02014b50) #define ENDHEADERMAGIC (0x06054b50) #define ZIP64ENDHEADERMAGIC (0x6064b50) #define ZIP64ENDLOCHEADERMAGIC (0x7064b50) #define FLAG_LOCALHEADER_OFFSET (0x06) #define CRC_LOCALHEADER_OFFSET (0x0e) #define SIZECENTRALHEADER (0x2e) /* 46 */ typedef struct linkedlist_datablock_internal_s { struct linkedlist_datablock_internal_s* next_datablock; uLong avail_in_this_block; uLong filled_in_this_block; uLong unused; /* for future use and alignement */ unsigned char data[SIZEDATA_INDATABLOCK]; } linkedlist_datablock_internal; typedef struct linkedlist_data_s { linkedlist_datablock_internal* first_block; linkedlist_datablock_internal* last_block; } linkedlist_data; typedef struct { z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif int stream_initialised; /* 1 is stream is initialised */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ ZPOS64_T pos_local_header; /* offset of the local header of the file currenty writing */ char* central_header; /* central header data for the current file */ uLong size_centralExtra; uLong size_centralheader; /* size of the central header for cur file */ uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ uLong flag; /* flag of the file currently writing */ int method; /* compression method of file currenty wr.*/ int raw; /* 1 for directly writing raw data */ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; int encrypt; int zip64; /* Add ZIP64 extened information in the extra field */ ZPOS64_T pos_zip64extrainfo; ZPOS64_T totalCompressedData; ZPOS64_T totalUncompressedData; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const unsigned long* pcrc_32_tab; int crypt_header_size; #endif } curfile64_info; typedef struct { zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ linkedlist_data central_dir;/* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ curfile64_info ci; /* info on the file curretly writing */ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ ZPOS64_T add_position_when_writting_offset; ZPOS64_T number_entry; #ifndef NO_ADDFILEINEXISTINGZIP char *globalcomment; #endif } zip64_internal; #ifndef NOCRYPT #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED #include "crypt.h" #endif local linkedlist_datablock_internal* allocate_new_datablock() { linkedlist_datablock_internal* ldi; ldi = (linkedlist_datablock_internal*) ALLOC(sizeof(linkedlist_datablock_internal)); if (ldi!=NULL) { ldi->next_datablock = NULL ; ldi->filled_in_this_block = 0 ; ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; } return ldi; } local void free_datablock(linkedlist_datablock_internal* ldi) { while (ldi!=NULL) { linkedlist_datablock_internal* ldinext = ldi->next_datablock; TRYFREE(ldi); ldi = ldinext; } } local void init_linkedlist(linkedlist_data* ll) { ll->first_block = ll->last_block = NULL; } local void free_linkedlist(linkedlist_data* ll) { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) { linkedlist_datablock_internal* ldi; const unsigned char* from_copy; if (ll==NULL) return ZIP_INTERNALERROR; if (ll->last_block == NULL) { ll->first_block = ll->last_block = allocate_new_datablock(); if (ll->first_block == NULL) return ZIP_INTERNALERROR; } ldi = ll->last_block; from_copy = (unsigned char*)buf; while (len>0) { uInt copy_this; uInt i; unsigned char* to_copy; if (ldi->avail_in_this_block==0) { ldi->next_datablock = allocate_new_datablock(); if (ldi->next_datablock == NULL) return ZIP_INTERNALERROR; ldi = ldi->next_datablock ; ll->last_block = ldi; } if (ldi->avail_in_this_block < len) copy_this = (uInt)ldi->avail_in_this_block; else copy_this = (uInt)len; to_copy = &(ldi->data[ldi->filled_in_this_block]); for (i=0;ifilled_in_this_block += copy_this; ldi->avail_in_this_block -= copy_this; from_copy += copy_this ; len -= copy_this; } return ZIP_OK; } /****************************************************************************/ #ifndef NO_ADDFILEINEXISTINGZIP /* =========================================================================== Inputs a long in LSB order to the given file nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) { unsigned char buf[8]; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 (X Roche) */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) return ZIP_ERRNO; else return ZIP_OK; } local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) { unsigned char* buf=(unsigned char*)dest; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } } /****************************************************************************/ local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) { uLong year = (uLong)ptm->tm_year; if (year>=1980) year-=1980; else if (year>=80) year-=80; return (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /****************************************************************************/ local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return ZIP_OK; } else { if (ZERROR64(*pzlib_filefunc_def,filestream)) return ZIP_ERRNO; else return ZIP_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<16; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (ZPOS64_T)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<8; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<16; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<24; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<32; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<40; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<48; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<56; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; uLong uL; ZPOS64_T relativeOffset; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) { // Signature "0x07064b50" Zip64 end of central directory locater if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+i; break; } } if (uPosFound!=0) break; } TRYFREE(buf); if (uPosFound == 0) return 0; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature, already checked */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 0) return 0; /* relative offset of the zip64 end of central directory record */ if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) return 0; /* total number of disks */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 1) return 0; /* Goto Zip64 end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' return 0; return relativeOffset; } int LoadCentralDirectoryRecord(zip64_internal* pziinit) { int err=ZIP_OK; ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory */ ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ ZPOS64_T number_entry; ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ uLong VersionMadeBy; uLong VersionNeeded; uLong size_comment; int hasZIP64Record = 0; // check first if we find a ZIP64 record central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); if(central_pos > 0) { hasZIP64Record = 1; } else if(central_pos == 0) { central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); } /* disable to allow appending to empty ZIP archive if (central_pos==0) err=ZIP_ERRNO; */ if(hasZIP64Record) { ZPOS64_T sizeEndOfCentralDirectory; if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; /* the signature, already checked */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) err=ZIP_ERRNO; /* size of zip64 end of central directory record */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) err=ZIP_ERRNO; /* version made by */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) err=ZIP_ERRNO; /* version needed to extract */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) err=ZIP_ERRNO; /* number of this disk */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) err=ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central directory on this disk */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central directory */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) err=ZIP_ERRNO; if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=ZIP_BADZIPFILE; /* size of the central directory */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) err=ZIP_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) err=ZIP_ERRNO; // TODO.. // read the comment from the standard central header. size_comment = 0; } else { // Read End of central Directory info if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=ZIP_ERRNO; /* the signature, already checked */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) err=ZIP_ERRNO; /* number of this disk */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) err=ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central dir on this disk */ number_entry = 0; if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else number_entry = uL; /* total number of entries in the central dir */ number_entry_CD = 0; if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else number_entry_CD = uL; if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=ZIP_BADZIPFILE; /* size of the central directory */ size_central_dir = 0; if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ offset_central_dir = 0; if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else offset_central_dir = uL; /* zipfile global comment length */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) err=ZIP_ERRNO; } if ((central_posz_filefunc, pziinit->filestream); return ZIP_ERRNO; } if (size_comment>0) { pziinit->globalcomment = (char*)ALLOC(size_comment+1); if (pziinit->globalcomment) { size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); pziinit->globalcomment[size_comment]=0; } } byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); pziinit->add_position_when_writting_offset = byte_before_the_zipfile; { ZPOS64_T size_central_dir_to_read = size_central_dir; size_t buf_size = SIZEDATA_INDATABLOCK; void* buf_read = (void*)ALLOC(buf_size); if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; while ((size_central_dir_to_read>0) && (err==ZIP_OK)) { ZPOS64_T read_this = SIZEDATA_INDATABLOCK; if (read_this > size_central_dir_to_read) read_this = size_central_dir_to_read; if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) err=ZIP_ERRNO; if (err==ZIP_OK) err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); size_central_dir_to_read-=read_this; } TRYFREE(buf_read); } pziinit->begin_pos = byte_before_the_zipfile; pziinit->number_entry = number_entry_CD; if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; return err; } #endif /* !NO_ADDFILEINEXISTINGZIP*/ /************************************************************/ extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) { zip64_internal ziinit; zip64_internal* zi; int err=ZIP_OK; ziinit.z_filefunc.zseek32_file = NULL; ziinit.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def==NULL) fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); else ziinit.z_filefunc = *pzlib_filefunc64_32_def; ziinit.filestream = ZOPEN64(ziinit.z_filefunc, pathname, (append == APPEND_STATUS_CREATE) ? (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); if (ziinit.filestream == NULL) return NULL; if (append == APPEND_STATUS_CREATEAFTER) ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); ziinit.in_opened_file_inzip = 0; ziinit.ci.stream_initialised = 0; ziinit.number_entry = 0; ziinit.add_position_when_writting_offset = 0; init_linkedlist(&(ziinit.central_dir)); zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); if (zi==NULL) { ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); return NULL; } /* now we add file in a zipfile */ # ifndef NO_ADDFILEINEXISTINGZIP ziinit.globalcomment = NULL; if (append == APPEND_STATUS_ADDINZIP) { // Read and Cache Central Directory Records err = LoadCentralDirectoryRecord(&ziinit); } if (globalcomment) { *globalcomment = ziinit.globalcomment; } # endif /* !NO_ADDFILEINEXISTINGZIP*/ if (err != ZIP_OK) { # ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(ziinit.globalcomment); # endif /* !NO_ADDFILEINEXISTINGZIP*/ TRYFREE(zi); return NULL; } else { *zi = ziinit; return (zipFile)zi; } } extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); } else return zipOpen3(pathname, append, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; zlib_filefunc64_32_def_fill.ztell32_file = NULL; zlib_filefunc64_32_def_fill.zseek32_file = NULL; return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); } else return zipOpen3(pathname, append, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen (const char* pathname, int append) { return zipOpen3((const void*)pathname,append,NULL,NULL); } extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) { return zipOpen3(pathname,append,NULL,NULL); } int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) { /* write the local header */ int err; uInt size_filename = (uInt)strlen(filename); uInt size_extrafield = size_extrafield_local; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ } if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); if(zi->ci.zip64) { size_extrafield += 20; } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); if ((err==ZIP_OK) && (size_filename > 0)) { if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) err = ZIP_ERRNO; } if ((err==ZIP_OK) && (size_extrafield_local > 0)) { if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) err = ZIP_ERRNO; } if ((err==ZIP_OK) && (zi->ci.zip64)) { // write the Zip64 extended info short HeaderID = 1; short DataSize = 16; ZPOS64_T CompressedSize = 0; ZPOS64_T UncompressedSize = 0; // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); } return err; } /* NOTE. When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped before calling this function it can be done with zipRemoveExtraInfoBlock It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize unnecessary allocations. */ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64) { zip64_internal* zi; uInt size_filename; uInt size_comment; uInt i; int err = ZIP_OK; # ifdef NOCRYPT if (password != NULL) return ZIP_PARAMERROR; # endif if (file == NULL) return ZIP_PARAMERROR; #ifdef HAVE_BZIP2 if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) return ZIP_PARAMERROR; #else if ((method!=0) && (method!=Z_DEFLATED)) return ZIP_PARAMERROR; #endif zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); if (err != ZIP_OK) return err; } if (filename==NULL) filename="-"; if (comment==NULL) size_comment = 0; else size_comment = (uInt)strlen(comment); size_filename = (uInt)strlen(filename); if (zipfi == NULL) zi->ci.dosDate = 0; else { if (zipfi->dosDate != 0) zi->ci.dosDate = zipfi->dosDate; else zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); } zi->ci.flag = flagBase; if ((level==8) || (level==9)) zi->ci.flag |= 2; if (level==2) zi->ci.flag |= 4; if (level==1) zi->ci.flag |= 6; if (password != NULL) zi->ci.flag |= 1; zi->ci.crc32 = 0; zi->ci.method = method; zi->ci.encrypt = 0; zi->ci.stream_initialised = 0; zi->ci.pos_in_buffered_data = 0; zi->ci.raw = raw; zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); zi->ci.size_centralExtra = size_extrafield_global; zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); /* version info */ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ if (zipfi==NULL) zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); else zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); if (zipfi==NULL) zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); else zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); if(zi->ci.pos_local_header >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); else zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = *(((const char*)extrafield_global)+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ size_extrafield_global+i) = *(comment+i); if (zi->ci.central_header == NULL) return ZIP_INTERNALERROR; zi->ci.zip64 = zip64; zi->ci.totalCompressedData = 0; zi->ci.totalUncompressedData = 0; zi->ci.pos_zip64extrainfo = 0; err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); #ifdef HAVE_BZIP2 zi->ci.bstream.avail_in = (uInt)0; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; zi->ci.bstream.total_in_hi32 = 0; zi->ci.bstream.total_in_lo32 = 0; zi->ci.bstream.total_out_hi32 = 0; zi->ci.bstream.total_out_lo32 = 0; #endif zi->ci.stream.avail_in = (uInt)0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; zi->ci.stream.total_in = 0; zi->ci.stream.total_out = 0; zi->ci.stream.data_type = Z_BINARY; #ifdef HAVE_BZIP2 if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) #else if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) #endif { if(zi->ci.method == Z_DEFLATED) { zi->ci.stream.zalloc = (alloc_func)0; zi->ci.stream.zfree = (free_func)0; zi->ci.stream.opaque = (voidpf)0; if (windowBits>0) windowBits = -windowBits; err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); if (err==Z_OK) zi->ci.stream_initialised = Z_DEFLATED; } else if(zi->ci.method == Z_BZIP2ED) { #ifdef HAVE_BZIP2 // Init BZip stuff here zi->ci.bstream.bzalloc = 0; zi->ci.bstream.bzfree = 0; zi->ci.bstream.opaque = (voidpf)0; err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); if(err == BZ_OK) zi->ci.stream_initialised = Z_BZIP2ED; #endif } } # ifndef NOCRYPT zi->ci.crypt_header_size = 0; if ((err==Z_OK) && (password != NULL)) { unsigned char bufHead[RAND_HEAD_LEN]; unsigned int sizeHead; zi->ci.encrypt = 1; zi->ci.pcrc_32_tab = get_crc_table(); /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); zi->ci.crypt_header_size = sizeHead; if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) err = ZIP_ERRNO; } # endif if (err==Z_OK) zi->in_opened_file_inzip = 1; return err; } extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, versionMadeBy, flagBase, 0); } extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } local int zip64FlushWriteBuffer(zip64_internal* zi) { int err=ZIP_OK; if (zi->ci.encrypt != 0) { #ifndef NOCRYPT uInt i; int t; for (i=0;ici.pos_in_buffered_data;i++) zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); #endif } if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) err = ZIP_ERRNO; zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; #ifdef HAVE_BZIP2 if(zi->ci.method == Z_BZIP2ED) { zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; zi->ci.bstream.total_in_lo32 = 0; zi->ci.bstream.total_in_hi32 = 0; } else #endif { zi->ci.totalUncompressedData += zi->ci.stream.total_in; zi->ci.stream.total_in = 0; } zi->ci.pos_in_buffered_data = 0; return err; } extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) { zip64_internal* zi; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); #ifdef HAVE_BZIP2 if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) { zi->ci.bstream.next_in = (void*)buf; zi->ci.bstream.avail_in = len; err = BZ_RUN_OK; while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) { if (zi->ci.bstream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; } if(err != BZ_RUN_OK) break; if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; // uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; } } if(err == BZ_RUN_OK) err = ZIP_OK; } else #endif { zi->ci.stream.next_in = (Bytef*)buf; zi->ci.stream.avail_in = len; while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) { if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } if(err != ZIP_OK) break; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { uLong uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_NO_FLUSH); if(uTotalOutBefore > zi->ci.stream.total_out) { int bBreak = 0; bBreak++; } zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } else { uInt copy_this,i; if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) copy_this = zi->ci.stream.avail_in; else copy_this = zi->ci.stream.avail_out; for (i = 0; i < copy_this; i++) *(((char*)zi->ci.stream.next_out)+i) = *(((const char*)zi->ci.stream.next_in)+i); { zi->ci.stream.avail_in -= copy_this; zi->ci.stream.avail_out-= copy_this; zi->ci.stream.next_in+= copy_this; zi->ci.stream.next_out+= copy_this; zi->ci.stream.total_in+= copy_this; zi->ci.stream.total_out+= copy_this; zi->ci.pos_in_buffered_data += copy_this; } } }// while(...) } return err; } extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) { return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); } extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) { zip64_internal* zi; ZPOS64_T compressed_size; uLong invalidValue = 0xffffffff; short datasize = 0; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.avail_in = 0; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { while (err==ZIP_OK) { uLong uTotalOutBefore; if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_FINISH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } } else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { #ifdef HAVE_BZIP2 err = BZ_FINISH_OK; while (err==BZ_FINISH_OK) { uLong uTotalOutBefore; if (zi->ci.bstream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; } uTotalOutBefore = zi->ci.bstream.total_out_lo32; err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); if(err == BZ_STREAM_END) err = Z_STREAM_END; zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); } if(err == BZ_FINISH_OK) err = ZIP_OK; #endif } if (err==Z_STREAM_END) err=ZIP_OK; /* this is normal */ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) { if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) err = ZIP_ERRNO; } if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { int tmp_err = deflateEnd(&zi->ci.stream); if (err == ZIP_OK) err = tmp_err; zi->ci.stream_initialised = 0; } #ifdef HAVE_BZIP2 else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); if (err==ZIP_OK) err = tmperr; zi->ci.stream_initialised = 0; } #endif if (!zi->ci.raw) { crc32 = (uLong)zi->ci.crc32; uncompressed_size = zi->ci.totalUncompressedData; } compressed_size = zi->ci.totalCompressedData; # ifndef NOCRYPT compressed_size += zi->ci.crypt_header_size; # endif // update Current Item crc and sizes, if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) { /*version Made by*/ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); /*version needed*/ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); } zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ if(compressed_size >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ else zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ /// set internal file attributes field if (zi->ci.stream.data_type == Z_ASCII) zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); if(uncompressed_size >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ else zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ // Add ZIP64 extra info field for uncompressed size if(uncompressed_size >= 0xffffffff) datasize += 8; // Add ZIP64 extra info field for compressed size if(compressed_size >= 0xffffffff) datasize += 8; // Add ZIP64 extra info field for relative offset to local file header of current file if(zi->ci.pos_local_header >= 0xffffffff) datasize += 8; if(datasize > 0) { char* p = NULL; if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) { // we can not write more data to the buffer that we have room for. return ZIP_BADZIPFILE; } p = zi->ci.central_header + zi->ci.size_centralheader; // Add Extra Information Header for 'ZIP64 information' zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID p += 2; zip64local_putValue_inmemory(p, datasize, 2); // DataSize p += 2; if(uncompressed_size >= 0xffffffff) { zip64local_putValue_inmemory(p, uncompressed_size, 8); p += 8; } if(compressed_size >= 0xffffffff) { zip64local_putValue_inmemory(p, compressed_size, 8); p += 8; } if(zi->ci.pos_local_header >= 0xffffffff) { zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); p += 8; } // Update how much extra free space we got in the memory buffer // and increase the centralheader size so the new ZIP64 fields are included // ( 4 below is the size of HeaderID and DataSize field ) zi->ci.size_centralExtraFree -= datasize + 4; zi->ci.size_centralheader += datasize + 4; // Update the extra info size field zi->ci.size_centralExtra += datasize + 4; zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); } if (err==ZIP_OK) err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); free(zi->ci.central_header); if (err==ZIP_OK) { // Update the LocalFileHeader with the new values. ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ if(uncompressed_size >= 0xffffffff) { if(zi->ci.pos_zip64extrainfo > 0) { // Update the size in the ZIP64 extended field. if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); } } else { if (err==ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); } if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; } zi->number_entry ++; zi->in_opened_file_inzip = 0; return err; } extern int ZEXPORT zipCloseFileInZip (zipFile file) { return zipCloseFileInZipRaw (file,0,0); } int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) { int err = ZIP_OK; ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); /*num disks*/ if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /*relative offset*/ if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); return err; } int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; uLong Zip64DataSize = 44; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? if (err==ZIP_OK) /* version made by */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); if (err==ZIP_OK) /* version needed */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); if (err==ZIP_OK) /* number of this disk */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); if (err==ZIP_OK) /* total number of entries in the central dir */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); if (err==ZIP_OK) /* size of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); } return err; } int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; /*signature*/ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); if (err==ZIP_OK) /* number of this disk */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ { { if(zi->number_entry >= 0xFFFF) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); } } if (err==ZIP_OK) /* total number of entries in the central dir */ { if(zi->number_entry >= 0xFFFF) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); } if (err==ZIP_OK) /* size of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; if(pos >= 0xffffffff) { err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); } else err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); } return err; } int Write_GlobalComment(zip64_internal* zi, const char* global_comment) { int err = ZIP_OK; uInt size_global_comment = 0; if(global_comment != NULL) size_global_comment = (uInt)strlen(global_comment); err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); if (err == ZIP_OK && size_global_comment > 0) { if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) err = ZIP_ERRNO; } return err; } extern int ZEXPORT zipClose (zipFile file, const char* global_comment) { zip64_internal* zi; int err = 0; uLong size_centraldir = 0; ZPOS64_T centraldir_pos_inzip; ZPOS64_T pos; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); } #ifndef NO_ADDFILEINEXISTINGZIP if (global_comment==NULL) global_comment = zi->globalcomment; #endif centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); if (err==ZIP_OK) { linkedlist_datablock_internal* ldi = zi->central_dir.first_block; while (ldi!=NULL) { if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) { if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) err = ZIP_ERRNO; } size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_linkedlist(&(zi->central_dir)); pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; if(pos >= 0xffffffff) { ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); } if (err==ZIP_OK) err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); if(err == ZIP_OK) err = Write_GlobalComment(zi, global_comment); if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) if (err == ZIP_OK) err = ZIP_ERRNO; #ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(zi->globalcomment); #endif TRYFREE(zi); return err; } extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) { char* p = pData; int size = 0; char* pNewHeader; char* pTmp; short header; short dataSize; int retVal = ZIP_OK; if(pData == NULL || *dataLen < 4) return ZIP_PARAMERROR; pNewHeader = (char*)ALLOC(*dataLen); pTmp = pNewHeader; while(p < (pData + *dataLen)) { header = *(short*)p; dataSize = *(((short*)p)+1); if( header == sHeader ) // Header found. { p += dataSize + 4; // skip it. do not copy to temp buffer } else { // Extra Info block should not be removed, So copy it to the temp buffer. memcpy(pTmp, p, dataSize + 4); p += dataSize + 4; size += dataSize + 4; } } if(size < *dataLen) { // clean old extra info block. memset(pData,0, *dataLen); // copy the new extra info block over the old if(size > 0) memcpy(pData, pNewHeader, size); // set the new extra info size *dataLen = size; retVal = ZIP_OK; } else retVal = ZIP_ERRNO; TRYFREE(pNewHeader); return retVal; } ================================================ FILE: Loader/libs/minizip/zip.h ================================================ /* zip.h -- IO on .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt --------------------------------------------------------------------------- Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. --------------------------------------------------------------------------- Changes See header of zip.h */ #ifndef _zip12_H #define _zip12_H #ifdef __cplusplus extern "C" { #endif //#define HAVE_BZIP2 #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #ifdef HAVE_BZIP2 #include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagzipFile__ { int unused; } zipFile__; typedef zipFile__ *zipFile; #else typedef voidp zipFile; #endif #define ZIP_OK (0) #define ZIP_EOF (0) #define ZIP_ERRNO (Z_ERRNO) #define ZIP_PARAMERROR (-102) #define ZIP_BADZIPFILE (-103) #define ZIP_INTERNALERROR (-104) #ifndef DEF_MEM_LEVEL # if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 # else # define DEF_MEM_LEVEL MAX_MEM_LEVEL # endif #endif /* default memLevel */ /* tm_zip contain date/time info */ typedef struct tm_zip_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct { tm_zip tmz_date; /* date in understandable format */ uLong dosDate; /* if dos_date == 0, tmu_date is used */ /* uLong flag; */ /* general purpose bit flag 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ } zip_fileinfo; typedef const char* zipcharpc; #define APPEND_STATUS_CREATE (0) #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); /* Create a zipfile. pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip will be created at the end of the file. (useful if the file contain a self extractor code) if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will add files in existing zip (be sure you don't add file that doesn't exist) If the zipfile cannot be opened, the return value is NULL. Else, the return value is a zipFile Handle, usable with other function of this zip package. */ /* Note : there is no delete function into a zipfile. If you want delete file into a zipfile, you must open a zipfile, and create another Of couse, you can use RAW reading and writing to copy the file you did not want delte */ extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level)); extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64)); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local contains the extrafield data the the local header if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global contains the extrafield data the the local header if comment != NULL, comment contain the comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) zip64 is set to 1 if a zip64 extended information block should be added to the local file header. this MUST be '1' if the uncompressed size is >= 0xffffffff. */ extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw)); extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64)); /* Same than zipOpenNewFileInZip, except if raw=1, we write raw file */ extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting)); extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64 )); /* Same than zipOpenNewFileInZip2, except windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 password : crypting password (NULL for no crypting) crcForCrypting : crc of file to compress (needed for crypting) */ extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase )); extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64 )); /* Same than zipOpenNewFileInZip4, except versionMadeBy : value for Version made by field flag : value for flag field (compression level info will be added) */ extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); /* Write data in the zipfile */ extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); /* Close the current file in the zipfile */ extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, ZPOS64_T uncompressed_size, uLong crc32)); /* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 uncompressed_size and crc32 are value for the uncompressed size */ extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); /* Close the zipfile */ extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); /* zipRemoveExtraInfoBlock - Added by Mathias Svensson Remove extra information block from a extra information data for the local file header or central directory header It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. 0x0001 is the signature header for the ZIP64 extra information blocks usage. Remove ZIP64 Extra information from a central director extra field data zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); Remove ZIP64 Extra information from a Local File Header extra field data zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); */ #ifdef __cplusplus } #endif #endif /* _zip64_H */ ================================================ FILE: Loader/tools/packer.php ================================================ row) { //fix the out of bound bug here var content = self.dataSource().objectAtIndex(row); var ctrl = JPViewController.alloc().initWithContent(content); self.navigationController().pushViewController(ctrl); } }, dataSource: function() { // get the original method by adding prefix 'ORIG' var data = self.ORIGdataSource().toJS(); return data.push('Good!'); } }, {}) ``` 详细文档请参考wiki页面:[Usage of defineClass](https://github.com/bang590/JSPatch/wiki/Usage-of-defineClass) #### 扩展 一些自定义的struct类型、C函数调用以及其他功能可以通过扩展实现,调用 `+addExtensions:` 可以加载扩展接口: ```objc @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [JPEngine startEngine]; //添加扩展 [JPEngine addExtensions:@[@"JPInclude", @"JPCGTransform"]]; NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"]; NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; } ``` ```js include('test.js') //`include()`方法在扩展 JPInclude.m 里提供 var view = require('UIView').alloc().init() //struct CGAffineTransform 类型在 JPCGTransform.m 里提供支持 view.setTransform({a:1, b:0, c:0, d:1, tx:0, ty:100}) ``` 扩展可以在JS动态加载,更推荐这种加载方式,在需要用到时才加载: ```js require('JPEngine').addExtensions(['JPInclude', 'JPCGTransform']) // `include()` and `CGAffineTransform` is avaliable now. ``` 可以通过新增扩展为自己项目里的 struct 类型以及C函数添加支持,详情请见wiki页面:[Adding new extensions](https://github.com/bang590/JSPatch/wiki/Adding-new-extensions) ## 运行环境 - iOS 7+ - JavaScriptCore.framework - 支持 armv7/armv7s/arm64 ================================================ FILE: README.md ================================================ # JSPatch [![Travis](https://img.shields.io/travis/bang590/JSPatch.svg)](https://travis-ci.org/bang590/JSPatch) ![CocoaPods Version](https://img.shields.io/cocoapods/v/JSPatch.svg?style=flat) [![License](https://img.shields.io/github/license/bang590/JSPatch.svg?style=flat)](https://github.com/bang590/JSPatch/blob/master/LICENSE) [中文介绍](https://github.com/bang590/JSPatch/blob/master/README-CN.md) | [文档](https://github.com/bang590/JSPatch/wiki) | [JSPatch平台](http://jspatch.com) **请大家不要自行接入 JSPatch,统一接入 JSPatch 平台,让热修复在一个安全和可控的环境下使用。原因详见 [这里](http://jspatch.com/Docs/appleFAQ)** JSPatch bridges Objective-C and JavaScript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. That makes the APP obtaining the power of script language: add modules or replacing Objective-C code to fix bugs dynamically. JSPatch is still in development, welcome to improve the project together. **Notice**: Please go to [Wiki](https://github.com/bang590/JSPatch/wiki/) to get full document. ## Example ```objc @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [JPEngine startEngine]; NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"]; NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; [self.window addSubview:[self genView]]; [self.window makeKeyAndVisible]; return YES; } - (UIView *)genView { return [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)]; } @end ``` ```js // demo.js require('UIView, UIColor, UILabel') defineClass('AppDelegate', { // replace the -genView method genView: function() { var view = self.ORIGgenView(); view.setBackgroundColor(UIColor.greenColor()) var label = UILabel.alloc().initWithFrame(view.frame()); label.setText("JSPatch"); label.setTextAlignment(1); view.addSubview(label); return view; } }); ``` You can also try to use [JSPatch Convertor](https://github.com/bang590/JSPatchConvertor) to convertor code from Objective-C to JavaScript automatically. ## Installation ### CocoaPods [CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like JSPatch in your projects. See the ["Getting Started"](https://guides.cocoapods.org/using/getting-started.html) guide for more information. ```ruby # Your Podfile platform :ios, '6.0' pod 'JSPatch' ``` ### Manually Copy `JSEngine.m` `JSEngine.h` `JSPatch.js` in `JSPatch/` to your project. ## Usage ### Objective-C 1. `#import "JPEngine.h"` 2. call `[JPEngine startEngine]` 3. exec JavasScript by `[JPEngine evaluateScript:@""]` ```objc [JPEngine startEngine]; // exec js directly [JPEngine evaluateScript:@"\ var alertView = require('UIAlertView').alloc().init();\ alertView.setTitle('Alert');\ alertView.setMessage('AlertView from js'); \ alertView.addButtonWithTitle('OK');\ alertView.show(); \ "]; // exec js file from network [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://cnbang.net/test.js"]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSString *script = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; [JPEngine evaluateScript:script]; }]; // exec local js file NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"js"]; NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; ``` ### JavaScript #### Base Usage ```js //require require('UIView, UIColor, UISlider, NSIndexPath') // Invoke class method var redColor = UIColor.redColor(); // Invoke instance method var view = UIView.alloc().init(); view.setNeedsLayout(); // set proerty view.setBackgroundColor(redColor); // get property var bgColor = view.backgroundColor(); // multi-params method (use underline to separate) // OC:NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:1]; var indexPath = NSIndexPath.indexPathForRow_inSection(0, 1); // method name contains underline (use double undeline to represent) // OC: [JPObject _privateMethod]; JPObject.__privateMethod() // use .toJS() to convert NSArray / NSString / NSDictionary to JS type. var arr = require('NSMutableArray').alloc().init() arr.addObject("JS") jsArr = arr.toJS() console.log(jsArr.push("Patch").join('')) //output: JSPatch // use hashes to represent struct like CGRect / CGSize / CGPoint / NSRange var view = UIView.alloc().initWithFrame({x:20, y:20, width:100, height:100}); var x = view.bounds().x; // wrap function with `block()` when passing block from JS to OC // OC Method: + (void)request:(void(^)(NSString *content, BOOL success))callback require('JPObject').request(block("NSString *, BOOL", function(ctn, succ) { if (succ) log(ctn) })); // GCD dispatch_after(1.0, function(){ // do something }) dispatch_async_main(function(){ // do something }) ``` Go to wiki page for more details: [Base Usage](https://github.com/bang590/JSPatch/wiki/Base-usage) #### defineClass You can redefine an existing class and override methods. ```objc // OC @implementation JPTableViewController ... - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *content = self.dataSource[[indexPath row]]; //may cause out of bound JPViewController *ctrl = [[JPViewController alloc] initWithContent:content]; [self.navigationController pushViewController:ctrl]; } - (NSArray *)dataSource { return @[@"JSPatch", @"is"]; } - (void)customMethod { NSLog(@"callCustom method") } @end ``` ```objc // JS defineClass("JPTableViewController", { // instance method definitions tableView_didSelectRowAtIndexPath: function(tableView, indexPath) { var row = indexPath.row() if (self.dataSource().count() > row) { //fix the out of bound bug here var content = self.dataSource().objectAtIndex(row); var ctrl = JPViewController.alloc().initWithContent(content); self.navigationController().pushViewController(ctrl); } }, dataSource: function() { // get the original method by adding prefix 'ORIG' var data = self.ORIGdataSource().toJS(); return data.push('Good!'); } }, {}) ``` Go to wiki page for more details: [Usage of defineClass](https://github.com/bang590/JSPatch/wiki/Usage-of-defineClass) #### Extensions There are some extensions provide support for custom struct type, C methods and other functional, call `+addExtensions:` after starting engine to add extensions: ```objc @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [JPEngine startEngine]; //add extensions after startEngine [JPEngine addExtensions:@[@"JPInclude", @"JPCGTransform"]]; NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"]; NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil]; [JPEngine evaluateScript:script]; } @end ``` ```js include('test.js') //include function provide by JPInclude.m var view = require('UIView').alloc().init() //CGAffineTransform is supported in JPCGTransform.m view.setTransform({a:1, b:0, c:0, d:1, tx:0, ty:100}) ``` Extensions can be added dynamiclly in JS, which is recommended: ```js require('JPEngine').addExtensions(['JPInclude', 'JPCGTransform']) // `include()` and `CGAffineTransform` is avaliable now. ``` You can create your own extension to support custom struct type and C methods in project, see the wiki page for more details: [Adding new extensions](https://github.com/bang590/JSPatch/wiki/Adding-new-extensions) ## Enviroment - iOS 7+, forward compatibility with iOS 6 - JavaScriptCore.framework - Support armv7/armv7s/arm64