diff --git a/Code/CoreData/NSManagedObject+ActiveRecord.m b/Code/CoreData/NSManagedObject+ActiveRecord.m index e3d6db83a2..5bbbe04e9d 100644 --- a/Code/CoreData/NSManagedObject+ActiveRecord.m +++ b/Code/CoreData/NSManagedObject+ActiveRecord.m @@ -12,6 +12,9 @@ #import "NSManagedObject+ActiveRecord.h" #import "RKObjectManager.h" #import "RKLog.h" +#import "../Support/RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSManagedObject_ActiveRecord) // Set Logging Component #undef RKLogComponent diff --git a/Code/CoreData/RKObjectPropertyInspector+CoreData.m b/Code/CoreData/RKObjectPropertyInspector+CoreData.m index 85046008b6..232a1910aa 100644 --- a/Code/CoreData/RKObjectPropertyInspector+CoreData.m +++ b/Code/CoreData/RKObjectPropertyInspector+CoreData.m @@ -9,6 +9,9 @@ #import #import "RKObjectPropertyInspector+CoreData.h" #import "../Support/RKLog.h" +#import "../Support/RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(RKObjectPropertyInspector_CoreData) // Set Logging Component #undef RKLogComponent diff --git a/Code/Network/NSData+MD5.m b/Code/Network/NSData+MD5.m index eb823f9e47..ab2af56363 100644 --- a/Code/Network/NSData+MD5.m +++ b/Code/Network/NSData+MD5.m @@ -6,8 +6,11 @@ // Copyright 2011 Two Toasters. All rights reserved. // -#import "NSData+MD5.h" #import +#import "NSData+MD5.h" +#import "../Support/RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSData_MD5) @implementation NSData (MD5) diff --git a/Code/Network/NSDictionary+RKRequestSerialization.m b/Code/Network/NSDictionary+RKRequestSerialization.m index b7690b698e..1cc529d219 100644 --- a/Code/Network/NSDictionary+RKRequestSerialization.m +++ b/Code/Network/NSDictionary+RKRequestSerialization.m @@ -7,6 +7,9 @@ // #import "NSDictionary+RKRequestSerialization.h" +#import "../Support/RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSDictionary_RKRequestSerialization) /** * private helper function to convert any object to its string representation diff --git a/Code/Network/NSString+MD5.m b/Code/Network/NSString+MD5.m index 9c4e479102..402ece162e 100644 --- a/Code/Network/NSString+MD5.m +++ b/Code/Network/NSString+MD5.m @@ -6,8 +6,11 @@ // Copyright 2011 Two Toasters. All rights reserved. // -#import "NSString+MD5.h" #import +#import "NSString+MD5.h" +#import "../Support/RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSString_MD5) @implementation NSString (MD5) diff --git a/Code/Network/RKClient.h b/Code/Network/RKClient.h index 4061093313..278b26ab4b 100644 --- a/Code/Network/RKClient.h +++ b/Code/Network/RKClient.h @@ -129,6 +129,7 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar NSString* _serviceUnavailableAlertTitle; NSString* _serviceUnavailableAlertMessage; BOOL _serviceUnavailableAlertEnabled; + RKRequestQueue *_requestQueue; RKRequestCache* _cache; RKRequestCachePolicy _cachePolicy; NSMutableSet *_additionalRootCertificates; diff --git a/Code/Network/RKRequest.h b/Code/Network/RKRequest.h index e2c0e1ce2b..99176853a6 100644 --- a/Code/Network/RKRequest.h +++ b/Code/Network/RKRequest.h @@ -90,6 +90,7 @@ typedef enum RKRequestBackgroundPolicy { BOOL _forceBasicAuthentication; RKRequestCache* _cache; NSTimeInterval _cacheTimeoutInterval; + RKRequestQueue *_queue; #if TARGET_OS_IPHONE RKRequestBackgroundPolicy _backgroundPolicy; diff --git a/Code/Network/RKRequestQueue.h b/Code/Network/RKRequestQueue.h index e9f4c3634c..8102e55504 100644 --- a/Code/Network/RKRequestQueue.h +++ b/Code/Network/RKRequestQueue.h @@ -16,6 +16,7 @@ * for dispatching and managing RKRequest objects */ @interface RKRequestQueue : NSObject { + NSString *_name; NSMutableArray* _requests; NSObject* _delegate; NSUInteger _loadingCount; diff --git a/Code/Network/RKRequestQueue.m b/Code/Network/RKRequestQueue.m index 0ac642cc64..fcfc95246b 100644 --- a/Code/Network/RKRequestQueue.m +++ b/Code/Network/RKRequestQueue.m @@ -14,7 +14,11 @@ #import "RKResponse.h" #import "RKNotifications.h" #import "../Support/RKLog.h" +#import "../Support/RKFixCategoryBug.h" +RK_FIX_CATEGORY_BUG(UIApplication_RKNetworkActivity) + +// Constants static RKRequestQueue* RKRequestQueueSharedQueue = nil; static NSMutableArray* RKRequestQueueInstances = nil; diff --git a/Code/Support/NSDictionary+RKAdditions.m b/Code/Support/NSDictionary+RKAdditions.m index 45a73d8f50..1fdbfb16b4 100644 --- a/Code/Support/NSDictionary+RKAdditions.m +++ b/Code/Support/NSDictionary+RKAdditions.m @@ -7,6 +7,9 @@ // #import "NSDictionary+RKAdditions.h" +#import "RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSDictionary_RKAdditions) @implementation NSDictionary (RKAdditions) diff --git a/Code/Support/NSString+InflectionSupport.m b/Code/Support/NSString+InflectionSupport.m index a6a5d02980..2db536073b 100644 --- a/Code/Support/NSString+InflectionSupport.m +++ b/Code/Support/NSString+InflectionSupport.m @@ -7,6 +7,9 @@ // #import "NSString+InflectionSupport.h" +#import "RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSString_InflectionSupport) @implementation NSString (InflectionSupport) diff --git a/Code/Support/NSString+RestKit.h b/Code/Support/NSString+RestKit.h index edbe3d9f93..929bd3c4e0 100644 --- a/Code/Support/NSString+RestKit.h +++ b/Code/Support/NSString+RestKit.h @@ -12,7 +12,7 @@ A library of helpful additions to the NSString class to simplify common tasks within RestKit */ -@interface NSString (NSString) +@interface NSString (RestKit) /** Returns a resource path with a dictionary of query parameters URL encoded and appended diff --git a/Code/Support/NSString+RestKit.m b/Code/Support/NSString+RestKit.m index 09293e29f8..866f03826c 100644 --- a/Code/Support/NSString+RestKit.m +++ b/Code/Support/NSString+RestKit.m @@ -8,6 +8,9 @@ #import "NSString+RestKit.h" #import "../Network/RKClient.h" +#import "RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSString_RestKit) @implementation NSString (RestKit) diff --git a/Code/Support/RKFixCategoryBug.h b/Code/Support/RKFixCategoryBug.h new file mode 100644 index 0000000000..5bf2099750 --- /dev/null +++ b/Code/Support/RKFixCategoryBug.h @@ -0,0 +1,23 @@ +// +// RKCategoryFix.h +// RestKit +// +// Created by Blake Watters on 9/1/11. +// Copyright (c) 2011 RestKit. All rights reserved. +// + +#ifndef RestKit_RKCategoryFix_h +#define RestKit_RKCategoryFix_h + +/** + Add this macro before each category implementation, so we don't have to use + -all_load or -force_load to load object files from static libraries that only contain + categories and no classes. + See http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html for more info. + + Shamelessly borrowed from Three20 + */ +#define RK_FIX_CATEGORY_BUG(name) @interface RK_FIX_CATEGORY_BUG##name @end \ +@implementation RK_FIX_CATEGORY_BUG##name @end + +#endif diff --git a/Examples/RKCatalog/RKCatalog.xcodeproj/project.pbxproj b/Examples/RKCatalog/RKCatalog.xcodeproj/project.pbxproj index 7e482742a4..35184eb392 100644 --- a/Examples/RKCatalog/RKCatalog.xcodeproj/project.pbxproj +++ b/Examples/RKCatalog/RKCatalog.xcodeproj/project.pbxproj @@ -297,7 +297,7 @@ 2501DEAD13607B74003DE9E4 /* libRestKitXMLParserLibxml.a */, 2501DEAF13607B74003DE9E4 /* libRestKitCoreData.a */, 2501DEB113607B74003DE9E4 /* libRestKitThree20.a */, - 2501DEB313607B74003DE9E4 /* UISpec.app */, + 2501DEB313607B74003DE9E4 /* RestKitSpecs.app */, ); name = Products; sourceTree = ""; @@ -533,10 +533,10 @@ remoteRef = 2501DEB013607B74003DE9E4 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 2501DEB313607B74003DE9E4 /* UISpec.app */ = { + 2501DEB313607B74003DE9E4 /* RestKitSpecs.app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; - path = UISpec.app; + path = RestKitSpecs.app; remoteRef = 2501DEB213607B74003DE9E4 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -704,6 +704,7 @@ "\"$(SOURCE_ROOT)/../../Build/$(BUILD_STYLE)-$(PLATFORM_NAME)\"", "\"$(SRCROOT)\"", ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -721,6 +722,7 @@ "\"$(SOURCE_ROOT)/../../Build/$(BUILD_STYLE)-$(PLATFORM_NAME)\"", "\"$(SRCROOT)\"", ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; VALIDATE_PRODUCT = YES; WRAPPER_EXTENSION = app; diff --git a/Examples/RKDiscussionBoardExample/DiscussionBoard/DiscussionBoard.xcodeproj/project.pbxproj b/Examples/RKDiscussionBoardExample/DiscussionBoard/DiscussionBoard.xcodeproj/project.pbxproj index 25268bb889..4c3bfe4055 100755 --- a/Examples/RKDiscussionBoardExample/DiscussionBoard/DiscussionBoard.xcodeproj/project.pbxproj +++ b/Examples/RKDiscussionBoardExample/DiscussionBoard/DiscussionBoard.xcodeproj/project.pbxproj @@ -1114,7 +1114,7 @@ 25A7B1DB13421D28004816AA /* libRestKitXMLParserLibxml.a */, A7A2D3B512D7822D00683D6F /* libRestKitCoreData.a */, A7A2D3B712D7822D00683D6F /* libRestKitThree20.a */, - A7A2D3B912D7822D00683D6F /* UISpec.app */, + A7A2D3B912D7822D00683D6F /* RestKitSpecs.app */, ); name = Products; sourceTree = ""; @@ -1248,10 +1248,10 @@ remoteRef = A7A2D3B612D7822D00683D6F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - A7A2D3B912D7822D00683D6F /* UISpec.app */ = { + A7A2D3B912D7822D00683D6F /* RestKitSpecs.app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; - path = UISpec.app; + path = RestKitSpecs.app; remoteRef = A7A2D3B812D7822D00683D6F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1378,10 +1378,7 @@ "\"$(SRCROOT)/Libraries/three20\"", "\"$(SRCROOT)\"", ); - OTHER_LDFLAGS = ( - "-all_load", - "-ObjC", - ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "Discussion Board"; VALIDATE_PRODUCT = YES; }; @@ -1401,10 +1398,7 @@ ../../../Build, Libraries/three20/Build/Products/three20, ); - OTHER_LDFLAGS = ( - "-all_load", - "-ObjC", - ); + OTHER_LDFLAGS = "-ObjC"; SDKROOT = iphoneos; }; name = Debug; diff --git a/Examples/RKMacOSX/RKMacOSX.xcodeproj/project.pbxproj b/Examples/RKMacOSX/RKMacOSX.xcodeproj/project.pbxproj index 0b794d43ce..a33afe4656 100644 --- a/Examples/RKMacOSX/RKMacOSX.xcodeproj/project.pbxproj +++ b/Examples/RKMacOSX/RKMacOSX.xcodeproj/project.pbxproj @@ -232,7 +232,7 @@ 25D63964135184F1000879B1 /* libRestKitXMLParserLibxml.a */, 25D63966135184F1000879B1 /* libRestKitCoreData.a */, 25D63968135184F1000879B1 /* libRestKitThree20.a */, - 25D6396A135184F1000879B1 /* UISpec.app */, + 25D6396A135184F1000879B1 /* RestKitSpecs.app */, ); name = Products; sourceTree = ""; @@ -367,10 +367,10 @@ remoteRef = 25D63967135184F1000879B1 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 25D6396A135184F1000879B1 /* UISpec.app */ = { + 25D6396A135184F1000879B1 /* RestKitSpecs.app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; - path = UISpec.app; + path = RestKitSpecs.app; remoteRef = 25D63969135184F1000879B1 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -459,10 +459,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = ( - "-ObjC", - "-all_load", - ); + OTHER_LDFLAGS = "-ObjC"; SDKROOT = macosx; }; name = Debug; @@ -477,10 +474,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.6; - OTHER_LDFLAGS = ( - "-ObjC", - "-all_load", - ); + OTHER_LDFLAGS = "-ObjC"; SDKROOT = macosx; }; name = Release; @@ -499,6 +493,7 @@ "$(inherited)", "\"$(SRCROOT)\"", ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -518,6 +513,7 @@ "$(inherited)", "\"$(SRCROOT)\"", ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/Examples/RKTwitter/RKTwitter.xcodeproj/project.pbxproj b/Examples/RKTwitter/RKTwitter.xcodeproj/project.pbxproj index 313f0d1590..f2405af4aa 100755 --- a/Examples/RKTwitter/RKTwitter.xcodeproj/project.pbxproj +++ b/Examples/RKTwitter/RKTwitter.xcodeproj/project.pbxproj @@ -218,7 +218,7 @@ 250AC4AE1358C79C006F084F /* libRestKitXMLParserLibxml.a */, 250AC4B01358C79C006F084F /* libRestKitCoreData.a */, 250AC4B21358C79C006F084F /* libRestKitThree20.a */, - 250AC4B41358C79C006F084F /* UISpec.app */, + 250AC4B41358C79C006F084F /* RestKitSpecs.app */, ); name = Products; sourceTree = ""; @@ -399,10 +399,10 @@ remoteRef = 250AC4B11358C79C006F084F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 250AC4B41358C79C006F084F /* UISpec.app */ = { + 250AC4B41358C79C006F084F /* RestKitSpecs.app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; - path = UISpec.app; + path = RestKitSpecs.app; remoteRef = 250AC4B31358C79C006F084F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -469,10 +469,7 @@ HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Build"; INFOPLIST_FILE = "Resources/RKTwitter-Info.plist"; LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ( - "-all_load", - "-ObjC", - ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = RKTwitter; }; name = Debug; @@ -488,10 +485,7 @@ HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Build"; INFOPLIST_FILE = "Resources/RKTwitter-Info.plist"; LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ( - "-all_load", - "-ObjC", - ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = RKTwitter; VALIDATE_PRODUCT = YES; }; diff --git a/Examples/RKTwitterCoreData/RKTwitterCoreData.xcodeproj/project.pbxproj b/Examples/RKTwitterCoreData/RKTwitterCoreData.xcodeproj/project.pbxproj index 3d9cb60ddc..1e40f861d5 100755 --- a/Examples/RKTwitterCoreData/RKTwitterCoreData.xcodeproj/project.pbxproj +++ b/Examples/RKTwitterCoreData/RKTwitterCoreData.xcodeproj/project.pbxproj @@ -264,7 +264,7 @@ 251E0D53134189230017A6DA /* libRestKitXMLParserLibxml.a */, 3F3CE2CF125B93780083FDCB /* libRestKitCoreData.a */, 2538E808123417E500ACB5D7 /* libRestKitThree20.a */, - 2538E80A123417E500ACB5D7 /* UISpec.app */, + 2538E80A123417E500ACB5D7 /* RestKitSpecs.app */, ); name = Products; sourceTree = ""; @@ -412,10 +412,10 @@ remoteRef = 2538E807123417E500ACB5D7 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 2538E80A123417E500ACB5D7 /* UISpec.app */ = { + 2538E80A123417E500ACB5D7 /* RestKitSpecs.app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; - path = UISpec.app; + path = RestKitSpecs.app; remoteRef = 2538E809123417E500ACB5D7 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -563,10 +563,7 @@ GCC_PREFIX_HEADER = RKTwitter_Prefix.pch; HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Build"; INFOPLIST_FILE = "Resources/RKTwitter-Info.plist"; - OTHER_LDFLAGS = ( - "-all_load", - "-ObjC", - ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = RKTwitterCoreData; }; name = Debug; @@ -581,10 +578,7 @@ GCC_PREFIX_HEADER = RKTwitter_Prefix.pch; HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Build"; INFOPLIST_FILE = "Resources/RKTwitter-Info.plist"; - OTHER_LDFLAGS = ( - "-all_load", - "-ObjC", - ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = RKTwitterCoreData; VALIDATE_PRODUCT = YES; }; @@ -603,10 +597,7 @@ GCC_PREPROCESSOR_DEFINITIONS = RESTKIT_GENERATE_SEED_DB; HEADER_SEARCH_PATHS = ../../Build; INFOPLIST_FILE = "Resources/RKTwitter-Info.plist"; - OTHER_LDFLAGS = ( - "-all_load", - "-ObjC", - ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "Generate Seed Database"; }; name = Debug; @@ -622,10 +613,7 @@ GCC_PREPROCESSOR_DEFINITIONS = RESTKIT_GENERATE_SEED_DB; HEADER_SEARCH_PATHS = ../../Build; INFOPLIST_FILE = "Resources/RKTwitter-Info.plist"; - OTHER_LDFLAGS = ( - "-all_load", - "-ObjC", - ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "Generate Seed Database"; VALIDATE_PRODUCT = YES; }; diff --git a/README.md b/README.md index 5bd9674a7b..09a86b8bf9 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Quick Start (aka TL;DR) 1. Add **Header Search Path** to the `"$(SOURCE_ROOT)/RestKit/Build"` directory. **DO NOT** check the `Recursive` checkbox. 1. Add **Library Search Path** to the `"$(SOURCE_ROOT)/RestKit/Build/$(BUILD_STYLE)-$(PLATFORM_NAME)"` directory. **NOTE**: This is only necessary if you are **NOT** using DerivedData. -1. Add **Other Linker Flags** for `-ObjC -all_load` +1. Add **Other Linker Flags** for `-ObjC` 1. Open target settings editor for the target you want to link RestKit into 1. Add direct dependency on the **RestKit** aggregate target 1. Link against required frameworks: @@ -104,7 +104,7 @@ To add RestKit to your project (you're using git, right?): 1. Switch to the 'Build' tab in your project inspector. Make sure that your **Configuration** pop-up menu reads **All Configurations** so that your changes will work for all build configurations. 1. Find the **Header Search Paths** setting. Double click and add a new entry. When RestKit is compiled, it will copy all relevant headers to the appropriate location under the /Build directory within the RestKit checkout. You need to add a path to the /Build directory of RestKit, relative to your project file. For example, if you checked the submodule out in the root directory of your project, your header path would be `"$(SOURCE_ROOT)/RestKit/Build"`. 1. Find the **Library Search Paths** setting. Double click and add a new entry. Add a search path to your RestKit build directory such as `"$(SOURCE_ROOT)/RestKit/Build/$(BUILD_STYLE)-$(PLATFORM_NAME)"` -1. Now find the **Other Linker Flags** setting. Double click it and add entries for -all_load and -ObjC. +1. Now find the **Other Linker Flags** setting. Double click it and add entries for -ObjC. 1. You may now close out the inspector window. Xcode 4.x (Git Submodule) @@ -119,7 +119,7 @@ Xcode 4.x (Git Submodule) 1. Find the **Header Search Paths** setting. Double click and add a new entry. Add a search path to the `"$(SOURCE_ROOT)/RestKit/Build"` directory you have added to your project. **DO NOT** check the `Recursive` checkbox. 1. Find the **Library Search Paths** setting. Double click and add a new entry. Add a search path to the `"$(SOURCE_ROOT)/RestKit/Build/$(BUILD_STYLE)-$(PLATFORM_NAME)"` directory you have added to your project. **NOTE**: This is only necessary if you are **NOT** using DerivedData. -1. Find the **Other Linker Flags** entry and double click it. Use the **+** button to add a new entry and enter `-ObjC -all_load`. Dismiss the editor with the **Done** button. +1. Find the **Other Linker Flags** entry and double click it. Use the **+** button to add a new entry and enter `-ObjC`. Dismiss the editor with the **Done** button. 1. Locate the target you wish to add RestKit to in the **TARGETS** list in the middle of the editor pane. Select it to open the target settings editor in the right pane of the window. 1. Click the **Build Phases** tab along the top of the window to open the Build Phases editor. 1. Click the disclosure triangles next to the **Target Dependencies** and **Link Binary with Libraries** items. diff --git a/RestKit.xcodeproj/project.pbxproj b/RestKit.xcodeproj/project.pbxproj index d9136522d3..e5e5bdfb65 100644 --- a/RestKit.xcodeproj/project.pbxproj +++ b/RestKit.xcodeproj/project.pbxproj @@ -140,6 +140,7 @@ 257FB7091395DC44003A628E /* RKManagedObjectMappingOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 257FB7071395DC44003A628E /* RKManagedObjectMappingOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 257FB70A1395DC44003A628E /* RKManagedObjectMappingOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 257FB7081395DC44003A628E /* RKManagedObjectMappingOperation.m */; }; 258E490113C51FE600C9C883 /* RKJSONParserJSONKitSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 258E490013C51FE600C9C883 /* RKJSONParserJSONKitSpec.m */; }; + 258F846F1410574B007AABCD /* RKFixCategoryBug.h in Headers */ = {isa = PBXBuildFile; fileRef = 258F846E1410574B007AABCD /* RKFixCategoryBug.h */; settings = {ATTRIBUTES = (Private, ); }; }; 259050F413F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 259050F213F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 259050F513F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.m in Sources */ = {isa = PBXBuildFile; fileRef = 259050F313F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.m */; }; 2590E67F125235C200531FA8 /* JSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 2590E674125235C200531FA8 /* JSON.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -203,8 +204,6 @@ 25952F0F136F8F7700D04F93 /* users.json in Resources */ = {isa = PBXBuildFile; fileRef = 25952F0C136F8F7700D04F93 /* users.json */; }; 25952F12136F97B300D04F93 /* RKObjectSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 25952F10136F97B300D04F93 /* RKObjectSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25952F13136F97B300D04F93 /* RKObjectSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 25952F11136F97B300D04F93 /* RKObjectSerializer.m */; }; - 25952FDD1370959900D04F93 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 25952FD81370959900D04F93 /* LICENSE.txt */; }; - 25952FDF1370959900D04F93 /* README.markdown in Resources */ = {isa = PBXBuildFile; fileRef = 25952FDC1370959900D04F93 /* README.markdown */; }; 259562E4126D3B36004BAC4C /* RKObjectRouter.h in Headers */ = {isa = PBXBuildFile; fileRef = 259562E2126D3B36004BAC4C /* RKObjectRouter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 259562E5126D3B36004BAC4C /* RKObjectRouter.m in Sources */ = {isa = PBXBuildFile; fileRef = 259562E3126D3B36004BAC4C /* RKObjectRouter.m */; }; 25956983126DF1AE004BAC4C /* libRestKitCoreData.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 253A081412551D5300976E89 /* libRestKitCoreData.a */; }; @@ -551,6 +550,7 @@ 257FB70C1395DEB5003A628E /* RKManagedObjectMappingOperationSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectMappingOperationSpec.m; sourceTree = ""; }; 258C65EF133C317A004388A4 /* CopyHeadersToLegacyBuildDir.command */ = {isa = PBXFileReference; lastKnownFileType = text; path = CopyHeadersToLegacyBuildDir.command; sourceTree = ""; }; 258E490013C51FE600C9C883 /* RKJSONParserJSONKitSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKJSONParserJSONKitSpec.m; sourceTree = ""; }; + 258F846E1410574B007AABCD /* RKFixCategoryBug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKFixCategoryBug.h; sourceTree = ""; }; 259050F213F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RKObjectPropertyInspector+CoreData.h"; sourceTree = ""; }; 259050F313F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RKObjectPropertyInspector+CoreData.m"; sourceTree = ""; }; 2590E64F125231F600531FA8 /* libRestKitJSONParserYAJL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRestKitJSONParserYAJL.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -628,11 +628,6 @@ 25952F0C136F8F7700D04F93 /* users.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = users.json; sourceTree = ""; }; 25952F10136F97B300D04F93 /* RKObjectSerializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectSerializer.h; sourceTree = ""; }; 25952F11136F97B300D04F93 /* RKObjectSerializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectSerializer.m; sourceTree = ""; }; - 25952FD81370959900D04F93 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; - 25952FD91370959900D04F93 /* LoggerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoggerClient.h; sourceTree = ""; }; - 25952FDA1370959900D04F93 /* LoggerClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoggerClient.m; sourceTree = ""; }; - 25952FDB1370959900D04F93 /* LoggerCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoggerCommon.h; sourceTree = ""; }; - 25952FDC1370959900D04F93 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.markdown; sourceTree = ""; }; 259562E2126D3B36004BAC4C /* RKObjectRouter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectRouter.h; sourceTree = ""; }; 259562E3126D3B36004BAC4C /* RKObjectRouter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectRouter.m; sourceTree = ""; }; 259BEF5013C3B12B00487F66 /* RKObjectMappingResultSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMappingResultSpec.m; sourceTree = ""; }; @@ -1130,6 +1125,7 @@ 253A09F512552BDC00976E89 /* Support.h */, 251939B213A94B5F0073A39B /* NSString+RestKit.h */, 251939B313A94B5F0073A39B /* NSString+RestKit.m */, + 258F846E1410574B007AABCD /* RKFixCategoryBug.h */, ); path = Support; sourceTree = ""; @@ -1215,7 +1211,6 @@ isa = PBXGroup; children = ( 250D5BD913A0698100471F0E /* LibComponentLogging */, - 25952FD71370959900D04F93 /* NSLogger */, 20808DB713DE8C7C000A156A /* NXJSON */, 73057FC61331AA28001908EE /* JSONKit */, 2590E69A1252372800531FA8 /* YAJL */, @@ -1400,19 +1395,6 @@ path = humans; sourceTree = ""; }; - 25952FD71370959900D04F93 /* NSLogger */ = { - isa = PBXGroup; - children = ( - 25952FD81370959900D04F93 /* LICENSE.txt */, - 25952FD91370959900D04F93 /* LoggerClient.h */, - 25952FDA1370959900D04F93 /* LoggerClient.m */, - 25952FDB1370959900D04F93 /* LoggerCommon.h */, - 25952FDC1370959900D04F93 /* README.markdown */, - ); - name = NSLogger; - path = Vendor/NSLogger; - sourceTree = ""; - }; 259D510D1328547000897272 /* CoreData */ = { isa = PBXGroup; children = ( @@ -1645,6 +1627,7 @@ 250D5C0213A069EA00471F0E /* lcl_config_extensions.h in Headers */, 250D5C0413A06A4D00471F0E /* lcl_config_logger.h in Headers */, 251939B613A94B670073A39B /* NSString+RestKit.h in Headers */, + 258F846F1410574B007AABCD /* RKFixCategoryBug.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2001,8 +1984,6 @@ 25952F0D136F8F7700D04F93 /* nested_user.json in Resources */, 25952F0E136F8F7700D04F93 /* user.json in Resources */, 25952F0F136F8F7700D04F93 /* users.json in Resources */, - 25952FDD1370959900D04F93 /* LICENSE.txt in Resources */, - 25952FDF1370959900D04F93 /* README.markdown in Resources */, 251939E913AABED40073A39B /* DynamicKeys.json in Resources */, 251939EA13AABED40073A39B /* error.json in Resources */, 251939EB13AABED40073A39B /* errors.json in Resources */, @@ -2706,7 +2687,6 @@ "-force_load", "$(PROJECT_DIR)/Specs/Runner/OCMock/libOCMock.a", "-ObjC", - "-all_load", "-lstdc++", "-framework", SenTestingKit, @@ -3059,7 +3039,6 @@ "-force_load", "$(PROJECT_DIR)/Specs/Runner/OCMock/libOCMock.a", "-ObjC", - "-all_load", "-lstdc++", "-framework", SenTestingKit, @@ -3263,7 +3242,6 @@ "-force_load", "$(PROJECT_DIR)/Specs/Runner/OCMock/libOCMock.a", "-ObjC", - "-all_load", "-lstdc++", "-framework", SenTestingKit, @@ -3309,7 +3287,6 @@ "-force_load", "$(PROJECT_DIR)/Specs/Runner/OCMock/libOCMock.a", "-ObjC", - "-all_load", "-lstdc++", "-framework", SenTestingKit, diff --git a/Vendor/NSLogger/LICENSE.txt b/Vendor/NSLogger/LICENSE.txt deleted file mode 100644 index f1b652a858..0000000000 --- a/Vendor/NSLogger/LICENSE.txt +++ /dev/null @@ -1,23 +0,0 @@ -BSD license follows (http://www.opensource.org/licenses/bsd-license.php) - -Copyright (c) 2010, Florent Pillet All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are -permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must -reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the -distribution. Neither the name of Florent Pillet nor the names of its -contributors may be used to endorse or promote products derived from this software -without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT -HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Vendor/NSLogger/LoggerClient.h b/Vendor/NSLogger/LoggerClient.h deleted file mode 100644 index 14a44c80b3..0000000000 --- a/Vendor/NSLogger/LoggerClient.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * LoggerClient.h - * - * version 1.0b10 2011-02-18 - * - * Part of NSLogger (client side) - * https://github.com/fpillet/NSLogger - * - * BSD license follows (http://www.opensource.org/licenses/bsd-license.php) - * - * Copyright (c) 2010-2011 Florent Pillet All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. Redistributions in - * binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. Neither the name of Florent - * Pillet nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT - * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#import -#import -#import -#import -#import -#import -#if !TARGET_OS_IPHONE -#import -#endif - -// This define is here so that user application can test whether NSLogger Client is -// being included in the project, and potentially configure their macros accordingly -#define NSLOGGER_WAS_HERE 1 - -// Set this to 0 if you absolutely NOT want any access to Cocoa (Objective-C, NS* calls) -// We need a couple ones to reliably obtain the thread number and device information -// Note that since we need NSAutoreleasePool when using Cocoa in the logger's worker thread, -// we need to put Cocoa in multithreading mode. Also, ALLOW_COCOA_USE allows the client code -// to use NSLog()-style message formatting (less verbose than CFShow()-style) through the -// use of -[NSString stringWithFormat:arguments:] -#define ALLOW_COCOA_USE 1 - -/* ----------------------------------------------------------------- - * Logger option flags & default options - * ----------------------------------------------------------------- - */ -enum { - kLoggerOption_LogToConsole = 0x01, - kLoggerOption_BufferLogsUntilConnection = 0x02, - kLoggerOption_BrowseBonjour = 0x04, - kLoggerOption_BrowseOnlyLocalDomain = 0x08, - kLoggerOption_UseSSL = 0x10 -}; - -#define LOGGER_DEFAULT_OPTIONS (kLoggerOption_BufferLogsUntilConnection | \ - kLoggerOption_BrowseBonjour | \ - kLoggerOption_BrowseOnlyLocalDomain | \ - kLoggerOption_UseSSL) - -/* ----------------------------------------------------------------- - * Structure defining a Logger - * ----------------------------------------------------------------- - */ -typedef struct -{ - CFStringRef bufferFile; // If non-NULL, all buffering is done to the specified file instead of in-memory - CFStringRef host; // Viewer host to connect to (instead of using Bonjour) - UInt32 port; // port on the viewer host - - CFMutableArrayRef bonjourServiceBrowsers; // Active service browsers - CFMutableArrayRef bonjourServices; // Services being tried - CFNetServiceBrowserRef bonjourDomainBrowser; // Domain browser - - CFMutableArrayRef logQueue; // Message queue - pthread_mutex_t logQueueMutex; - pthread_cond_t logQueueEmpty; - - pthread_t workerThread; // The worker thread responsible for Bonjour resolution, connection and logs transmission - CFRunLoopSourceRef messagePushedSource; // A message source that fires on the worker thread when messages are available for send - CFRunLoopSourceRef bufferFileChangedSource; // A message source that fires on the worker thread when the buffer file configuration changes - - CFWriteStreamRef logStream; // The connected stream we're writing to - CFWriteStreamRef bufferWriteStream; // If bufferFile not NULL and we're not connected, points to a stream for writing log data - CFReadStreamRef bufferReadStream; // If bufferFile not NULL, points to a read stream that will be emptied prior to sending the rest of in-memory messages - - SCNetworkReachabilityRef reachability; // The reachability object we use to determine when the target host becomes reachable - CFRunLoopTimerRef checkHostTimer; // A timer to regularly check connection to the defined host, along with reachability for added reliability - - uint8_t *sendBuffer; // data waiting to be sent - NSUInteger sendBufferSize; - NSUInteger sendBufferUsed; // number of bytes of the send buffer currently in use - NSUInteger sendBufferOffset; // offset in sendBuffer to start sending at - - int32_t messageSeq; // sequential message number (added to each message sent) - - // settings - uint32_t options; // Flags, see enum above - CFStringRef bonjourServiceType; // leave NULL to use the default - CFStringRef bonjourServiceName; // leave NULL to use the first one available - - // internal state - BOOL connected; // Set to YES once the write stream declares the connection open - volatile BOOL quit; // Set to YES to terminate the logger worker thread's runloop - BOOL incompleteSendOfFirstItem; // set to YES if we are sending the first item in the queue and it's bigger than what the buffer can hold -} Logger; - - -/* ----------------------------------------------------------------- - * LOGGING FUNCTIONS - * ----------------------------------------------------------------- - */ - -#ifdef __cplusplus -extern "C" { -#endif - -// Functions to set and get the default logger -extern void LoggerSetDefaultLogger(Logger *aLogger); -extern Logger *LoggerGetDefaultLogger(); - -// Initialize a new logger, set as default logger if this is the first one -// Options default to: -// - logging to console = NO -// - buffer until connection = YES -// - browse Bonjour = YES -// - browse only locally on Bonjour = YES -extern Logger* LoggerInit(); - -// Set logger options if you don't want the default options (see above) -extern void LoggerSetOptions(Logger *logger, uint32_t options); - -// Set Bonjour logging names, so you can force the logger to use a specific service type -// or direct logs to the machine on your network which publishes a specific name -extern void LoggerSetupBonjour(Logger *logger, CFStringRef bonjourServiceType, CFStringRef bonjourServiceName); - -// Directly set the viewer host (hostname or IP address) and port we want to connect to. If set, LoggerStart() will -// try to connect there first before trying Bonjour -extern void LoggerSetViewerHost(Logger *logger, CFStringRef hostName, UInt32 port); - - -// Configure the logger to use a local file for buffering, instead of memory. -// - If you initially set a buffer file after logging started but while a logger connection -// has not been acquired, the contents of the log queue will be written to the buffer file -// the next time a logging function is called, or when LoggerStop() is called. -// - If you want to change the buffering file after logging started, you should first -// call LoggerStop() the call LoggerSetBufferFile(). Note that all logs stored in the previous -// buffer file WON'T be transferred to the new file in this case. -extern void LoggerSetBufferFile(Logger *logger, CFStringRef absolutePath); - -// Activate the logger, try connecting -extern void LoggerStart(Logger *logger); - -//extern void LoggerConnectToHost(CFDataRef address, int port); - -// Deactivate and free the logger. -extern void LoggerStop(Logger *logger); - -// Pause the current thread until all messages from the logger have been transmitted -// this is useful to use before an assert() aborts your program. If waitForConnection is YES, -// LoggerFlush() will block even if the client is not currently connected to the desktop -// viewer. You should be using NO most of the time, but in some cases it can be useful. -extern void LoggerFlush(Logger *logger, BOOL waitForConnection); - -/* Logging functions. Each function exists in four versions: - * - * - one without a Logger instance (uses default logger) and without filename/line/function (no F suffix) - * - one without a Logger instance but with filename/line/function (F suffix) - * - one with a Logger instance (use a specific Logger) and without filename/line/function (no F suffix) - * - one with a Logger instance (use a specific Logger) and with filename/line/function (F suffix) - * - * The exception being the single LogMessageCompat() function which is designed to be a drop-in replacement for NSLog() - * - */ - -// Log a message, calling format compatible with NSLog -extern void LogMessageCompat(NSString *format, ...); - -// Log a message. domain can be nil if default domain. -extern void LogMessage(NSString *domain, int level, NSString *format, ...); -extern void LogMessageF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, ...); -extern void LogMessageTo(Logger *logger, NSString *domain, int level, NSString *format, ...); -extern void LogMessageToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, ...); - -// Log a message. domain can be nil if default domain (versions with va_list format args instead of ...) -extern void LogMessage_va(NSString *domain, int level, NSString *format, va_list args); -extern void LogMessageF_va(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, va_list args); -extern void LogMessageTo_va(Logger *logger, NSString *domain, int level, NSString *format, va_list args); -extern void LogMessageToF_va(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, va_list args); - -// Send binary data to remote logger -extern void LogData(NSString *domain, int level, NSData *data); -extern void LogDataF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSData *data); -extern void LogDataTo(Logger *logger, NSString *domain, int level, NSData *data); -extern void LogDataToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSData *data); - -// Send image data to remote logger -extern void LogImageData(NSString *domain, int level, int width, int height, NSData *data); -extern void LogImageDataF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, int width, int height, NSData *data); -extern void LogImageDataTo(Logger *logger, NSString *domain, int level, int width, int height, NSData *data); -extern void LogImageDataToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, int width, int height, NSData *data); - -// Mark the start of a block. This allows the remote logger to group blocks together -extern void LogStartBlock(NSString *format, ...); -extern void LogStartBlockTo(Logger *logger, NSString *format, ...); - -// Mark the end of a block -extern void LogEndBlock(); -extern void LogEndBlockTo(Logger *logger); - -#ifdef __cplusplus -}; -#endif diff --git a/Vendor/NSLogger/LoggerClient.m b/Vendor/NSLogger/LoggerClient.m deleted file mode 100644 index f58e4775f5..0000000000 --- a/Vendor/NSLogger/LoggerClient.m +++ /dev/null @@ -1,2193 +0,0 @@ -/* - * LoggerClient.m - * - * version 1.0b10 2011-02-18 - * - * Main implementation of the NSLogger client side code - * Part of NSLogger (client side) - * https://github.com/fpillet/NSLogger - * - * BSD license follows (http://www.opensource.org/licenses/bsd-license.php) - * - * Copyright (c) 2010-2011 Florent Pillet All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. Redistributions in - * binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. Neither the name of Florent - * Pillet nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT - * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -// Defined here to enable building into static lib -#define ALLOW_COCOA_USE 1 - -#import -#if !TARGET_OS_IPHONE - #import - #import - #import -#elif ALLOW_COCOA_USE - #import -#endif -#import - -#import "LoggerClient.h" -#import "LoggerCommon.h" - -/* -------------------------------------------------------------------------------- - * IMPLEMENTATION NOTES: - * - * The logger runs in a separate thread. It is written - * in straight C for maximum compatibility with all runtime environments - * (does not use the Objective-C runtime, only uses unix and CoreFoundation - * calls, except for get the thread name and device information, but these - * can be disabled by setting ALLOW_COCOA_USE to 0). - * - * It is suitable for use in both Cocoa and low-level code. It does not activate - * Cocoa multi-threading (no call to [NSThread detachNewThread...]). You can start - * logging very early (as soon as your code starts running), logs will be - * buffered and sent to the log viewer as soon as a connection is acquired. - * This makes the logger suitable for use in conditions where you usually - * don't have a connection to a remote machine yet (early wakeup, network - * down, etc). - * - * When you call one of the public logging functions, the logger is designed - * to return to your application as fast as possible. It enqueues logs to - * send for processing by its own thread, while your application keeps running. - * - * The logger does buffer logs while not connected to a desktop - * logger. It uses Bonjour to find a logger on the local network, and can - * optionally connect to a remote logger identified by an IP address / port - * or a Host Name / port. - * - * The logger can optionally output its log to the console, like NSLog(). - * - * The logger can optionally buffer its logs to a file for which you specify the - * full path. Upon connection to the desktop viewer, the file contents are - * transmitted to the viewer prior to sending new logs. When the whole file - * content has been transmitted, it is emptied. - * - * Multiple loggers can coexist at the same time. You can perfectly use a - * logger for your debug traces, and another that connects remotely to help - * diagnostic issues while the application runs on your user's device. - * - * Using the logger's flexible packet format, you can customize logging by - * creating your own log types, and customize the desktop viewer to display - * runtime information panels for your application. - * -------------------------------------------------------------------------------- - */ - -/* Logger internal debug flags */ -// Set to 0 to disable internal debug completely -// Set to 1 to activate console logs when running the logger itself -// Set to 2 to see every logging call issued by the app, too -#define LOGGER_DEBUG 0 -#ifdef NSLog - #undef NSLog -#endif - -// Internal debugging stuff for the logger itself -#if LOGGER_DEBUG - #define LOGGERDBG LoggerDbg - #if LOGGER_DEBUG > 1 - #define LOGGERDBG2 LoggerDbg - #else - #define LOGGERDBG2(format, ...) do{}while(0) - #endif - // Internal logging function prototype - static void LoggerDbg(CFStringRef format, ...); -#else - #define LOGGERDBG(format, ...) do{}while(0) - #define LOGGERDBG2(format, ...) do{}while(0) -#endif - -/* Local prototypes */ -static void* LoggerWorkerThread(Logger *logger); -static void LoggerWriteMoreData(Logger *logger); -static void LoggerPushMessageToQueue(Logger *logger, CFDataRef message); - -// Bonjour management -static void LoggerStartBonjourBrowsing(Logger *logger); -static void LoggerStopBonjourBrowsing(Logger *logger); -static BOOL LoggerBrowseBonjourForServices(Logger *logger, CFStringRef domainName); -static void LoggerServiceBrowserCallBack(CFNetServiceBrowserRef browser, CFOptionFlags flags, CFTypeRef domainOrService, CFStreamError* error, void *info); - -// Reachability and reconnect timer -static void LoggerStartReachabilityChecking(Logger *logger); -static void LoggerStopReachabilityChecking(Logger *logger); -static void LoggerReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info); -static void LoggerTimedReconnectCallback(CFRunLoopTimerRef timer, void *info); - -// Connection & stream management -static void LoggerTryConnect(Logger *logger); -static void LoggerWriteStreamCallback(CFWriteStreamRef ws, CFStreamEventType event, void* info); -#if LOGGER_DEBUG -static void LoggerReadStreamCallback(CFReadStreamRef ws, CFStreamEventType event, void* info); -#endif - -// File buffering -static void LoggerCreateBufferWriteStream(Logger *logger); -static void LoggerCreateBufferReadStream(Logger *logger); -static void LoggerEmptyBufferFile(Logger *logger); -static void LoggerFileBufferingOptionsChanged(Logger *logger); -static void LoggerFlushQueueToBufferStream(Logger *logger, BOOL firstEntryIsClientInfo); - -// Encoding functions -static void LoggerPushClientInfoToFrontOfQueue(Logger *logger); -static void LoggerMessageAddTimestampAndThreadID(CFMutableDataRef encoder); -static void LogDataInternal(Logger *logger, NSString *domain, int level, NSData *data, int binaryOrImageType); - -static CFMutableDataRef LoggerMessageCreate(); -static void LoggerMessageUpdateDataHeader(CFMutableDataRef data); -static void LoggerMessageAddInt16(CFMutableDataRef data, int16_t anInt, int key); -static void LoggerMessageAddInt32(CFMutableDataRef data, int32_t anInt, int key); -static void LoggerMessageAddInt64(CFMutableDataRef data, int64_t anInt, int key); -static void LoggerMessageAddString(CFMutableDataRef data, CFStringRef aString, int key); -static void LoggerMessageAddData(CFMutableDataRef data, CFDataRef theData, int key, int partType); -static uint32_t LoggerMessageGetSeq(CFDataRef message); - -/* Static objects */ -static Logger* volatile sDefaultLogger = NULL; -static pthread_mutex_t sDefaultLoggerMutex = PTHREAD_MUTEX_INITIALIZER; - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Default logger -// ----------------------------------------------------------------------------- -void LoggerSetDefautLogger(Logger *defaultLogger) -{ - pthread_mutex_lock(&sDefaultLoggerMutex); - sDefaultLogger = defaultLogger; - pthread_mutex_unlock(&sDefaultLoggerMutex); -} - -Logger *LoggerGetDefaultLogger() -{ - if (sDefaultLogger == NULL) - { - pthread_mutex_lock(&sDefaultLoggerMutex); - Logger *logger = LoggerInit(); - if (sDefaultLogger == NULL) - { - sDefaultLogger = logger; - logger = NULL; - } - pthread_mutex_unlock(&sDefaultLoggerMutex); - if (logger != NULL) - LoggerStop(logger); - } - return sDefaultLogger; -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Initialization and setup -// ----------------------------------------------------------------------------- -Logger *LoggerInit() -{ - LOGGERDBG(CFSTR("LoggerInit defaultLogger=%p"), sDefaultLogger); - - Logger *logger = (Logger *)malloc(sizeof(Logger)); - bzero(logger, sizeof(Logger)); - - logger->logQueue = CFArrayCreateMutable(NULL, 32, &kCFTypeArrayCallBacks); - pthread_mutex_init(&logger->logQueueMutex, NULL); - pthread_cond_init(&logger->logQueueEmpty, NULL); - - logger->bonjourServiceBrowsers = CFArrayCreateMutable(NULL, 4, &kCFTypeArrayCallBacks); - logger->bonjourServices = CFArrayCreateMutable(NULL, 4, &kCFTypeArrayCallBacks); - - // for now we don't grow the send buffer, just use one page of memory which should be enouh - // (bigger messages will be sent separately) - logger->sendBuffer = (uint8_t *)malloc(4096); - logger->sendBufferSize = 4096; - - logger->options = LOGGER_DEFAULT_OPTIONS; - - logger->quit = NO; - - // Set this logger as the default logger is none exist already - if (!pthread_mutex_trylock(&sDefaultLoggerMutex)) - { - if (sDefaultLogger == NULL) - sDefaultLogger = logger; - pthread_mutex_unlock(&sDefaultLoggerMutex); - } - - return logger; -} - -void LoggerSetOptions(Logger *logger, uint32_t options) -{ - LOGGERDBG(CFSTR("LoggerSetOptions options=0x%08lx"), options); - - if (logger == NULL) - logger = LoggerGetDefaultLogger(); - if (logger != NULL) - logger->options = options; -} - -void LoggerSetupBonjour(Logger *logger, CFStringRef bonjourServiceType, CFStringRef bonjourServiceName) -{ - LOGGERDBG(CFSTR("LoggerSetupBonjour serviceType=%@ serviceName=%@"), bonjourServiceType, bonjourServiceName); - - if (logger == NULL) - logger = LoggerGetDefaultLogger(); - if (logger != NULL) - { - if (bonjourServiceType != NULL) - CFRetain(bonjourServiceType); - if (bonjourServiceName != NULL) - CFRetain(bonjourServiceName); - if (logger->bonjourServiceType != NULL) - CFRelease(logger->bonjourServiceType); - if (logger->bonjourServiceName != NULL) - CFRelease(logger->bonjourServiceName); - logger->bonjourServiceType = bonjourServiceType; - logger->bonjourServiceName = bonjourServiceName; - } -} - -void LoggerSetViewerHost(Logger *logger, CFStringRef hostName, UInt32 port) -{ - if (logger == NULL) - logger = LoggerGetDefaultLogger(); - if (logger == NULL) - return; - - if (logger->host != NULL) - { - CFRelease(logger->host); - logger->host = NULL; - } - if (hostName != NULL) - { - logger->host = CFStringCreateCopy(NULL, hostName); - logger->port = port; - } -} - -void LoggerSetBufferFile(Logger *logger, CFStringRef absolutePath) -{ - if (logger == NULL) - { - logger = LoggerGetDefaultLogger(); - if (logger == NULL) - return; - } - - BOOL change = ((logger->bufferFile != NULL && absolutePath == NULL) || - (logger->bufferFile == NULL && absolutePath != NULL) || - (logger->bufferFile != NULL && absolutePath != NULL && CFStringCompare(logger->bufferFile, absolutePath, 0) != kCFCompareEqualTo)); - if (change) - { - if (logger->bufferFile != NULL) - { - CFRelease(logger->bufferFile); - logger->bufferFile = NULL; - } - if (absolutePath != NULL) - logger->bufferFile = CFStringCreateCopy(NULL, absolutePath); - if (logger->bufferFileChangedSource != NULL) - CFRunLoopSourceSignal(logger->bufferFileChangedSource); - } -} - -void LoggerStart(Logger *logger) -{ - // will do nothing if logger is already started - if (logger == NULL) - logger = LoggerGetDefaultLogger(); - - if (logger->workerThread == NULL) - { - // Start the work thread which performs the Bonjour search, - // connects to the logging service and forwards the logs - LOGGERDBG(CFSTR("LoggerStart logger=%p"), logger); - pthread_create(&logger->workerThread, NULL, (void *(*)(void *))&LoggerWorkerThread, logger); - } -} - -void LoggerStop(Logger *logger) -{ - LOGGERDBG(CFSTR("LoggerStop")); - - pthread_mutex_lock(&sDefaultLoggerMutex); - if (logger == NULL || logger == sDefaultLogger) - { - logger = sDefaultLogger; - sDefaultLogger = NULL; - } - pthread_mutex_unlock(&sDefaultLoggerMutex); - - if (logger != NULL) - { - if (logger->workerThread != NULL) - { - logger->quit = YES; - pthread_join(logger->workerThread, NULL); - } - - CFRelease(logger->bonjourServiceBrowsers); - CFRelease(logger->bonjourServices); - free(logger->sendBuffer); - if (logger->host != NULL) - CFRelease(logger->host); - if (logger->bufferFile != NULL) - CFRelease(logger->bufferFile); - if (logger->bonjourServiceType != NULL) - CFRelease(logger->bonjourServiceType); - if (logger->bonjourServiceName != NULL) - CFRelease(logger->bonjourServiceName); - - // to make sure potential errors are catched, set the whole structure - // to a value that will make code crash if it tries using pointers to it. - memset(logger, 0x55, sizeof(logger)); - - free(logger); - } -} - -void LoggerFlush(Logger *logger, BOOL waitForConnection) -{ - // Special case: if nothing has ever been logged, don't bother - if (logger == NULL && sDefaultLogger == NULL) - return; - if (logger == NULL) - logger = LoggerGetDefaultLogger(); - if (logger != NULL && - pthread_self() != logger->workerThread && - (logger->connected || logger->bufferFile != NULL || waitForConnection)) - { - pthread_mutex_lock(&logger->logQueueMutex); - if (CFArrayGetCount(logger->logQueue) > 0) - pthread_cond_wait(&logger->logQueueEmpty, &logger->logQueueMutex); - pthread_mutex_unlock(&logger->logQueueMutex); - } -} - -static void LoggerDbg(CFStringRef format, ...) -{ - // Internal debugging function - // (what do you think, that we use the Logger to debug itself ??) - if (format != NULL) - { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - va_list args; - va_start(args, format); - CFStringRef s = CFStringCreateWithFormatAndArguments(NULL, NULL, (CFStringRef)format, args); - va_end(args); - if (s != NULL) - { - CFShow(s); - CFRelease(s); - } - [pool drain]; - } -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Main processing -// ----------------------------------------------------------------------------- -static void *LoggerWorkerThread(Logger *logger) -{ - LOGGERDBG(CFSTR("Start LoggerWorkerThread")); - -#if !TARGET_OS_IPHONE - // Register thread with Garbage Collector on Mac OS X if we're running an OS version that has GC - void (*registerThreadWithCollector_fn)(void); - registerThreadWithCollector_fn = (void(*)(void)) dlsym(RTLD_NEXT, "objc_registerThreadWithCollector"); - if (registerThreadWithCollector_fn) - (*registerThreadWithCollector_fn)(); -#endif - - // Create and get the runLoop for this thread - CFRunLoopRef runLoop = CFRunLoopGetCurrent(); - - // Create the run loop source that signals when messages have been added to the runloop - // this will directly trigger a WriteMoreData() call, which will or won't write depending - // on whether we're connected and there's space available in the stream - CFRunLoopSourceContext context; - bzero(&context, sizeof(context)); - context.info = logger; - context.perform = (void *)&LoggerWriteMoreData; - logger->messagePushedSource = CFRunLoopSourceCreate(NULL, 0, &context); - if (logger->messagePushedSource == NULL) - { - // Failing to create the runloop source for pushing messages is a major failure. - // This NSLog is intentional. We WANT console output in this case - NSLog(@"*** NSLogger: Worker thread failed creating runLoop source, switching to console logging."); - logger->options |= kLoggerOption_LogToConsole; - logger->workerThread = NULL; - return NULL; - } - CFRunLoopAddSource(runLoop, logger->messagePushedSource, kCFRunLoopDefaultMode); - - // Create the buffering stream if needed - if (logger->bufferFile != NULL) - LoggerCreateBufferWriteStream(logger); - - // Create the runloop source that lets us know when file buffering options change - context.perform = (void *)&LoggerFileBufferingOptionsChanged; - logger->bufferFileChangedSource = CFRunLoopSourceCreate(NULL, 0, &context); - if (logger->bufferFileChangedSource == NULL) - { - // This failure MUST be logged to console - NSLog(@"*** NSLogger Warning: failed creating a runLoop source for file buffering options change."); - } - else - CFRunLoopAddSource(runLoop, logger->bufferFileChangedSource, kCFRunLoopDefaultMode); - - // Start Bonjour browsing, wait for remote logging service to be found - if (logger->host == NULL && (logger->options & kLoggerOption_BrowseBonjour)) - { - LOGGERDBG(CFSTR("-> logger configured for Bonjour, no direct host set -- trying Bonjour first")); - LoggerStartBonjourBrowsing(logger); - } - else if (logger->host != NULL) - { - LOGGERDBG(CFSTR("-> logger configured with direct host, trying it first")); - LoggerTryConnect(logger); - } - - // Run logging thread until LoggerStop() is called - while (!logger->quit) - { - int result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, true); - if (result == kCFRunLoopRunFinished || result == kCFRunLoopRunStopped) - break; - - // Make sure we restart connection attempts if we get disconnected - if (!logger->connected && - !CFArrayGetCount(logger->bonjourServices) && - !CFArrayGetCount(logger->bonjourServiceBrowsers) && - !CFArrayGetCount(logger->bonjourServices)) - { - if (logger->options & kLoggerOption_BrowseBonjour) - LoggerStartBonjourBrowsing(logger); - else if (logger->host != NULL && logger->reachability == NULL && logger->checkHostTimer == NULL) - LoggerTryConnect(logger); - } - } - - // Cleanup - if (logger->options & kLoggerOption_BrowseBonjour) - LoggerStopBonjourBrowsing(logger); - LoggerStopReachabilityChecking(logger); - - if (logger->logStream != NULL) - { - CFWriteStreamSetClient(logger->logStream, 0, NULL, NULL); - CFWriteStreamClose(logger->logStream); - CFRelease(logger->logStream); - logger->logStream = NULL; - } - - if (logger->bufferWriteStream == NULL && logger->bufferFile != NULL) - { - // If there are messages in the queue and LoggerStop() was called and - // a buffer file was set just before LoggerStop() was called, flush - // the log queue to the buffer file - pthread_mutex_lock(&logger->logQueueMutex); - CFIndex outstandingMessages = CFArrayGetCount(logger->logQueue); - pthread_mutex_unlock(&logger->logQueueMutex); - if (outstandingMessages) - LoggerCreateBufferWriteStream(logger); - } - - if (logger->bufferWriteStream != NULL) - { - CFWriteStreamClose(logger->bufferWriteStream); - CFRelease(logger->bufferWriteStream); - logger->bufferWriteStream = NULL; - } - - if (logger->messagePushedSource != NULL) - { - CFRunLoopSourceInvalidate(logger->messagePushedSource); - CFRelease(logger->messagePushedSource); - logger->messagePushedSource = NULL; - } - - if (logger->bufferFileChangedSource != NULL) - { - CFRunLoopSourceInvalidate(logger->bufferFileChangedSource); - CFRelease(logger->bufferFileChangedSource); - logger->bufferFileChangedSource = NULL; - } - - // if the client ever tries to log again against us, make sure that logs at least - // go to console - logger->options |= kLoggerOption_LogToConsole; - logger->workerThread = NULL; - return NULL; -} - -static CFStringRef LoggerCreateStringRepresentationFromBinaryData(CFDataRef data) -{ - CFMutableStringRef s = CFStringCreateMutable(NULL, 0); - unsigned int offset = 0; - unsigned int dataLen = (unsigned int)CFDataGetLength(data); - char buffer[1+6+16*3+1+16+1+1+1]; - buffer[0] = '\0'; - const unsigned char *q = (unsigned char *)CFDataGetBytePtr(data); - if (dataLen == 1) - CFStringAppend(s, CFSTR("Raw data, 1 byte:\n")); - else - CFStringAppendFormat(s, NULL, CFSTR("Raw data, %u bytes:\n"), dataLen); - while (dataLen) - { - int i, j, b = sprintf(buffer," %04x: ", offset); - for (i=0; i < 16 && i < (int)dataLen; i++) - sprintf(&buffer[b+3*i], "%02x ", (int)q[i]); - for (j=i; j < 16; j++) - strcat(buffer, " "); - - b = strlen(buffer); - buffer[b++] = '\''; - for (i=0; i < 16 && i < (int)dataLen; i++, q++) - { - if (*q >= 32 && *q < 128) - buffer[b++] = *q; - else - buffer[b++] = ' '; - } - for (j=i; j < 16; j++) - buffer[b++] = ' '; - buffer[b++] = '\''; - buffer[b++] = '\n'; - buffer[b] = 0; - - CFStringRef bufferStr = CFStringCreateWithBytesNoCopy(NULL, (const UInt8 *)buffer, strlen(buffer), kCFStringEncodingISOLatin1, false, kCFAllocatorNull); - CFStringAppend(s, bufferStr); - CFRelease(bufferStr); - - dataLen -= i; - offset += i; - } - return s; -} - -static void LoggerLogToConsole(CFDataRef data) -{ - // Decode and log a message to the console. Doing this from the worker thread - // allow us to serialize logging, which is a benefit that NSLog() doesn't have. - // Only drawback is that we have to decode our own message, but that is a minor hassle. - - struct timeval timestamp; - bzero(×tamp, sizeof(timestamp)); - int type = LOGMSG_TYPE_LOG, contentsType = PART_TYPE_STRING; - int imgWidth=0, imgHeight=0; - CFStringRef message = NULL; - CFStringRef thread = NULL; - - // decode message contents - uint8_t *p = (uint8_t *)CFDataGetBytePtr(data) + 4; - uint16_t partCount; - memcpy(&partCount, p, 2); - partCount = ntohs(partCount); - p += 2; - while (partCount--) - { - uint8_t partKey = *p++; - uint8_t partType = *p++; - uint32_t partSize; - if (partType == PART_TYPE_INT16) - partSize = 2; - else if (partType == PART_TYPE_INT32) - partSize = 4; - else if (partType == PART_TYPE_INT64) - partSize = 8; - else - { - memcpy(&partSize, p, 4); - p += 4; - partSize = ntohl(partSize); - } - CFTypeRef part = NULL; - uint32_t value32 = 0; - uint64_t value64 = 0; - if (partSize > 0) - { - if (partType == PART_TYPE_STRING) - { - // trim whitespace and newline at both ends of the string - uint8_t *q = p; - uint32_t l = partSize; - while (l && (*q == ' ' || *q == '\t' || *q == '\n' || *q == '\r')) - q++, l--; - uint8_t *r = q + l - 1; - while (l && (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r')) - r--, l--; - part = CFStringCreateWithBytesNoCopy(NULL, q, l, kCFStringEncodingUTF8, false, kCFAllocatorNull); - } - else if (partType == PART_TYPE_BINARY) - { - part = CFDataCreateWithBytesNoCopy(NULL, p, partSize, kCFAllocatorNull); - } - else if (partType == PART_TYPE_IMAGE) - { - // ignore image data, we can't log it to console - } - else if (partType == PART_TYPE_INT32) - { - memcpy(&value32, p, 4); - value32 = ntohl(value32); - } - else if (partType == PART_TYPE_INT64) - { - memcpy(&value64, p, 8); - value64 = CFSwapInt64BigToHost(value64); - } - p += partSize; - } - switch (partKey) - { - case PART_KEY_MESSAGE_TYPE: - type = (int)value32; - break; - case PART_KEY_TIMESTAMP_S: // timestamp with seconds-level resolution - timestamp.tv_sec = (partType == PART_TYPE_INT64) ? (__darwin_time_t)value64 : (__darwin_time_t)value32; - break; - case PART_KEY_TIMESTAMP_MS: // millisecond part of the timestamp (optional) - timestamp.tv_usec = ((partType == PART_TYPE_INT64) ? (__darwin_suseconds_t)value64 : (__darwin_suseconds_t)value32) * 1000; - break; - case PART_KEY_TIMESTAMP_US: // microsecond part of the timestamp (optional) - timestamp.tv_usec = (partType == PART_TYPE_INT64) ? (__darwin_suseconds_t)value64 : (__darwin_suseconds_t)value32; - break; - case PART_KEY_THREAD_ID: - if (thread == NULL) // useless test, we know what we're doing but clang analyzer doesn't... - { - if (partType == PART_TYPE_INT32) - thread = CFStringCreateWithFormat(NULL, NULL, CFSTR("thread 0x%08x"), value32); - else if (partType == PART_TYPE_INT64) - thread = CFStringCreateWithFormat(NULL, NULL, CFSTR("thread 0x%qx"), value64); - else if (partType == PART_TYPE_STRING && part != NULL) - thread = CFRetain(part); - } - break; - case PART_KEY_MESSAGE: - if (part != NULL) - { - if (partType == PART_TYPE_STRING) - message = CFRetain(part); - else if (partType == PART_TYPE_BINARY) - message = LoggerCreateStringRepresentationFromBinaryData(part); - } - contentsType = partType; - break; - case PART_KEY_IMAGE_WIDTH: - imgWidth = (partType == PART_TYPE_INT32 ? (int)value32 : (int)value64); - break; - case PART_KEY_IMAGE_HEIGHT: - imgHeight = (partType == PART_TYPE_INT32 ? (int)value32 : (int)value64); - break; - default: - break; - } - if (part != NULL) - CFRelease(part); - } - - // Prepare the final representation and log to console - CFMutableStringRef s = CFStringCreateMutable(NULL, 0); - - char buf[32]; - struct tm t; - gmtime_r(×tamp.tv_sec, &t); - strftime(buf, sizeof(buf)-1, "%T", &t); - CFStringRef ts = CFStringCreateWithBytesNoCopy(NULL, (const UInt8 *)buf, strlen(buf), kCFStringEncodingASCII, false, kCFAllocatorNull); - CFStringAppend(s, ts); - CFRelease(ts); - - if (contentsType == PART_TYPE_IMAGE) - message = CFStringCreateWithFormat(NULL, NULL, CFSTR(""), imgWidth, imgHeight); - - char threadNamePadding[16]; - threadNamePadding[0] = 0; - if (CFStringGetLength(thread) < 16) - { - int n = 16 - CFStringGetLength(thread); - memset(threadNamePadding, ' ', n); - threadNamePadding[n] = 0; - } - CFStringAppendFormat(s, NULL, CFSTR(".%04d %s%@ | %@"), - (int)(timestamp.tv_usec / 1000), - threadNamePadding, thread, - message ? message : CFSTR("")); - - if (thread != NULL) - CFRelease(thread); - if (message) - CFRelease(message); - - if (type == LOGMSG_TYPE_LOG) - CFShow(s); - - CFRelease(s); -} - -static void LoggerWriteMoreData(Logger *logger) -{ - if (!logger->connected) - { - if (logger->options & kLoggerOption_LogToConsole) - { - pthread_mutex_lock(&logger->logQueueMutex); - while (CFArrayGetCount(logger->logQueue)) - { - LoggerLogToConsole((CFDataRef)CFArrayGetValueAtIndex(logger->logQueue, 0)); - CFArrayRemoveValueAtIndex(logger->logQueue, 0); - } - pthread_mutex_unlock(&logger->logQueueMutex); - pthread_cond_broadcast(&logger->logQueueEmpty); - } - else if (logger->bufferWriteStream != NULL) - { - LoggerFlushQueueToBufferStream(logger, NO); - } - return; - } - - if (CFWriteStreamCanAcceptBytes(logger->logStream)) - { - // prepare archived data with log queue contents, unblock the queue as soon as possible - CFMutableDataRef sendFirstItem = NULL; - if (logger->sendBufferUsed == 0) - { - // pull more data from the log queue - if (logger->bufferReadStream != NULL) - { - if (!CFReadStreamHasBytesAvailable(logger->bufferReadStream)) - { - CFReadStreamClose(logger->bufferReadStream); - CFRelease(logger->bufferReadStream); - logger->bufferReadStream = NULL; - LoggerEmptyBufferFile(logger); - } - else - { - logger->sendBufferUsed = CFReadStreamRead(logger->bufferReadStream, logger->sendBuffer, logger->sendBufferSize); - } - } - else - { - pthread_mutex_lock(&logger->logQueueMutex); - while (CFArrayGetCount(logger->logQueue)) - { - CFDataRef d = (CFDataRef)CFArrayGetValueAtIndex(logger->logQueue, 0); - CFIndex dsize = CFDataGetLength(d); - if ((logger->sendBufferUsed + dsize) > logger->sendBufferSize) - break; - memcpy(logger->sendBuffer + logger->sendBufferUsed, CFDataGetBytePtr(d), dsize); - logger->sendBufferUsed += dsize; - CFArrayRemoveValueAtIndex(logger->logQueue, 0); - logger->incompleteSendOfFirstItem = NO; - } - pthread_mutex_unlock(&logger->logQueueMutex); - } - if (logger->sendBufferUsed == 0) - { - // are we done yet? - pthread_mutex_lock(&logger->logQueueMutex); - if (CFArrayGetCount(logger->logQueue) == 0) - { - pthread_mutex_unlock(&logger->logQueueMutex); - pthread_cond_broadcast(&logger->logQueueEmpty); - return; - } - - // first item is too big to fit in a single packet, send it separately - sendFirstItem = (CFMutableDataRef)CFArrayGetValueAtIndex(logger->logQueue, 0); - logger->incompleteSendOfFirstItem = YES; - pthread_mutex_unlock(&logger->logQueueMutex); - logger->sendBufferOffset = 0; - } - } - - // send data over the socket. We try hard to be failsafe and if we have to send - // data in fragments, we make sure that in case a disconnect occurs we restart - // sending the whole message(s) - if (logger->sendBufferUsed != 0) - { - CFIndex written = CFWriteStreamWrite(logger->logStream, - logger->sendBuffer + logger->sendBufferOffset, - logger->sendBufferUsed - logger->sendBufferOffset); - if (written < 0) - { - // We'll get an event if the stream closes on error. Don't discard the data, - // it will be sent as soon as a connection is re-acquired. - return; - } - if ((logger->sendBufferOffset + written) < logger->sendBufferUsed) - { - // everything couldn't be sent at once - logger->sendBufferOffset += written; - } - else - { - logger->sendBufferUsed = 0; - logger->sendBufferOffset = 0; - } - } - else if (sendFirstItem) - { - CFIndex length = CFDataGetLength(sendFirstItem) - logger->sendBufferOffset; - CFIndex written = CFWriteStreamWrite(logger->logStream, - CFDataGetBytePtr(sendFirstItem) + logger->sendBufferOffset, - length); - if (written < 0) - { - // We'll get an event if the stream closes on error - return; - } - if (written < length) - { - // The output pipe is full, and the first item has not been sent completely - // We need to reduce the remaining data on the first item so it can be taken - // care of at the next iteration. We take advantage of the fact that each item - // in the queue is actually a mutable data block - // @@@ NOTE: IF WE GET DISCONNECTED WHILE DOING THIS, THINGS WILL GO WRONG - // NEED TO UPDATE THIS LOGIC - CFDataReplaceBytes((CFMutableDataRef)sendFirstItem, CFRangeMake(0, written), NULL, 0); - return; - } - - // we are done sending the first item in the queue, remove it now - pthread_mutex_lock(&logger->logQueueMutex); - CFArrayRemoveValueAtIndex(logger->logQueue, 0); - logger->incompleteSendOfFirstItem = NO; - pthread_mutex_unlock(&logger->logQueueMutex); - logger->sendBufferOffset = 0; - } - } -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark File buffering functions -// ----------------------------------------------------------------------------- -static void LoggerCreateBufferWriteStream(Logger *logger) -{ - LOGGERDBG(CFSTR("LoggerCreateBufferWriteStream to file %@"), logger->bufferFile); - CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, logger->bufferFile, kCFURLPOSIXPathStyle, false); - if (fileURL != NULL) - { - // Create write stream to file - logger->bufferWriteStream = CFWriteStreamCreateWithFile(NULL, fileURL); - CFRelease(fileURL); - if (logger->bufferWriteStream != NULL) - { - // Set flag to append new data to buffer file - CFWriteStreamSetProperty(logger->bufferWriteStream, kCFStreamPropertyAppendToFile, kCFBooleanTrue); - - // Open the buffer stream for writing - if (!CFWriteStreamOpen(logger->bufferWriteStream)) - { - CFRelease(logger->bufferWriteStream); - logger->bufferWriteStream = NULL; - } - else - { - // Write client info and flush the queue contents to buffer file - LoggerPushClientInfoToFrontOfQueue(logger); - LoggerFlushQueueToBufferStream(logger, YES); - } - } - } - if (logger->bufferWriteStream == NULL) - { - CFShow(CFSTR("NSLogger Warning: failed opening buffer file for writing:")); - CFShow(logger->bufferFile); - } -} - -static void LoggerCreateBufferReadStream(Logger *logger) -{ - LOGGERDBG(CFSTR("LoggerCreateBufferReadStream from file %@"), logger->bufferFile); - CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, logger->bufferFile, kCFURLPOSIXPathStyle, false); - if (fileURL != NULL) - { - // Create read stream from file - logger->bufferReadStream = CFReadStreamCreateWithFile(NULL, fileURL); - CFRelease(fileURL); - if (logger->bufferReadStream != NULL) - { - if (!CFReadStreamOpen(logger->bufferReadStream)) - { - CFRelease(logger->bufferReadStream); - logger->bufferReadStream = NULL; - } - } - } -} - -static void LoggerEmptyBufferFile(Logger *logger) -{ - // completely remove the buffer file from storage - LOGGERDBG(CFSTR("LoggerEmptyBufferFile %@"), logger->bufferFile); - if (logger->bufferFile != NULL) - { - CFIndex bufferSize = 1 + CFStringGetLength(logger->bufferFile) * 3; - char *buffer = (char *)malloc(bufferSize); - if (buffer != NULL) - { - if (CFStringGetFileSystemRepresentation(logger->bufferFile, buffer, bufferSize)) - { - // remove file - unlink(buffer); - } - free(buffer); - } - } -} - -static void LoggerFileBufferingOptionsChanged(Logger *logger) -{ - // File buffering options changed: - // - close the current buffer file stream, if any - // - create a new one, if needed - LOGGERDBG(CFSTR("LoggerFileBufferingOptionsChanged bufferFile=%@"), logger->bufferFile); - if (logger->bufferWriteStream != NULL) - { - CFWriteStreamClose(logger->bufferWriteStream); - CFRelease(logger->bufferWriteStream); - logger->bufferWriteStream = NULL; - } - if (logger->bufferFile != NULL) - LoggerCreateBufferWriteStream(logger); -} - -static void LoggerFlushQueueToBufferStream(Logger *logger, BOOL firstEntryIsClientInfo) -{ - LOGGERDBG(CFSTR("LoggerFlushQueueToBufferStream")); - pthread_mutex_lock(&logger->logQueueMutex); - if (logger->incompleteSendOfFirstItem) - { - // drop anything being sent - logger->sendBufferUsed = 0; - logger->sendBufferOffset = 0; - } - logger->incompleteSendOfFirstItem = NO; - - // Write outstanding messages to the buffer file (streams don't detect disconnection - // until the next write, where we could lose one or more messages) - if (!firstEntryIsClientInfo && logger->sendBufferUsed) - CFWriteStreamWrite(logger->bufferWriteStream, logger->sendBuffer + logger->sendBufferOffset, logger->sendBufferUsed - logger->sendBufferOffset); - - int n = 0; - while (CFArrayGetCount(logger->logQueue)) - { - CFDataRef data = CFArrayGetValueAtIndex(logger->logQueue, 0); - CFIndex dataLength = CFDataGetLength(data); - CFIndex written = CFWriteStreamWrite(logger->bufferWriteStream, CFDataGetBytePtr(data), dataLength); - if (written != dataLength) - { - // couldn't write all data to file, maybe storage run out of space? - CFShow(CFSTR("NSLogger Error: failed flushing the whole queue to buffer file:")); - CFShow(logger->bufferFile); - break; - } - CFArrayRemoveValueAtIndex(logger->logQueue, 0); - if (n == 0 && firstEntryIsClientInfo && logger->sendBufferUsed) - { - // try hard: write any outstanding messages to the buffer file, after the client info - CFWriteStreamWrite(logger->bufferWriteStream, logger->sendBuffer + logger->sendBufferOffset, logger->sendBufferUsed - logger->sendBufferOffset); - } - n++; - } - logger->sendBufferUsed = 0; - logger->sendBufferOffset = 0; - pthread_mutex_unlock(&logger->logQueueMutex); -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Bonjour browsing -// ----------------------------------------------------------------------------- -static void LoggerStartBonjourBrowsing(Logger *logger) -{ - LOGGERDBG(CFSTR("LoggerStartBonjourBrowsing")); - - if (logger->options & kLoggerOption_BrowseOnlyLocalDomain) - { - LOGGERDBG(CFSTR("Logger configured to search only the local domain, searching for services on: local.")); - if (!LoggerBrowseBonjourForServices(logger, CFSTR("local.")) && logger->host == NULL) - { - LOGGERDBG(CFSTR("*** Logger: could not browse for services in domain local., no remote host configured: reverting to console logging. ***")); - logger->options |= kLoggerOption_LogToConsole; - } - } - else - { - LOGGERDBG(CFSTR("Logger configured to search all domains, browsing for domains first")); - CFNetServiceClientContext context = {0, (void *)logger, NULL, NULL, NULL}; - CFRunLoopRef runLoop = CFRunLoopGetCurrent(); - logger->bonjourDomainBrowser = CFNetServiceBrowserCreate(NULL, &LoggerServiceBrowserCallBack, &context); - CFNetServiceBrowserScheduleWithRunLoop(logger->bonjourDomainBrowser, runLoop, kCFRunLoopCommonModes); - if (!CFNetServiceBrowserSearchForDomains(logger->bonjourDomainBrowser, false, NULL)) - { - // An error occurred, revert to console logging if there is no remote host - LOGGERDBG(CFSTR("*** Logger: could not browse for domains, reverting to console logging. ***")); - CFNetServiceBrowserUnscheduleFromRunLoop(logger->bonjourDomainBrowser, runLoop, kCFRunLoopCommonModes); - CFRelease(logger->bonjourDomainBrowser); - logger->bonjourDomainBrowser = NULL; - if (logger->host == NULL) - logger->options |= kLoggerOption_LogToConsole; - } - } -} - -static void LoggerStopBonjourBrowsing(Logger *logger) -{ - LOGGERDBG(CFSTR("LoggerStopBonjourBrowsing")); - - // stop browsing for domains - if (logger->bonjourDomainBrowser != NULL) - { - CFNetServiceBrowserStopSearch(logger->bonjourDomainBrowser, NULL); - CFNetServiceBrowserUnscheduleFromRunLoop(logger->bonjourDomainBrowser, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - CFNetServiceBrowserInvalidate(logger->bonjourDomainBrowser); - CFRelease(logger->bonjourDomainBrowser); - logger->bonjourDomainBrowser = NULL; - } - - // stop browsing for services - CFIndex idx; - for (idx = 0; idx < CFArrayGetCount(logger->bonjourServiceBrowsers); idx++) - { - CFNetServiceBrowserRef browser = (CFNetServiceBrowserRef)CFArrayGetValueAtIndex(logger->bonjourServiceBrowsers, idx); - CFNetServiceBrowserStopSearch(browser, NULL); - CFNetServiceBrowserUnscheduleFromRunLoop(browser, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - CFNetServiceBrowserInvalidate(browser); - } - CFArrayRemoveAllValues(logger->bonjourServiceBrowsers); - - // Forget all services - CFArrayRemoveAllValues(logger->bonjourServices); -} - -static BOOL LoggerBrowseBonjourForServices(Logger *logger, CFStringRef domainName) -{ - BOOL result = NO; - CFNetServiceClientContext context = {0, (void *)logger, NULL, NULL, NULL}; - CFRunLoopRef runLoop = CFRunLoopGetCurrent(); - - CFNetServiceBrowserRef browser = CFNetServiceBrowserCreate(NULL, (CFNetServiceBrowserClientCallBack)&LoggerServiceBrowserCallBack, &context); - CFNetServiceBrowserScheduleWithRunLoop(browser, runLoop, kCFRunLoopCommonModes); - CFStreamError error; - - // try to use the user-specfied service type if any, fallback on our - // default service type - CFStringRef serviceType = logger->bonjourServiceType; - if (serviceType == NULL) - { - if (logger->options & kLoggerOption_UseSSL) - serviceType = LOGGER_SERVICE_TYPE_SSL; - else - serviceType = LOGGER_SERVICE_TYPE; - } - if (!CFNetServiceBrowserSearchForServices(browser, domainName, serviceType, &error)) - { - LOGGERDBG(CFSTR("Logger can't start search on domain: %@ (error %d)"), domainName, error.error); - CFNetServiceBrowserUnscheduleFromRunLoop(browser, runLoop, kCFRunLoopCommonModes); - CFNetServiceBrowserInvalidate(browser); - } - else - { - LOGGERDBG(CFSTR("Logger started search for services of type %@ in domain %@"), serviceType, domainName); - CFArrayAppendValue(logger->bonjourServiceBrowsers, browser); - result = YES; - } - CFRelease(browser); - return result; -} - -static void LoggerServiceBrowserCallBack (CFNetServiceBrowserRef browser, - CFOptionFlags flags, - CFTypeRef domainOrService, - CFStreamError* error, - void* info) -{ - LOGGERDBG(CFSTR("LoggerServiceBrowserCallback browser=%@ flags=0x%04x domainOrService=%@ error=%d"), browser, flags, domainOrService, error==NULL ? 0 : error->error); - - Logger *logger = (Logger *)info; - assert(logger != NULL); - - if (flags & kCFNetServiceFlagRemove) - { - if (!(flags & kCFNetServiceFlagIsDomain)) - { - CFNetServiceRef service = (CFNetServiceRef)domainOrService; - CFIndex idx; - for (idx = 0; idx < CFArrayGetCount(logger->bonjourServices); idx++) - { - if (CFArrayGetValueAtIndex(logger->bonjourServices, idx) == service) - { - CFNetServiceUnscheduleFromRunLoop(service, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - CFNetServiceClientContext context = {0, NULL, NULL, NULL, NULL}; - CFNetServiceSetClient(service, NULL, &context); - CFNetServiceCancel(service); - CFArrayRemoveValueAtIndex(logger->bonjourServices, idx); - break; - } - } - } - } - else - { - if (flags & kCFNetServiceFlagIsDomain) - { - // start searching for services in this domain - LoggerBrowseBonjourForServices(logger, (CFStringRef)domainOrService); - } - else - { - // a service has been found - LOGGERDBG(CFSTR("Logger found service: %@"), domainOrService); - CFNetServiceRef service = (CFNetServiceRef)domainOrService; - if (service != NULL) - { - // if the user has specified that Logger shall only connect to the specified - // Bonjour service name, check it now. This makes things easier in a teamwork - // environment where multiple instances of NSLogger viewer may run on the - // same network - if (logger->bonjourServiceName != NULL) - { - LOGGERDBG(CFSTR("-> looking for services of name %@"), logger->bonjourServiceName); - CFStringRef name = CFNetServiceGetName(service); - if (name == NULL || kCFCompareEqualTo != CFStringCompare(name, logger->bonjourServiceName, kCFCompareCaseInsensitive | kCFCompareDiacriticInsensitive)) - { - LOGGERDBG(CFSTR("-> service name %@ does not match requested service name, ignoring."), name, logger->bonjourServiceName); - return; - } - } - CFArrayAppendValue(logger->bonjourServices, service); - LoggerTryConnect(logger); - } - } - } -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Reachability -// ----------------------------------------------------------------------------- -static void LoggerStartReachabilityChecking(Logger *logger) -{ - if (logger->host != NULL && logger->reachability == NULL) - { - LOGGERDBG(CFSTR("Starting SCNetworkReachability to wait for host %@ to be reachable"), logger->host); - - CFIndex length = CFStringGetLength(logger->host) * 3; - char *buffer = (char *)malloc(length + 1); - CFStringGetBytes(logger->host, CFRangeMake(0, CFStringGetLength(logger->host)), kCFStringEncodingUTF8, '?', false, (UInt8 *)buffer, length, &length); - buffer[length] = 0; - - logger->reachability = SCNetworkReachabilityCreateWithName(NULL, buffer); - - SCNetworkReachabilityContext context = {0, logger, NULL, NULL, NULL}; - SCNetworkReachabilitySetCallback(logger->reachability, &LoggerReachabilityCallBack, &context); - SCNetworkReachabilityScheduleWithRunLoop(logger->reachability, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - - free(buffer); - - // Also start a timer that will try to reconnect every N seconds - if (logger->checkHostTimer == NULL) - { - CFRunLoopTimerContext timerContext = { - .version = 0, - .info = logger, - .retain = NULL, - .release = NULL, - .copyDescription = NULL - }; - logger->checkHostTimer = CFRunLoopTimerCreate(NULL, - CFAbsoluteTimeGetCurrent() + 5, - 5, // reconnect interval - 0, - 0, - &LoggerTimedReconnectCallback, - &timerContext); - if (logger->checkHostTimer != NULL) - { - LOGGERDBG(CFSTR("Starting the TimedReconnect timer to regularly retry the connection")); - CFRunLoopAddTimer(CFRunLoopGetCurrent(), logger->checkHostTimer, kCFRunLoopCommonModes); - } - } - } -} - -static void LoggerStopReachabilityChecking(Logger *logger) -{ - if (logger->reachability != NULL) - { - LOGGERDBG(CFSTR("Stopping SCNetworkReachability")); - SCNetworkReachabilityUnscheduleFromRunLoop(logger->reachability, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - CFRelease(logger->reachability); - logger->reachability = NULL; - } - if (logger->checkHostTimer != NULL) - { - CFRunLoopTimerInvalidate(logger->checkHostTimer); - CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), logger->checkHostTimer, kCFRunLoopCommonModes); - CFRelease(logger->checkHostTimer); - logger->checkHostTimer = NULL; - } -} - -static void LoggerReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) -{ - Logger *logger = (Logger *)info; - assert(logger != NULL); - LOGGERDBG(CFSTR("LoggerReachabilityCallBack called with flags=0x%08lx"), flags); - if (flags & kSCNetworkReachabilityFlagsReachable) - { - // target host became reachable. If we have not other open connection, - // try direct connection to the host - if (logger->logStream == NULL && logger->host != NULL) - { - LOGGERDBG(CFSTR("-> host %@ became reachable, trying to connect."), logger->host); - LoggerTryConnect(logger); - } - } -} - -static void LoggerTimedReconnectCallback(CFRunLoopTimerRef timer, void *info) -{ - Logger *logger = (Logger *)info; - assert(logger != NULL); - LOGGERDBG(CFSTR("LoggerTimedReconnectCallback")); - if (logger->logStream == NULL && logger->host != NULL) - { - LOGGERDBG(CFSTR("-> trying to reconnect to host %@"), logger->host); - LoggerTryConnect(logger); - } - else - { - LOGGERDBG(CFSTR("-> timer not needed anymore, removing it form runloop")); - CFRunLoopTimerInvalidate(timer); - CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), logger->checkHostTimer, kCFRunLoopCommonModes); - CFRelease(timer); - logger->checkHostTimer = NULL; - } -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Stream management -// ----------------------------------------------------------------------------- -static BOOL LoggerConfigureAndOpenStream(Logger *logger) -{ - // configure and open stream - LOGGERDBG(CFSTR("LoggerConfigureAndOpenStream configuring and opening log stream")); - CFStreamClientContext context = {0, (void *)logger, NULL, NULL, NULL}; - if (CFWriteStreamSetClient(logger->logStream, - (kCFStreamEventOpenCompleted | - kCFStreamEventCanAcceptBytes | - kCFStreamEventErrorOccurred | - kCFStreamEventEndEncountered), - &LoggerWriteStreamCallback, - &context)) - { - if (logger->options & kLoggerOption_UseSSL) - { - // Configure stream to require a SSL connection - LOGGERDBG(CFSTR("-> configuring SSL")); - const void *SSLKeys[] = { - kCFStreamSSLLevel, - kCFStreamSSLValidatesCertificateChain, - kCFStreamSSLIsServer, - kCFStreamSSLPeerName - }; - const void *SSLValues[] = { - kCFStreamSocketSecurityLevelNegotiatedSSL, - kCFBooleanFalse, // no certificate chain validation (we use a self-signed certificate) - kCFBooleanFalse, // not a server - kCFNull - }; - CFDictionaryRef SSLDict = CFDictionaryCreate(NULL, SSLKeys, SSLValues, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFWriteStreamSetProperty(logger->logStream, kCFStreamPropertySSLSettings, SSLDict); - CFRelease(SSLDict); - } - - CFWriteStreamScheduleWithRunLoop(logger->logStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - - if (CFWriteStreamOpen(logger->logStream)) - { - LOGGERDBG(CFSTR("-> stream open attempt, waiting for open completion")); - return YES; - } - - LOGGERDBG(CFSTR("-> stream open failed.")); - - CFWriteStreamSetClient(logger->logStream, kCFStreamEventNone, NULL, NULL); - if (CFWriteStreamGetStatus(logger->logStream) == kCFStreamStatusOpen) - CFWriteStreamClose(logger->logStream); - CFWriteStreamUnscheduleFromRunLoop(logger->logStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - } - else - { - LOGGERDBG(CFSTR("-> stream set client failed.")); - } - CFRelease(logger->logStream); - logger->logStream = NULL; - return NO; -} - -static void LoggerTryConnect(Logger *logger) -{ - // Try connecting to the next address in the sConnectAttempts array - LOGGERDBG(CFSTR("LoggerTryConnect, %d services registered, current stream=%@"), CFArrayGetCount(logger->bonjourServices), logger->logStream); - - // If we already have a connection established or being attempted, stop here - if (logger->logStream != NULL) - { - LOGGERDBG(CFSTR("-> another connection is opened or in progress, giving up for now")); - return; - } - - // If there are discovered Bonjour services, try them now - while (CFArrayGetCount(logger->bonjourServices)) - { - CFNetServiceRef service = (CFNetServiceRef)CFArrayGetValueAtIndex(logger->bonjourServices, 0); - LOGGERDBG(CFSTR("-> Trying to open write stream to service %@"), service); - CFStreamCreatePairWithSocketToNetService(NULL, service, NULL, &logger->logStream); - CFArrayRemoveValueAtIndex(logger->bonjourServices, 0); - if (logger->logStream == NULL) - { - // create pair failed - LOGGERDBG(CFSTR("-> failed.")); - } - else if (LoggerConfigureAndOpenStream(logger)) - { - // open is now in progress - return; - } - } - - // If there is a host to directly connect to, try it now (this will happen before - // Bonjour kicks in, Bonjour being handled as a fallback solution if direct Host - // fails) - if (logger->host != NULL) - { - LOGGERDBG(CFSTR("-> Trying to open direct connection to host %@ port %u"), logger->host, logger->port); - CFStreamCreatePairWithSocketToHost(NULL, logger->host, logger->port, NULL, &logger->logStream); - if (logger->logStream == NULL) - { - // Create stream failed - LOGGERDBG(CFSTR("-> failed.")); - if (logger->logStream != NULL) - { - CFRelease(logger->logStream); - logger->logStream = NULL; - } - } - else if (LoggerConfigureAndOpenStream(logger)) - { - // open is now in progress - return; - } - - // Could not connect to host: start Reachability so we know when target host becomes reachable - // and can try to connect again - LoggerStartReachabilityChecking(logger); - } - - // Finally, if Bonjour is enabled and not started yet, start it now. - if ((logger->options & kLoggerOption_BrowseBonjour) && - (logger->bonjourDomainBrowser == NULL || CFArrayGetCount(logger->bonjourServiceBrowsers) == 0)) - { - LoggerStartBonjourBrowsing(logger); - } -} - -static void LoggerWriteStreamCallback(CFWriteStreamRef ws, CFStreamEventType event, void* info) -{ - Logger *logger = (Logger *)info; - assert(ws == logger->logStream); - switch (event) - { - case kCFStreamEventOpenCompleted: - // A stream open was complete. Cancel all bonjour browsing, - // service resolution and connection attempts, and try to - // write existing buffer contents - LOGGERDBG(CFSTR("Logger CONNECTED")); - logger->connected = YES; - LoggerStopBonjourBrowsing(logger); - LoggerStopReachabilityChecking(logger); - if (logger->bufferWriteStream != NULL) - { - // now that a connection is acquired, we can stop logging to a file - CFWriteStreamClose(logger->bufferWriteStream); - CFRelease(logger->bufferWriteStream); - logger->bufferWriteStream = NULL; - } - if (logger->bufferFile != NULL) - { - // if a buffer file was defined, try to read its contents - LoggerCreateBufferReadStream(logger); - } - LoggerPushClientInfoToFrontOfQueue(logger); - LoggerWriteMoreData(logger); - break; - - case kCFStreamEventCanAcceptBytes: - LoggerWriteMoreData(logger); - break; - - case kCFStreamEventErrorOccurred: { - CFErrorRef error = CFWriteStreamCopyError(ws); - LOGGERDBG(CFSTR("Logger stream error: %@"), error); - CFRelease(error); - // Fall-thru - } - - case kCFStreamEventEndEncountered: - if (logger->connected) - { - LOGGERDBG(CFSTR("Logger DISCONNECTED")); - logger->connected = NO; - } - CFWriteStreamSetClient(logger->logStream, 0, NULL, NULL); - CFWriteStreamUnscheduleFromRunLoop(logger->logStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - CFWriteStreamClose(logger->logStream); - - CFRelease(logger->logStream); - logger->logStream = NULL; - - if (logger->bufferReadStream != NULL) - { - // In the case the connection drops before we have flushed the - // whole contents of the file, we choose to keep it integrally - // and retransmit it when reconnecting to the viewer. The reason - // of this choice is that we may have transmitted only part of - // a message, and this may cause errors on the desktop side. - CFReadStreamClose(logger->bufferReadStream); - CFRelease(logger->bufferReadStream); - logger->bufferReadStream = NULL; - } - if (logger->bufferFile != NULL && logger->bufferWriteStream == NULL) - LoggerCreateBufferWriteStream(logger); - - if (logger->host != NULL && !(logger->options & kLoggerOption_BrowseBonjour)) - LoggerStartReachabilityChecking(logger); - else - LoggerTryConnect(logger); - break; - } -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Internal encoding functions -// ----------------------------------------------------------------------------- -static void LoggerMessageAddTimestamp(CFMutableDataRef encoder) -{ - struct timeval t; - if (gettimeofday(&t, NULL) == 0) - { -#if __LP64__ - LoggerMessageAddInt64(encoder, t.tv_sec, PART_KEY_TIMESTAMP_S); - LoggerMessageAddInt64(encoder, t.tv_usec, PART_KEY_TIMESTAMP_US); -#else - LoggerMessageAddInt32(encoder, t.tv_sec, PART_KEY_TIMESTAMP_S); - LoggerMessageAddInt32(encoder, t.tv_usec, PART_KEY_TIMESTAMP_US); -#endif - } - else - { - time_t ts = time(NULL); -#if __LP64__ - LoggerMessageAddInt64(encoder, ts, PART_KEY_TIMESTAMP_S); -#else - LoggerMessageAddInt32(encoder, ts, PART_KEY_TIMESTAMP_S); -#endif - } -} - -static void LoggerMessageAddTimestampAndThreadID(CFMutableDataRef encoder) -{ - LoggerMessageAddTimestamp(encoder); - - BOOL hasThreadName = NO; -#if ALLOW_COCOA_USE - // Getting the thread number is tedious, to say the least. Since there is - // no direct way to get it, we have to do it sideways. Note that it can be dangerous - // to use any Cocoa call when in a multithreaded application that only uses non-Cocoa threads - // and for which Cocoa's multithreading has not been activated. We test for this case. - if ([NSThread isMultiThreaded] || [NSThread isMainThread]) - { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSThread *thread = [NSThread currentThread]; - NSString *name = [thread name]; - if (name == nil) - { - if ([thread isMainThread]) - name = @"Main thread"; - else - { - name = [thread description]; - NSRange range = [name rangeOfString:@"num = "]; - if (range.location != NSNotFound) - { - name = [NSString stringWithFormat:@"Thread %@", - [name substringWithRange:NSMakeRange(range.location + range.length, - [name length] - range.location - range.length - 1)]]; - } - } - } - if (name != nil) - { - LoggerMessageAddString(encoder, (CFStringRef)name, PART_KEY_THREAD_ID); - hasThreadName = YES; - } - [pool drain]; - } -#endif - if (!hasThreadName) - { -#if __LP64__ - LoggerMessageAddInt64(encoder, (int64_t)pthread_self(), PART_KEY_THREAD_ID); -#else - LoggerMessageAddInt32(encoder, (int32_t)pthread_self(), PART_KEY_THREAD_ID); -#endif - } -} - -static void LoggerMessageUpdateDataHeader(CFMutableDataRef data) -{ - // update the data header with updated part count and size - UInt8 *p = CFDataGetMutableBytePtr(data); - uint32_t size = htonl(CFDataGetLength(data) - 4); - uint16_t partCount = htons(ntohs(*(uint16_t *)(p + 4)) + 1); - memcpy(p, &size, 4); - memcpy(p+4, &partCount, 2); -} - -static CFMutableDataRef LoggerMessageCreate() -{ - CFMutableDataRef data = CFDataCreateMutable(NULL, 0); - CFDataIncreaseLength(data, 6); - UInt8 *p = CFDataGetMutableBytePtr(data); - p[3] = 2; // size 0x00000002 in big endian - return data; -} - -static void LoggerMessageAddInt16(CFMutableDataRef data, int16_t anInt, int key) -{ - uint16_t partData = htonl(anInt); - uint8_t keyAndType[2] = {(uint8_t)key, PART_TYPE_INT16}; - CFDataAppendBytes(data, (const UInt8 *)&keyAndType, 2); - CFDataAppendBytes(data, (const UInt8 *)&partData, 2); - LoggerMessageUpdateDataHeader(data); -} - -static void LoggerMessageAddInt32(CFMutableDataRef data, int32_t anInt, int key) -{ - uint32_t partData = htonl(anInt); - uint8_t keyAndType[2] = {(uint8_t)key, PART_TYPE_INT32}; - CFDataAppendBytes(data, (const UInt8 *)&keyAndType, 2); - CFDataAppendBytes(data, (const UInt8 *)&partData, 4); - LoggerMessageUpdateDataHeader(data); -} - -static void LoggerMessageAddInt64(CFMutableDataRef data, int64_t anInt, int key) -{ - uint32_t partData[2] = {htonl((uint32_t)(anInt >> 32)), htonl((uint32_t)anInt)}; - uint8_t keyAndType[2] = {(uint8_t)key, PART_TYPE_INT64}; - CFDataAppendBytes(data, (const UInt8 *)&keyAndType, 2); - CFDataAppendBytes(data, (const UInt8 *)&partData, 8); - LoggerMessageUpdateDataHeader(data); -} - -static void LoggerMessageAddCString(CFMutableDataRef data, const char *aString, int key) -{ - if (aString == NULL || *aString == 0) - return; - - // convert to UTF-8 - int len = strlen(aString); - uint8_t *buf = malloc(2 * len); - if (buf != NULL) - { - int i, n = 0; - for (i = 0; i < len; i++) - { - uint8_t c = (uint8_t)(*aString++); - if (c < 0x80) - buf[n++] = c; - else { - buf[n++] = 0xC0 | (c >> 6); - buf[n++] = (c & 0x6F) | 0x80; - } - } - if (n) - { - uint32_t partSize = htonl(n); - uint8_t keyAndType[2] = {(uint8_t)key, PART_TYPE_STRING}; - CFDataAppendBytes(data, (const UInt8 *)&keyAndType, 2); - CFDataAppendBytes(data, (const UInt8 *)&partSize, 4); - CFDataAppendBytes(data, buf, n); - LoggerMessageUpdateDataHeader(data); - } - free(buf); - } -} - -static void LoggerMessageAddString(CFMutableDataRef data, CFStringRef aString, int key) -{ - if (aString == NULL) - aString = CFSTR(""); - - // All strings are UTF-8 encoded - uint8_t keyAndType[2] = {(uint8_t)key, PART_TYPE_STRING}; - uint32_t partSize = 0; - uint8_t *bytes = NULL; - - CFIndex stringLength = CFStringGetLength(aString); - CFIndex bytesLength = stringLength * 4; - if (stringLength) - { - bytes = (uint8_t *)malloc(stringLength * 4 + 4); - CFStringGetBytes(aString, CFRangeMake(0, stringLength), kCFStringEncodingUTF8, '?', false, bytes, bytesLength, &bytesLength); - partSize = htonl(bytesLength); - } - - CFDataAppendBytes(data, (const UInt8 *)&keyAndType, 2); - CFDataAppendBytes(data, (const UInt8 *)&partSize, 4); - if (partSize) - CFDataAppendBytes(data, bytes, bytesLength); - - if (bytes != NULL) - free(bytes); - LoggerMessageUpdateDataHeader(data); -} - -static void LoggerMessageAddData(CFMutableDataRef data, CFDataRef theData, int key, int partType) -{ - uint8_t keyAndType[2] = {(uint8_t)key, (uint8_t)partType}; - CFIndex dataLength = CFDataGetLength(theData); - uint32_t partSize = htonl(dataLength); - CFDataAppendBytes(data, (const UInt8 *)&keyAndType, 2); - CFDataAppendBytes(data, (const UInt8 *)&partSize, 4); - if (partSize) - CFDataAppendBytes(data, CFDataGetBytePtr(theData), dataLength); - LoggerMessageUpdateDataHeader(data); -} - -static uint32_t LoggerMessageGetSeq(CFDataRef message) -{ - // Extract the sequence number from a message. When pushing messages to the queue, - // we use this to guarantee the logging order according to the seq# - uint32_t seq = 0; - uint8_t *p = (uint8_t *)CFDataGetBytePtr(message) + 4; - uint16_t partCount; - memcpy(&partCount, p, 2); - partCount = ntohs(partCount); - p += 2; - while (partCount--) - { - uint8_t partKey = *p++; - uint8_t partType = *p++; - uint32_t partSize; - if (partType == PART_TYPE_INT16) - partSize = 2; - else if (partType == PART_TYPE_INT32) - partSize = 4; - else if (partType == PART_TYPE_INT64) - partSize = 8; - else - { - memcpy(&partSize, p, 4); - p += 4; - partSize = ntohl(partSize); - } - if (partKey == PART_KEY_MESSAGE_SEQ) - { - memcpy(&seq, p, sizeof(uint32_t)); - seq = ntohl(seq); - break; - } - p += partSize; - } - return seq; -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Private logging functions -// ----------------------------------------------------------------------------- -static void LoggerPushClientInfoToFrontOfQueue(Logger *logger) -{ - // Extract client information from the main bundle, as well as platform info, - // and assmble it to a message that will be put in front of the queue - // Helps desktop viewer display who's talking to it - // Note that we must be called from the logger work thread, as we don't - // run through the message port to transmit this message to the queue - CFBundleRef bundle = CFBundleGetMainBundle(); - if (bundle == NULL) - return; - CFMutableDataRef encoder = LoggerMessageCreate(); - if (encoder != NULL) - { - LoggerMessageAddTimestamp(encoder); - LoggerMessageAddInt32(encoder, LOGMSG_TYPE_CLIENTINFO, PART_KEY_MESSAGE_TYPE); - - CFStringRef version = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey); - if (version != NULL && CFGetTypeID(version) == CFStringGetTypeID()) - LoggerMessageAddString(encoder, version, PART_KEY_CLIENT_VERSION); - CFStringRef name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey); - if (name != NULL) - LoggerMessageAddString(encoder, name, PART_KEY_CLIENT_NAME); - -#if TARGET_OS_IPHONE && ALLOW_COCOA_USE - if ([NSThread isMultiThreaded] || [NSThread isMainThread]) - { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - UIDevice *device = [UIDevice currentDevice]; - LoggerMessageAddString(encoder, (CFStringRef)device.uniqueIdentifier, PART_KEY_UNIQUEID); - LoggerMessageAddString(encoder, (CFStringRef)device.systemVersion, PART_KEY_OS_VERSION); - LoggerMessageAddString(encoder, (CFStringRef)device.systemName, PART_KEY_OS_NAME); - LoggerMessageAddString(encoder, (CFStringRef)device.model, PART_KEY_CLIENT_MODEL); - [pool release]; - } -#elif TARGET_OS_MAC - SInt32 versionMajor, versionMinor, versionFix; - Gestalt(gestaltSystemVersionMajor, &versionMajor); - Gestalt(gestaltSystemVersionMinor, &versionMinor); - Gestalt(gestaltSystemVersionBugFix, &versionFix); - CFStringRef osVersion = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d.%d.%d"), versionMajor, versionMinor, versionFix); - LoggerMessageAddString(encoder, osVersion, PART_KEY_OS_VERSION); - CFRelease(osVersion); - LoggerMessageAddString(encoder, CFSTR("Mac OS X"), PART_KEY_OS_NAME); - - char buf[64]; - size_t len; - int ncpu = 0; - bzero(buf, sizeof(buf)); - len = sizeof(buf)-1; - sysctlbyname("hw.model", buf, &len, NULL, 0); - len = sizeof(ncpu); - sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0); - sprintf(buf+strlen(buf), " - %d * ", ncpu); - len = sizeof(buf)-strlen(buf)-1; - sysctlbyname("hw.machine", buf+strlen(buf), &len, NULL, 0); - - CFStringRef s = CFStringCreateWithCString(NULL, buf, kCFStringEncodingASCII); - LoggerMessageAddString(encoder, s, PART_KEY_CLIENT_MODEL); - CFRelease(s); -#endif - pthread_mutex_lock(&logger->logQueueMutex); - CFArrayInsertValueAtIndex(logger->logQueue, logger->incompleteSendOfFirstItem ? 1 : 0, encoder); - pthread_mutex_unlock(&logger->logQueueMutex); - - CFRelease(encoder); - } -} - -static void LoggerPushMessageToQueue(Logger *logger, CFDataRef message) -{ - // Add the message to the log queue and signal the runLoop source that will trigger - // a send on the worker thread. - pthread_mutex_lock(&logger->logQueueMutex); - CFIndex idx = CFArrayGetCount(logger->logQueue); - if (idx) - { - // to prevent out-of-order messages (as much as possible), we try to transmit messages in the - // order their sequence number was generated. Since the seq is generated first-thing, - // we can provide fine-grained ordering that gives a reasonable idea of the order - // the logging calls were made (useful for precise information about multithreading code) - uint32_t lastSeq, seq = LoggerMessageGetSeq(message); - do { - lastSeq = LoggerMessageGetSeq(CFArrayGetValueAtIndex(logger->logQueue, idx-1)); - } while (lastSeq > seq && --idx > 0); - } - if (idx >= 0) - CFArrayInsertValueAtIndex(logger->logQueue, idx, message); - else - CFArrayAppendValue(logger->logQueue, message); - pthread_mutex_unlock(&logger->logQueueMutex); - - if (logger->messagePushedSource != NULL) - { - // One case where the pushed source may be NULL is if the client code - // immediately starts logging without initializing the logger first. - // In this case, the worker thread has not completed startup, so we don't need - // to fire the runLoop source - CFRunLoopSourceSignal(logger->messagePushedSource); - } - else if (logger->workerThread == NULL && (logger->options & kLoggerOption_LogToConsole)) - { - // In this case, a failure creating the message runLoop source forces us - // to always log to console - pthread_mutex_lock(&logger->logQueueMutex); - while (CFArrayGetCount(logger->logQueue)) - { - LoggerLogToConsole(CFArrayGetValueAtIndex(logger->logQueue, 0)); - CFArrayRemoveValueAtIndex(logger->logQueue, 0); - } - pthread_mutex_unlock(&logger->logQueueMutex); - } -} - -static void LogMessageTo_internal(Logger *logger, - const char *filename, - int lineNumber, - const char *functionName, - NSString *domain, - int level, - NSString *format, - va_list args) -{ - if (logger == NULL) - { - logger = LoggerGetDefaultLogger(); - LoggerStart(logger); - } - - int32_t seq = OSAtomicIncrement32Barrier(&logger->messageSeq); - LOGGERDBG2(CFSTR("%ld LogMessage"), seq); - - CFMutableDataRef encoder = LoggerMessageCreate(); - if (encoder != NULL) - { - LoggerMessageAddTimestampAndThreadID(encoder); - LoggerMessageAddInt32(encoder, LOGMSG_TYPE_LOG, PART_KEY_MESSAGE_TYPE); - LoggerMessageAddInt32(encoder, seq, PART_KEY_MESSAGE_SEQ); - if (domain != nil && [domain length]) - LoggerMessageAddString(encoder, (CFStringRef)domain, PART_KEY_TAG); - if (level) - LoggerMessageAddInt32(encoder, level, PART_KEY_LEVEL); - if (filename != NULL) - LoggerMessageAddCString(encoder, filename, PART_KEY_FILENAME); - if (lineNumber) - LoggerMessageAddInt32(encoder, lineNumber, PART_KEY_LINENUMBER); - if (functionName != NULL) - LoggerMessageAddCString(encoder, functionName, PART_KEY_FUNCTIONNAME); - -#if ALLOW_COCOA_USE - // Go though NSString to avoid low-level logging of CF datastructures (i.e. too detailed NSDictionary, etc) - NSString *msgString = [[NSString alloc] initWithFormat:format arguments:args]; - if (msgString != nil) - { - LoggerMessageAddString(encoder, (CFStringRef)msgString, PART_KEY_MESSAGE); - [msgString release]; - } -#else - CFStringRef msgString = CFStringCreateWithFormatAndArguments(NULL, NULL, (CFStringRef)format, args); - if (msgString != NULL) - { - LoggerMessageAddString(encoder, msgString, PART_KEY_MESSAGE); - CFRelease(msgString); - } -#endif - - LoggerPushMessageToQueue(logger, encoder); - CFRelease(encoder); - } - else - { - LOGGERDBG2(CFSTR("-> failed creating encoder")); - } -} - -static void LogImageTo_internal(Logger *logger, - const char *filename, - int lineNumber, - const char *functionName, - NSString *domain, - int level, - int width, - int height, - NSData *data) -{ - if (logger == NULL) - { - logger = LoggerGetDefaultLogger(); - LoggerStart(logger); - } - - int32_t seq = OSAtomicIncrement32Barrier(&logger->messageSeq); - LOGGERDBG2(CFSTR("%ld LogImage"), seq); - - CFMutableDataRef encoder = LoggerMessageCreate(); - if (encoder != NULL) - { - LoggerMessageAddTimestampAndThreadID(encoder); - LoggerMessageAddInt32(encoder, LOGMSG_TYPE_LOG, PART_KEY_MESSAGE_TYPE); - LoggerMessageAddInt32(encoder, seq, PART_KEY_MESSAGE_SEQ); - if (domain != nil && [domain length]) - LoggerMessageAddString(encoder, (CFStringRef)domain, PART_KEY_TAG); - if (level) - LoggerMessageAddInt32(encoder, level, PART_KEY_LEVEL); - if (width && height) - { - LoggerMessageAddInt32(encoder, width, PART_KEY_IMAGE_WIDTH); - LoggerMessageAddInt32(encoder, height, PART_KEY_IMAGE_HEIGHT); - } - if (filename != NULL) - LoggerMessageAddCString(encoder, filename, PART_KEY_FILENAME); - if (lineNumber) - LoggerMessageAddInt32(encoder, lineNumber, PART_KEY_LINENUMBER); - if (functionName != NULL) - LoggerMessageAddCString(encoder, functionName, PART_KEY_FUNCTIONNAME); - LoggerMessageAddData(encoder, (CFDataRef)data, PART_KEY_MESSAGE, PART_TYPE_IMAGE); - - LoggerPushMessageToQueue(logger, encoder); - CFRelease(encoder); - } - else - { - LOGGERDBG2(CFSTR("-> failed creating encoder")); - } -} - -static void LogDataTo_internal(Logger *logger, - const char *filename, - int lineNumber, - const char *functionName, - NSString *domain, - int level, NSData *data) -{ - if (logger == NULL) - { - logger = LoggerGetDefaultLogger(); - LoggerStart(logger); - } - - int32_t seq = OSAtomicIncrement32Barrier(&logger->messageSeq); - LOGGERDBG2(CFSTR("%ld LogData"), seq); - - CFMutableDataRef encoder = LoggerMessageCreate(); - if (encoder != NULL) - { - LoggerMessageAddTimestampAndThreadID(encoder); - LoggerMessageAddInt32(encoder, LOGMSG_TYPE_LOG, PART_KEY_MESSAGE_TYPE); - LoggerMessageAddInt32(encoder, seq, PART_KEY_MESSAGE_SEQ); - if (domain != nil && [domain length]) - LoggerMessageAddString(encoder, (CFStringRef)domain, PART_KEY_TAG); - if (level) - LoggerMessageAddInt32(encoder, level, PART_KEY_LEVEL); - if (filename != NULL) - LoggerMessageAddCString(encoder, filename, PART_KEY_FILENAME); - if (lineNumber) - LoggerMessageAddInt32(encoder, lineNumber, PART_KEY_LINENUMBER); - if (functionName != NULL) - LoggerMessageAddCString(encoder, functionName, PART_KEY_FUNCTIONNAME); - LoggerMessageAddData(encoder, (CFDataRef)data, PART_KEY_MESSAGE, PART_TYPE_BINARY); - - LoggerPushMessageToQueue(logger, encoder); - CFRelease(encoder); - } - else - { - LOGGERDBG2(CFSTR("-> failed creating encoder")); - } -} - -static void LogStartBlockTo_internal(Logger *logger, NSString *format, va_list args) -{ - if (logger == NULL) - { - logger = LoggerGetDefaultLogger(); - LoggerStart(logger); - } - - int32_t seq = OSAtomicIncrement32Barrier(&logger->messageSeq); - LOGGERDBG2(CFSTR("%ld LogStartBlock"), seq); - - CFMutableDataRef encoder = LoggerMessageCreate(); - if (encoder != NULL) - { - LoggerMessageAddTimestampAndThreadID(encoder); - LoggerMessageAddInt32(encoder, LOGMSG_TYPE_BLOCKSTART, PART_KEY_MESSAGE_TYPE); - LoggerMessageAddInt32(encoder, seq, PART_KEY_MESSAGE_SEQ); - - CFStringRef msgString = NULL; - if (format != nil) - { - msgString = CFStringCreateWithFormatAndArguments(NULL, NULL, (CFStringRef)format, args); - if (msgString != NULL) - { - LoggerMessageAddString(encoder, msgString, PART_KEY_MESSAGE); - CFRelease(msgString); - } - } - - LoggerPushMessageToQueue(logger, encoder); - CFRelease(encoder); - } -} - -// ----------------------------------------------------------------------------- -#pragma mark - -#pragma mark Public logging functions -// ----------------------------------------------------------------------------- -void LogMessageCompat(NSString *format, ...) -{ - va_list args; - va_start(args, format); - LogMessageTo_internal(NULL, NULL, 0, NULL, nil, 0, format, args); - va_end(args); -} - -void LogMessageTo(Logger *logger, NSString *domain, int level, NSString *format, ...) -{ - va_list args; - va_start(args, format); - LogMessageTo_internal(logger, NULL, 0, NULL, domain, level, format, args); - va_end(args); -} - -void LogMessageToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, ...) -{ - va_list args; - va_start(args, format); - LogMessageTo_internal(logger, filename, lineNumber, functionName, domain, level, format, args); - va_end(args); -} - -void LogMessageTo_va(Logger *logger, NSString *domain, int level, NSString *format, va_list args) -{ - LogMessageTo_internal(logger, NULL, 0, NULL, domain, level, format, args); -} - -void LogMessageToF_va(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, va_list args) -{ - LogMessageTo_internal(logger, filename, lineNumber, functionName, domain, level, format, args); -} - -void LogMessage(NSString *domain, int level, NSString *format, ...) -{ - va_list args; - va_start(args, format); - LogMessageTo_internal(NULL, NULL, 0, NULL, domain, level, format, args); - va_end(args); -} - -void LogMessageF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, ...) -{ - va_list args; - va_start(args, format); - LogMessageTo_internal(NULL, filename, lineNumber, functionName, domain, level, format, args); - va_end(args); -} - -void LogMessage_va(NSString *domain, int level, NSString *format, va_list args) -{ - LogMessageTo_internal(NULL, NULL, 0, NULL, domain, level, format, args); -} - -void LogMessageF_va(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, va_list args) -{ - LogMessageTo_internal(NULL, filename, lineNumber, functionName, domain, level, format, args); -} - -void LogData(NSString *domain, int level, NSData *data) -{ - LogDataTo_internal(NULL, NULL, 0, NULL, domain, level, data); -} - -void LogDataF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSData *data) -{ - LogDataTo_internal(NULL, filename, lineNumber, functionName, domain, level, data); -} - -void LogDataTo(Logger *logger, NSString *domain, int level, NSData *data) -{ - LogDataTo_internal(logger, NULL, 0, NULL, domain, level, data); -} - -void LogDataToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSData *data) -{ - LogDataTo_internal(logger, filename, lineNumber, functionName, domain, level, data); -} - -void LogImageData(NSString *domain, int level, int width, int height, NSData *data) -{ - LogImageTo_internal(NULL, NULL, 0, NULL, domain, level, width, height, data); -} - -void LogImageDataF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, int width, int height, NSData *data) -{ - LogImageTo_internal(NULL, filename, lineNumber, functionName, domain, level, width, height, data); -} - -void LogImageDataTo(Logger *logger, NSString *domain, int level, int width, int height, NSData *data) -{ - LogImageTo_internal(logger, NULL, 0, NULL, domain, level, width, height, data); -} - -void LogImageDataToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, int width, int height, NSData *data) -{ - LogImageTo_internal(logger, filename, lineNumber, functionName, domain, level, width, height, data); -} - -void LogStartBlock(NSString *format, ...) -{ - va_list args; - va_start(args, format); - LogStartBlockTo_internal(NULL, format, args); - va_end(args); -} - -void LogStartBlockTo(Logger *logger, NSString *format, ...) -{ - va_list args; - va_start(args, format); - LogStartBlockTo_internal(logger, format, args); - va_end(args); -} - -void LogEndBlockTo(Logger *logger) -{ - if (logger == NULL) - { - logger = LoggerGetDefaultLogger(); - LoggerStart(logger); - } - - if (logger->options & kLoggerOption_LogToConsole) - return; - - int32_t seq = OSAtomicIncrement32Barrier(&logger->messageSeq); - LOGGERDBG2(CFSTR("%ld LogEndBlock"), seq); - - CFMutableDataRef encoder = LoggerMessageCreate(); - if (encoder != NULL) - { - LoggerMessageAddTimestampAndThreadID(encoder); - LoggerMessageAddInt32(encoder, LOGMSG_TYPE_BLOCKEND, PART_KEY_MESSAGE_TYPE); - LoggerMessageAddInt32(encoder, seq, PART_KEY_MESSAGE_SEQ); - LoggerPushMessageToQueue(logger, encoder); - CFRelease(encoder); - } - else - { - LOGGERDBG2(CFSTR("-> failed creating encoder")); - } -} - -void LogEndBlock() -{ - LogEndBlockTo(NULL); -} diff --git a/Vendor/NSLogger/LoggerCommon.h b/Vendor/NSLogger/LoggerCommon.h deleted file mode 100644 index ab063039eb..0000000000 --- a/Vendor/NSLogger/LoggerCommon.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * LoggerCommon.h - * - * version 1.0b10 2011-02-18 - * - * Definitions common to NSLogger Viewer and NSLoggerClient - * for the binary messages format - * https://github.com/fpillet/NSLogger - * - * BSD license follows (http://www.opensource.org/licenses/bsd-license.php) - * - * Copyright (c) 2010-2011 Florent Pillet All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. Redistributions in - * binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. Neither the name of Florent - * Pillet nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT - * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* NSLogger native binary message format: - * Each message is a dictionary encoded in a compact format. All values are stored - * in network order (big endian). A message is made of several "parts", which are - * typed chunks of data, each with a specific purpose (partKey), data type (partType) - * and data size (partSize). - * - * uint32_t totalSize (total size for the whole message) - * uint16_t partCount (number of parts below) - * [repeat partCount times]: - * uint8_t partKey the part key - * uint8_t partType (string, binary, image, int16, int32, int64) - * uint32_t partSize (only for string, binary and image types, others are implicit) - * .. `partSize' data bytes - * - * Complete message is usually made of: - * - a PART_KEY_MESSAGE_TYPE (mandatory) which contains one of the LOGMSG_TYPE_* values - * - a PART_KEY_TIMESTAMP_S (mandatory) which is the timestamp returned by gettimeofday() (seconds from 01.01.1970 00:00) - * - a PART_KEY_TIMESTAMP_MS (optional) complement of the timestamp seconds, in milliseconds - * - a PART_KEY_TIMESTAMP_US (optional) complement of the timestamp seconds and milliseconds, in microseconds - * - a PART_KEY_THREAD_ID (mandatory) the ID of the user thread that produced the log entry - * - a PART_KEY_TAG (optional) a tag that helps categorizing and filtering logs from your application, and shows up in viewer logs - * - a PART_KEY_LEVEL (optional) a log level that helps filtering logs from your application (see as few or as much detail as you need) - * - a PART_KEY_MESSAGE which is the message text, binary data or image - * - a PART_KEY_MESSAGE_SEQ which is the message sequence number (message# sent by client) - * - a PART_KEY_FILENAME (optional) with the filename from which the log was generated - * - a PART_KEY_LINENUMBER (optional) the linenumber in the filename at which the log was generated - * - a PART_KEY_FUNCTIONNAME (optional) the function / method / selector from which the log was generated - * - if logging an image, PART_KEY_IMAGE_WIDTH and PART_KEY_IMAGE_HEIGHT let the desktop know the image size without having to actually decode it - */ - -// Constants for the "part key" field -#define PART_KEY_MESSAGE_TYPE 0 -#define PART_KEY_TIMESTAMP_S 1 // "seconds" component of timestamp -#define PART_KEY_TIMESTAMP_MS 2 // milliseconds component of timestamp (optional, mutually exclusive with PART_KEY_TIMESTAMP_US) -#define PART_KEY_TIMESTAMP_US 3 // microseconds component of timestamp (optional, mutually exclusive with PART_KEY_TIMESTAMP_MS) -#define PART_KEY_THREAD_ID 4 -#define PART_KEY_TAG 5 -#define PART_KEY_LEVEL 6 -#define PART_KEY_MESSAGE 7 -#define PART_KEY_IMAGE_WIDTH 8 // messages containing an image should also contain a part with the image size -#define PART_KEY_IMAGE_HEIGHT 9 // (this is mainly for the desktop viewer to compute the cell size without having to immediately decode the image) -#define PART_KEY_MESSAGE_SEQ 10 // the sequential number of this message which indicates the order in which messages are generated -#define PART_KEY_FILENAME 11 // when logging, message can contain a file name -#define PART_KEY_LINENUMBER 12 // as well as a line number -#define PART_KEY_FUNCTIONNAME 13 // and a function or method name - -// Constants for parts in LOGMSG_TYPE_CLIENTINFO -#define PART_KEY_CLIENT_NAME 20 -#define PART_KEY_CLIENT_VERSION 21 -#define PART_KEY_OS_NAME 22 -#define PART_KEY_OS_VERSION 23 -#define PART_KEY_CLIENT_MODEL 24 // For iPhone, device model (i.e 'iPhone', 'iPad', etc) -#define PART_KEY_UNIQUEID 25 // for remote device identification, part of LOGMSG_TYPE_CLIENTINFO - -// Area starting at which you may define your own constants -#define PART_KEY_USER_DEFINED 100 - -// Constants for the "partType" field -#define PART_TYPE_STRING 0 // Strings are stored as UTF-8 data -#define PART_TYPE_BINARY 1 // A block of binary data -#define PART_TYPE_INT16 2 -#define PART_TYPE_INT32 3 -#define PART_TYPE_INT64 4 -#define PART_TYPE_IMAGE 5 // An image, stored in PNG format - -// Data values for the PART_KEY_MESSAGE_TYPE parts -#define LOGMSG_TYPE_LOG 0 // A standard log message -#define LOGMSG_TYPE_BLOCKSTART 1 // The start of a "block" (a group of log entries) -#define LOGMSG_TYPE_BLOCKEND 2 // The end of the last started "block" -#define LOGMSG_TYPE_CLIENTINFO 3 // Information about the client app -#define LOGMSG_TYPE_DISCONNECT 4 // Pseudo-message on the desktop side to identify client disconnects -#define LOGMSG_TYPE_MARK 5 // Pseudo-message that defines a "mark" that users can place in the log flow - -// Default Bonjour service identifiers -#define LOGGER_SERVICE_TYPE_SSL CFSTR("_nslogger-ssl._tcp") -#define LOGGER_SERVICE_TYPE CFSTR("_nslogger._tcp") diff --git a/Vendor/NSLogger/README.markdown b/Vendor/NSLogger/README.markdown deleted file mode 100644 index 153dbd4dc1..0000000000 --- a/Vendor/NSLogger/README.markdown +++ /dev/null @@ -1,73 +0,0 @@ -# NSLogger # -![Icon](https://github.com/fpillet/NSLogger/raw/master/Screenshots/icon_small.png "Icon") - -*NSLogger* is a high perfomance logging utility which displays traces emitted by client applications running on **Mac OS X** or **iOS (iPhone OS)**. It replaces your usual *NSLog()*-based traces and provides powerful additions like display filtering, image and binary logging, traces buffering, timing information, etc. - -*NSLogger* feature summary: - - * View logs using the Mac OS X desktop viewer, accept connections from local network clients (using Bonjour) or remote clients connecting directly over the internet - * Online (application running and connected to _NSLogger_) and offline (saved logs) log viewing - * Buffer all traces in memory or in a file, send them over to viewer when a connection is acquired - * Secure logging (connections use SSL by default) - * Advanced log filtering options - * Save viewer logs to share them and/or review them later - * Export logs to text files - * Open raw buffered traces files that you brought back from client applications not directly connected to the log viewer - -**You'll find instructions for use in the [NSLogger wiki](https://github.com/fpillet/NSLogger/wiki/).** - -Your application emits traces using the *NSLogger* [trace APIs](https://github.com/fpillet/NSLogger/wiki/NSLogger-API). The desktop viewer application (running on **Mac OS X 10.6 or later**) displays them. - -Clients automatically find the logger application running on Mac OS X via Bonjour networking, and can optionally connect to a specific remote host/port. You have no setup to do: just start the logger on your Mac, launch your iOS or Mac OS X application then when your app emits traces, they will automatically show up in *NSLogger* if the viewer is running locally on your network. Until a logger is found, logs are buffered on the client so you don't lose anything. - -![Desktop Viewer (main window)](https://github.com/fpillet/NSLogger/raw/master/Screenshots/mainwindow.png "Desktop Viewer") - -# One-step setup # -All you have to do is add `LoggerClient.h`, `LoggerClient.m` and `LoggerCommon.h` (as well as add the `CFNetwork.framework` and `SystemConfiguration.framework` frameworks) to your iOS or Mac OS X application, then replace your *NSLog()* calls with *LogMessageCompat()* calls. We recommend using a macro, so you can turn off logs when building the distribution version of your application. - -# Using the desktop logger # -Start the NSLogger application on Mac OS X. Your client app must run on a device that is on the same network as your Mac. When it starts logging traces, it will automatically (by default) look for the desktop NSLogger using Bonjour. As soon as traces start coming, a new window will open on your Mac. Advanced users can setup a Remote Host / Port to log from a client to a specific host). - -You can create custom filters to quickly switch between different views of your logs. - -# Evolved logging facility # -It's very easy to log binary data or images using *NSLogger*. Use the *LogData()* and *LogImage()* calls in your application, and you're done. Advanced users can also enable remote logging to have logs sent directly from remote devices running at distant locations, or have logs be directed to a file that can later be sent to a remote server. - -# Powerful desktop viewer # -The desktop viewer application provides tools like: - - * Filters (with [regular expression matching](https://github.com/fpillet/NSLogger/wiki/Tips-and-tricks)) that let your perform data mining in your logs - * Timing information: each message displays the time elapsed since the previous message in the filtered display, so you can get a sense of time between events in your application. - * Image and binary data display directly in the log window - * [Markers](https://github.com/fpillet/NSLogger/wiki/Tips-and-tricks) (when a client is connected, place a marker at the end of a log to clearly see what happens afterwards, for example place a marker before pressing a button in your application) - * Fast navigation in your logs - * Display and export all your logs as text - * Optional display of file, line and function for uncluttered display - - -Your logs can be saved to a `.nsloggerdata` file, and reloaded later. When logging to a file, name your log file with extension `.rawnsloggerdata` so NSLogger can reopen and process it. You can have clients remotely generating raw logger data files, then send them to you so you can investigate post-mortem. - -Note that the NSLogger Mac OS X viewer requires **Mac OS X 10.6 or later**. - -![Filter Editor](https://github.com/fpillet/NSLogger/raw/master/Screenshots/filtereditor.png "Filter Editor") - -# High performance, low overhead # -*NSLogger* runs in its own thread in your application. It tries hard to consume as few CPU and memory as possible. If the desktop viewer has not been found yet, your traces can be buffered in memory until a connection is acquired. This allows for tracing in difficult situations, for example device wakeup times when the network connection is not up and running. - -*NSLogger* can be used for low-level code in situations where only CoreFoundation can be called. Disable the **ALLOW_COCOA** flag in *LoggerClient.h* to prevent any use of Cocoa code. - -# Work in progress - Current status # -This tool comes from a personal need for a more powerful logger. There are more features planned for inclusion, here is a quick list of what I'm thinking of. Requests and suggestions are welcome. - - * Log entry colorization - * Search and search term highlight in Details window - * Support time-based filtering (filter clause based on the time lapse between a previous trace) - * Pause (buffer logs) and resume sending logs to the logger, in order to eliminate NSLogger's network load from the equation when testing networking code - - -You'll find documentation in the [NSLogger Wiki](https://github.com/fpillet/NSLogger/wiki/) - -NSLogger uses [Brandon Walkin's BWToolkit](http://www.brandonwalkin.com/bwtoolkit/), for which source code is included with NSLogger. - -NSLogger is Copyright (c) 2010-2011 Florent Pillet, All Rights Reserved, All Wrongs Revenged. Released under the [New BSD Licence](http://www.opensource.org/licenses/bsd-license.php). -The NSLogger icon is Copyright (c) [Louis Harboe](http://www.graphicpeel.com) diff --git a/Vendor/NXJSON/NSError+Extensions.m b/Vendor/NXJSON/NSError+Extensions.m index 14cbaa842d..72f471ef1c 100644 --- a/Vendor/NXJSON/NSError+Extensions.m +++ b/Vendor/NXJSON/NSError+Extensions.m @@ -22,7 +22,9 @@ Created by Martin Adoue (martin@nextive.com) and Hernan Pelassini (hernan@nextiv */ #import "NSError+Extensions.h" +#import "RKFixCategoryBug.h" +RK_FIX_CATEGORY_BUG(NSError_Extensions) @implementation NSError(Extensions) +(NSError*)errorWithDomain:(NSString*)domain code:(NSInteger)code description:(NSString*)description diff --git a/Vendor/SBJSON/NSObject+SBJSON.m b/Vendor/SBJSON/NSObject+SBJSON.m index 30570b5937..5cc845fee5 100644 --- a/Vendor/SBJSON/NSObject+SBJSON.m +++ b/Vendor/SBJSON/NSObject+SBJSON.m @@ -29,6 +29,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE #import "NSObject+SBJSON.h" #import "SBJsonWriter.h" +#import "RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSObject_SBJSON) @implementation NSObject (NSObject_SBJSON) diff --git a/Vendor/SBJSON/NSString+SBJSON.m b/Vendor/SBJSON/NSString+SBJSON.m index bb132e1eb3..4170f5e998 100644 --- a/Vendor/SBJSON/NSString+SBJSON.m +++ b/Vendor/SBJSON/NSString+SBJSON.m @@ -29,6 +29,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE #import "NSString+SBJSON.h" #import "SBJsonParser.h" +#import "RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSString_SBJSON) @implementation NSString (NSString_SBJSON) diff --git a/Vendor/YAJL/NSBundle+YAJL.m b/Vendor/YAJL/NSBundle+YAJL.m index 3e3f08b340..2c2d4303f9 100644 --- a/Vendor/YAJL/NSBundle+YAJL.m +++ b/Vendor/YAJL/NSBundle+YAJL.m @@ -30,6 +30,9 @@ #import "NSBundle+YAJL.h" #import "GHNSBundle+Utils.h" #import "NSObject+YAJL.h" +#import "RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSBundle_YAJL) @implementation NSBundle (YAJL) diff --git a/Vendor/YAJL/NSObject+YAJL.m b/Vendor/YAJL/NSObject+YAJL.m index ce5a559b4a..52371f6a87 100644 --- a/Vendor/YAJL/NSObject+YAJL.m +++ b/Vendor/YAJL/NSObject+YAJL.m @@ -30,6 +30,9 @@ #import "NSObject+YAJL.h" #import "YAJLGen.h" #import "YAJLDocument.h" +#import "RKFixCategoryBug.h" + +RK_FIX_CATEGORY_BUG(NSObject_YAJL) @implementation NSObject (YAJL)