Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d7d40e6d27 | |||
| bec7e0c229 | |||
| 82a19e41e7 | |||
| 867ae614e5 | |||
| 22b7c6ccc7 | |||
| 9e9704580a | |||
| 1ef608cf8a | |||
| b64cd37ec6 | |||
| 44e9d55fb8 | |||
| ab9515caaf |
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXArgumentInputFontsPickerView.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by 啟倫 陳 on 2014/7/27.
|
||||
// Copyright (c) 2014年 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXArgumentInputFontsPickerView.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by 啟倫 陳 on 2014/7/27.
|
||||
// Copyright (c) 2014年 f. All rights reserved.
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "FLEXArgumentInputTextView.h"
|
||||
|
||||
#warning TODO This is never supported
|
||||
@interface FLEXArgumentInputJSONObjectView : FLEXArgumentInputTextView
|
||||
|
||||
@end
|
||||
|
||||
@@ -39,26 +39,23 @@
|
||||
+ (Class)argumentInputViewSubclassForTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue
|
||||
{
|
||||
Class argumentInputViewSubclass = nil;
|
||||
NSArray<Class> *inputViewClasses = @[[FLEXArgumentInputColorView class],
|
||||
[FLEXArgumentInputFontView class],
|
||||
[FLEXArgumentInputStringView class],
|
||||
[FLEXArgumentInputStructView class],
|
||||
[FLEXArgumentInputSwitchView class],
|
||||
[FLEXArgumentInputDateView class],
|
||||
[FLEXArgumentInputNumberView class],
|
||||
[FLEXArgumentInputJSONObjectView class]];
|
||||
|
||||
// Note that order is important here since multiple subclasses may support the same type.
|
||||
// An example is the number subclass and the bool subclass for the type @encode(BOOL).
|
||||
// Both work, but we'd prefer to use the bool subclass.
|
||||
if ([FLEXArgumentInputColorView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = [FLEXArgumentInputColorView class];
|
||||
} else if ([FLEXArgumentInputFontView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = [FLEXArgumentInputFontView class];
|
||||
} else if ([FLEXArgumentInputStringView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = [FLEXArgumentInputStringView class];
|
||||
} else if ([FLEXArgumentInputStructView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = [FLEXArgumentInputStructView class];
|
||||
} else if ([FLEXArgumentInputSwitchView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = [FLEXArgumentInputSwitchView class];
|
||||
} else if ([FLEXArgumentInputDateView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = [FLEXArgumentInputDateView class];
|
||||
} else if ([FLEXArgumentInputNumberView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = [FLEXArgumentInputNumberView class];
|
||||
} else if ([FLEXArgumentInputJSONObjectView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = [FLEXArgumentInputJSONObjectView class];
|
||||
for (Class inputView in inputViewClasses) {
|
||||
if ([inputView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
|
||||
argumentInputViewSubclass = inputView;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return argumentInputViewSubclass;
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
// Copyright (c) 2014 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXFieldEditorViewController.h"
|
||||
#import "FLEXMutableFieldEditorViewController.h"
|
||||
|
||||
@interface FLEXDefaultEditorViewController : FLEXFieldEditorViewController
|
||||
@interface FLEXDefaultEditorViewController : FLEXMutableFieldEditorViewController
|
||||
|
||||
- (id)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key;
|
||||
|
||||
|
||||
@@ -64,6 +64,13 @@
|
||||
self.firstInputView.inputValue = [self.defaults objectForKey:self.key];
|
||||
}
|
||||
|
||||
- (void)getterButtonPressed:(id)sender
|
||||
{
|
||||
[super getterButtonPressed:sender];
|
||||
id returnedObject = [self.defaults objectForKey:self.key];
|
||||
[self exploreObjectOrPopViewController:returnedObject];
|
||||
}
|
||||
|
||||
+ (BOOL)canEditDefaultWithValue:(id)currentValue
|
||||
{
|
||||
return [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:@encode(id) currentValue:currentValue];
|
||||
|
||||
@@ -22,7 +22,11 @@
|
||||
@property (nonatomic, strong, readonly) id target;
|
||||
@property (nonatomic, strong, readonly) FLEXFieldEditorView *fieldEditorView;
|
||||
@property (nonatomic, strong, readonly) UIBarButtonItem *setterButton;
|
||||
|
||||
- (void)actionButtonPressed:(id)sender;
|
||||
- (NSString *)titleForActionButton;
|
||||
/// Pushes an explorer view controller for the given object
|
||||
/// or pops the current view controller.
|
||||
- (void)exploreObjectOrPopViewController:(id)objectOrNil;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
#import "FLEXFieldEditorView.h"
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "FLEXArgumentInputView.h"
|
||||
#import "FLEXArgumentInputViewFactory.h"
|
||||
#import "FLEXObjectExplorerViewController.h"
|
||||
|
||||
@interface FLEXFieldEditorViewController () <UIScrollViewDelegate>
|
||||
|
||||
@@ -114,4 +116,16 @@
|
||||
return @"Set";
|
||||
}
|
||||
|
||||
- (void)exploreObjectOrPopViewController:(id)objectOrNil {
|
||||
if (objectOrNil) {
|
||||
// For non-nil (or void) return types, push an explorer view controller to display the object
|
||||
FLEXObjectExplorerViewController *explorerViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:objectOrNil];
|
||||
[self.navigationController pushViewController:explorerViewController animated:YES];
|
||||
} else {
|
||||
// If we didn't get a returned object but the method call succeeded,
|
||||
// pop this view controller off the stack to indicate that the call went through.
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
// Copyright (c) 2014 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXFieldEditorViewController.h"
|
||||
#import "FLEXMutableFieldEditorViewController.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface FLEXIvarEditorViewController : FLEXFieldEditorViewController
|
||||
@interface FLEXIvarEditorViewController : FLEXMutableFieldEditorViewController
|
||||
|
||||
- (id)initWithTarget:(id)target ivar:(Ivar)ivar;
|
||||
|
||||
|
||||
@@ -55,6 +55,17 @@
|
||||
|
||||
[FLEXRuntimeUtility setValue:self.firstInputView.inputValue forIvar:self.ivar onObject:self.target];
|
||||
self.firstInputView.inputValue = [FLEXRuntimeUtility valueForIvar:self.ivar onObject:self.target];
|
||||
|
||||
// Pop view controller for consistency;
|
||||
// property setters and method calls also pop on success.
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)getterButtonPressed:(id)sender
|
||||
{
|
||||
[super getterButtonPressed:sender];
|
||||
id returnedObject = [FLEXRuntimeUtility valueForIvar:self.ivar onObject:self.target];
|
||||
[self exploreObjectOrPopViewController:returnedObject];
|
||||
}
|
||||
|
||||
- (void)argumentInputViewValueDidChange:(FLEXArgumentInputView *)argumentInputView
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
@interface FLEXMethodCallingViewController ()
|
||||
|
||||
@property (nonatomic, assign) Method method;
|
||||
@property (nonatomic, assign) FLEXTypeEncoding *returnType;
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,7 +28,8 @@
|
||||
self = [super initWithTarget:target];
|
||||
if (self) {
|
||||
self.method = method;
|
||||
self.title = [self isClassMethod] ? @"Class Method" : @"Method";
|
||||
self.returnType = [FLEXRuntimeUtility returnTypeForMethod:method];
|
||||
self.title = [self isClassMethod] ? @"Class Method" : @"Method";;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -36,7 +38,11 @@
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
self.fieldEditorView.fieldDescription = [FLEXRuntimeUtility prettyNameForMethod:self.method isClassMethod:[self isClassMethod]];
|
||||
NSString *returnType = @((const char *)self.returnType);
|
||||
NSString *methodDescription = [FLEXRuntimeUtility prettyNameForMethod:self.method isClassMethod:[self isClassMethod]];
|
||||
NSString *format = @"Signature:\n%@\n\nReturn Type:\n%@";
|
||||
NSString *info = [NSString stringWithFormat:format, methodDescription, returnType];
|
||||
self.fieldEditorView.fieldDescription = info;
|
||||
|
||||
NSArray<NSString *> *methodComponents = [FLEXRuntimeUtility prettyArgumentComponentsForMethod:self.method];
|
||||
NSMutableArray<FLEXArgumentInputView *> *argumentInputViews = [NSMutableArray array];
|
||||
@@ -54,6 +60,12 @@
|
||||
self.fieldEditorView.argumentInputViews = argumentInputViews;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(self.returnType);
|
||||
self.returnType = NULL;
|
||||
}
|
||||
|
||||
- (BOOL)isClassMethod
|
||||
{
|
||||
return self.target && self.target == [self.target class];
|
||||
@@ -88,12 +100,11 @@
|
||||
[alert show];
|
||||
} else if (returnedObject) {
|
||||
// For non-nil (or void) return types, push an explorer view controller to display the returned object
|
||||
returnedObject = [FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:returnedObject type:self.returnType];
|
||||
FLEXObjectExplorerViewController *explorerViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:returnedObject];
|
||||
[self.navigationController pushViewController:explorerViewController animated:YES];
|
||||
} else {
|
||||
// If we didn't get a returned object but the method call succeeded,
|
||||
// pop this view controller off the stack to indicate that the call went through.
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
[self exploreObjectOrPopViewController:returnedObject];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FLEXMutableFieldEditorViewController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 11/22/18.
|
||||
// Copyright © 2018 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXFieldEditorViewController.h"
|
||||
|
||||
@interface FLEXMutableFieldEditorViewController : FLEXFieldEditorViewController
|
||||
|
||||
@property (nonatomic, strong, readonly) UIBarButtonItem *getterButton;
|
||||
|
||||
- (void)getterButtonPressed:(id)sender;
|
||||
- (NSString *)titleForGetterButton;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// FLEXMutableFieldEditorViewController.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 11/22/18.
|
||||
// Copyright © 2018 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXMutableFieldEditorViewController.h"
|
||||
#import "FLEXFieldEditorView.h"
|
||||
|
||||
@interface FLEXMutableFieldEditorViewController ()
|
||||
|
||||
@property (nonatomic, strong, readwrite) UIBarButtonItem *getterButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXMutableFieldEditorViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.getterButton = [[UIBarButtonItem alloc] initWithTitle:[self titleForGetterButton] style:UIBarButtonItemStyleDone target:self action:@selector(getterButtonPressed:)];
|
||||
self.navigationItem.rightBarButtonItems = @[self.setterButton, self.getterButton];
|
||||
}
|
||||
|
||||
- (void)getterButtonPressed:(id)sender {
|
||||
// Subclasses can override
|
||||
[self.fieldEditorView endEditing:YES];
|
||||
}
|
||||
|
||||
- (NSString *)titleForGetterButton {
|
||||
return @"Get";
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -6,10 +6,10 @@
|
||||
// Copyright (c) 2014 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXFieldEditorViewController.h"
|
||||
#import "FLEXMutableFieldEditorViewController.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface FLEXPropertyEditorViewController : FLEXFieldEditorViewController
|
||||
@interface FLEXPropertyEditorViewController : FLEXMutableFieldEditorViewController
|
||||
|
||||
- (id)initWithTarget:(id)target property:(objc_property_t)property;
|
||||
|
||||
|
||||
@@ -76,6 +76,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getterButtonPressed:(id)sender
|
||||
{
|
||||
[super getterButtonPressed:sender];
|
||||
id returnedObject = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
|
||||
[self exploreObjectOrPopViewController:returnedObject];
|
||||
}
|
||||
|
||||
- (void)argumentInputViewValueDidChange:(FLEXArgumentInputView *)argumentInputView
|
||||
{
|
||||
if ([argumentInputView isKindOfClass:[FLEXArgumentInputSwitchView class]]) {
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
typedef UIViewController *(^FLEXCustomContentViewerFuture)(NSData *data);
|
||||
|
||||
@interface FLEXManager : NSObject
|
||||
|
||||
+ (instancetype)sharedManager;
|
||||
@@ -77,4 +79,13 @@
|
||||
- (void)registerGlobalEntryWithName:(NSString *)entryName
|
||||
viewControllerFutureBlock:(UIViewController * (^)(void))viewControllerFutureBlock;
|
||||
|
||||
/// Sets custom viewer for specific content type.
|
||||
/// @param contentType Mime type like application/json
|
||||
/// @param viewControllerFutureBlock Viewer (view controller) creation block
|
||||
/// @note This method must be called from the main thread.
|
||||
/// The viewControllerFutureBlock will be invoked from the main thread and may not return nil.
|
||||
/// @note The passed block will be copied and retain for the duration of the application, you may want to use __weak references.
|
||||
- (void)setCustomViewerForContentType:(NSString *)contentType
|
||||
viewControllerFutureBlock:(FLEXCustomContentViewerFuture)viewControllerFutureBlock;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXTableContentHeaderCell.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Peng Tao on 15/11/26.
|
||||
// Copyright © 2015年 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXTableContentHeaderCell.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Peng Tao on 15/11/26.
|
||||
// Copyright © 2015年 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXTableContentCell.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Peng Tao on 15/11/24.
|
||||
// Copyright © 2015年 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXTableContentCell.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Peng Tao on 15/11/24.
|
||||
// Copyright © 2015年 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXTableLeftCell.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Peng Tao on 15/11/24.
|
||||
// Copyright © 2015年 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXTableLeftCell.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Peng Tao on 15/11/24.
|
||||
// Copyright © 2015年 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXFileBrowserSearchOperation.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by 啟倫 陳 on 2014/8/4.
|
||||
// Copyright (c) 2014年 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXFileBrowserSearchOperation.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by 啟倫 陳 on 2014/8/4.
|
||||
// Copyright (c) 2014年 f. All rights reserved.
|
||||
|
||||
@@ -79,6 +79,11 @@
|
||||
{
|
||||
NSMutableArray<FLEXObjectRef *> *instances = [NSMutableArray array];
|
||||
[FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id tryObject, __unsafe_unretained Class actualClass) {
|
||||
// Skip Swift objects
|
||||
if ([actualClass isKindOfClass:NSClassFromString(@"SwiftObject")]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all the ivars on the object. Start with the class and and travel up the inheritance chain.
|
||||
// Once we find a match, record it and move on to the next object. There's no reason to find multiple matches within the same object.
|
||||
Class tryClass = actualClass;
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// Taken from https://github.com/llvm-mirror/lldb/blob/master/tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h
|
||||
// by Tanner Bennett on 03/03/2019 with minimal modifications.
|
||||
//
|
||||
|
||||
//===-- ActivityStreamAPI.h -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ActivityStreamSPI_h
|
||||
#define ActivityStreamSPI_h
|
||||
|
||||
#include <sys/time.h>
|
||||
// #include <xpc/xpc.h>
|
||||
|
||||
/* By default, XPC objects are declared as Objective-C types when building with
|
||||
* an Objective-C compiler. This allows them to participate in ARC, in RR
|
||||
* management by the Blocks runtime and in leaks checking by the static
|
||||
* analyzer, and enables them to be added to Cocoa collections.
|
||||
*
|
||||
* See <os/object.h> for details.
|
||||
*/
|
||||
#if OS_OBJECT_USE_OBJC
|
||||
OS_OBJECT_DECL(xpc_object);
|
||||
#else
|
||||
typedef void * xpc_object_t;
|
||||
#endif
|
||||
|
||||
#define OS_ACTIVITY_MAX_CALLSTACK 32
|
||||
|
||||
// Enums
|
||||
|
||||
typedef NS_ENUM(uint32_t, os_activity_stream_flag_t) {
|
||||
OS_ACTIVITY_STREAM_PROCESS_ONLY = 0x00000001,
|
||||
OS_ACTIVITY_STREAM_SKIP_DECODE = 0x00000002,
|
||||
OS_ACTIVITY_STREAM_PAYLOAD = 0x00000004,
|
||||
OS_ACTIVITY_STREAM_HISTORICAL = 0x00000008,
|
||||
OS_ACTIVITY_STREAM_CALLSTACK = 0x00000010,
|
||||
OS_ACTIVITY_STREAM_DEBUG = 0x00000020,
|
||||
OS_ACTIVITY_STREAM_BUFFERED = 0x00000040,
|
||||
OS_ACTIVITY_STREAM_NO_SENSITIVE = 0x00000080,
|
||||
OS_ACTIVITY_STREAM_INFO = 0x00000100,
|
||||
OS_ACTIVITY_STREAM_PROMISCUOUS = 0x00000200,
|
||||
OS_ACTIVITY_STREAM_PRECISE_TIMESTAMPS = 0x00000200
|
||||
};
|
||||
|
||||
typedef NS_ENUM(uint32_t, os_activity_stream_type_t) {
|
||||
OS_ACTIVITY_STREAM_TYPE_ACTIVITY_CREATE = 0x0201,
|
||||
OS_ACTIVITY_STREAM_TYPE_ACTIVITY_TRANSITION = 0x0202,
|
||||
OS_ACTIVITY_STREAM_TYPE_ACTIVITY_USERACTION = 0x0203,
|
||||
|
||||
OS_ACTIVITY_STREAM_TYPE_TRACE_MESSAGE = 0x0300,
|
||||
|
||||
OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE = 0x0400,
|
||||
OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE = 0x0480,
|
||||
|
||||
OS_ACTIVITY_STREAM_TYPE_SIGNPOST_BEGIN = 0x0601,
|
||||
OS_ACTIVITY_STREAM_TYPE_SIGNPOST_END = 0x0602,
|
||||
OS_ACTIVITY_STREAM_TYPE_SIGNPOST_EVENT = 0x0603,
|
||||
|
||||
OS_ACTIVITY_STREAM_TYPE_STATEDUMP_EVENT = 0x0A00,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(uint32_t, os_activity_stream_event_t) {
|
||||
OS_ACTIVITY_STREAM_EVENT_STARTED = 1,
|
||||
OS_ACTIVITY_STREAM_EVENT_STOPPED = 2,
|
||||
OS_ACTIVITY_STREAM_EVENT_FAILED = 3,
|
||||
OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED = 4,
|
||||
OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED = 5,
|
||||
};
|
||||
|
||||
// Types
|
||||
|
||||
typedef uint64_t os_activity_id_t;
|
||||
typedef struct os_activity_stream_s *os_activity_stream_t;
|
||||
typedef struct os_activity_stream_entry_s *os_activity_stream_entry_t;
|
||||
|
||||
#define OS_ACTIVITY_STREAM_COMMON() \
|
||||
uint64_t trace_id; \
|
||||
uint64_t timestamp; \
|
||||
uint64_t thread; \
|
||||
const uint8_t *image_uuid; \
|
||||
const char *image_path; \
|
||||
struct timeval tv_gmt; \
|
||||
struct timezone tz; \
|
||||
uint32_t offset
|
||||
|
||||
typedef struct os_activity_stream_common_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
} * os_activity_stream_common_t;
|
||||
|
||||
struct os_activity_create_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *name;
|
||||
os_activity_id_t creator_aid;
|
||||
uint64_t unique_pid;
|
||||
};
|
||||
|
||||
struct os_activity_transition_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
os_activity_id_t transition_id;
|
||||
};
|
||||
|
||||
typedef struct os_log_message_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *format;
|
||||
const uint8_t *buffer;
|
||||
size_t buffer_sz;
|
||||
const uint8_t *privdata;
|
||||
size_t privdata_sz;
|
||||
const char *subsystem;
|
||||
const char *category;
|
||||
uint32_t oversize_id;
|
||||
uint8_t ttl;
|
||||
bool persisted;
|
||||
} * os_log_message_t;
|
||||
|
||||
typedef struct os_trace_message_v2_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *format;
|
||||
const void *buffer;
|
||||
size_t bufferLen;
|
||||
xpc_object_t __unsafe_unretained payload;
|
||||
} * os_trace_message_v2_t;
|
||||
|
||||
typedef struct os_activity_useraction_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *action;
|
||||
bool persisted;
|
||||
} * os_activity_useraction_t;
|
||||
|
||||
typedef struct os_signpost_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
const char *format;
|
||||
const uint8_t *buffer;
|
||||
size_t buffer_sz;
|
||||
const uint8_t *privdata;
|
||||
size_t privdata_sz;
|
||||
const char *subsystem;
|
||||
const char *category;
|
||||
uint64_t duration_nsec;
|
||||
uint32_t callstack_depth;
|
||||
uint64_t callstack[OS_ACTIVITY_MAX_CALLSTACK];
|
||||
} * os_signpost_t;
|
||||
|
||||
typedef struct os_activity_statedump_s {
|
||||
OS_ACTIVITY_STREAM_COMMON();
|
||||
char *message;
|
||||
size_t message_size;
|
||||
char image_path_buffer[PATH_MAX];
|
||||
} * os_activity_statedump_t;
|
||||
|
||||
struct os_activity_stream_entry_s {
|
||||
os_activity_stream_type_t type;
|
||||
|
||||
// information about the process streaming the data
|
||||
pid_t pid;
|
||||
uint64_t proc_id;
|
||||
const uint8_t *proc_imageuuid;
|
||||
const char *proc_imagepath;
|
||||
|
||||
// the activity associated with this streamed event
|
||||
os_activity_id_t activity_id;
|
||||
os_activity_id_t parent_id;
|
||||
|
||||
union {
|
||||
struct os_activity_stream_common_s common;
|
||||
struct os_activity_create_s activity_create;
|
||||
struct os_activity_transition_s activity_transition;
|
||||
struct os_log_message_s log_message;
|
||||
struct os_trace_message_v2_s trace_message;
|
||||
struct os_activity_useraction_s useraction;
|
||||
struct os_signpost_s signpost;
|
||||
struct os_activity_statedump_s statedump;
|
||||
};
|
||||
};
|
||||
|
||||
// Blocks
|
||||
|
||||
typedef bool (^os_activity_stream_block_t)(os_activity_stream_entry_t entry,
|
||||
int error);
|
||||
|
||||
typedef void (^os_activity_stream_event_block_t)(
|
||||
os_activity_stream_t stream, os_activity_stream_event_t event);
|
||||
|
||||
// SPI entry point prototypes
|
||||
|
||||
typedef os_activity_stream_t (*os_activity_stream_for_pid_t)(
|
||||
pid_t pid, os_activity_stream_flag_t flags,
|
||||
os_activity_stream_block_t stream_block);
|
||||
|
||||
typedef void (*os_activity_stream_resume_t)(os_activity_stream_t stream);
|
||||
|
||||
typedef void (*os_activity_stream_cancel_t)(os_activity_stream_t stream);
|
||||
|
||||
typedef char *(*os_log_copy_formatted_message_t)(os_log_message_t log_message);
|
||||
|
||||
typedef void (*os_activity_stream_set_event_handler_t)(
|
||||
os_activity_stream_t stream, os_activity_stream_event_block_t block);
|
||||
|
||||
#endif /* ActivityStreamSPI_h */
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FLEXASLLogController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 3/14/19.
|
||||
// Copyright © 2019 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXLogController.h"
|
||||
|
||||
@interface FLEXASLLogController : NSObject <FLEXLogController>
|
||||
|
||||
/// Guaranteed to call back on the main thread.
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler;
|
||||
|
||||
- (BOOL)startMonitoring;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// FLEXASLLogController.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 3/14/19.
|
||||
// Copyright © 2019 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXASLLogController.h"
|
||||
#import <asl.h>
|
||||
|
||||
// Querrying the ASL is much slower in the simulator. We need a longer polling interval to keep things repsonsive.
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
#define updateInterval 5.0
|
||||
#else
|
||||
#define updateInterval 1.0
|
||||
#endif
|
||||
|
||||
@interface FLEXASLLogController ()
|
||||
|
||||
@property (nonatomic, readonly) void (^updateHandler)(NSArray<FLEXSystemLogMessage *> *);
|
||||
|
||||
@property (nonatomic, strong) NSTimer *logUpdateTimer;
|
||||
@property (nonatomic, readonly) NSMutableIndexSet *logMessageIdentifiers;
|
||||
|
||||
// ASL stuff
|
||||
|
||||
@property (nonatomic) NSUInteger heapSize;
|
||||
@property (nonatomic) dispatch_queue_t logQueue;
|
||||
@property (nonatomic) dispatch_io_t io;
|
||||
@property (nonatomic) NSString *remaining;
|
||||
@property (nonatomic) int stderror;
|
||||
@property (nonatomic) NSString *lastTimestamp;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXASLLogController
|
||||
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler
|
||||
{
|
||||
return [[self alloc] initWithUpdateHandler:newMessagesHandler];
|
||||
}
|
||||
|
||||
- (id)initWithUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler
|
||||
{
|
||||
NSParameterAssert(newMessagesHandler);
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_updateHandler = newMessagesHandler;
|
||||
_logMessageIdentifiers = [NSMutableIndexSet indexSet];
|
||||
self.logUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:updateInterval
|
||||
target:self
|
||||
selector:@selector(updateLogMessages)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self.logUpdateTimer invalidate];
|
||||
}
|
||||
|
||||
- (BOOL)startMonitoring {
|
||||
[self.logUpdateTimer fire];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)updateLogMessages
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray<FLEXSystemLogMessage *> *newMessages;
|
||||
@synchronized (self) {
|
||||
newMessages = [self newLogMessagesForCurrentProcess];
|
||||
if (!newMessages.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (FLEXSystemLogMessage *message in newMessages) {
|
||||
[self.logMessageIdentifiers addIndex:(NSUInteger)message.messageID];
|
||||
}
|
||||
|
||||
self.lastTimestamp = @(asl_get(newMessages.lastObject.aslMessage, ASL_KEY_TIME));
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.updateHandler(newMessages);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Log Message Fetching
|
||||
|
||||
- (NSArray<FLEXSystemLogMessage *> *)newLogMessagesForCurrentProcess
|
||||
{
|
||||
if (!self.logMessageIdentifiers.count) {
|
||||
return [self allLogMessagesForCurrentProcess];
|
||||
}
|
||||
|
||||
aslresponse response = [self ASLMessageListForCurrentProcess];
|
||||
aslmsg aslMessage = NULL;
|
||||
|
||||
NSMutableArray<FLEXSystemLogMessage *> *newMessages = [NSMutableArray array];
|
||||
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
NSUInteger messageID = (NSUInteger)atoll(asl_get(aslMessage, ASL_KEY_MSG_ID));
|
||||
if (![self.logMessageIdentifiers containsIndex:messageID]) {
|
||||
[newMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
}
|
||||
|
||||
asl_release(response);
|
||||
return newMessages;
|
||||
}
|
||||
|
||||
- (aslresponse)ASLMessageListForCurrentProcess
|
||||
{
|
||||
static NSString *pidString = nil;
|
||||
if (!pidString) {
|
||||
pidString = @([[NSProcessInfo processInfo] processIdentifier]).stringValue;
|
||||
}
|
||||
|
||||
// Create system log query object.
|
||||
asl_object_t query = asl_new(ASL_TYPE_QUERY);
|
||||
|
||||
// Filter for messages from the current process.
|
||||
// Note that this appears to happen by default on device, but is required in the simulator.
|
||||
asl_set_query(query, ASL_KEY_PID, pidString.UTF8String, ASL_QUERY_OP_EQUAL);
|
||||
// Filter for messages after the last retreived message.
|
||||
if (self.lastTimestamp) {
|
||||
asl_set_query(query, ASL_KEY_TIME, self.lastTimestamp.UTF8String, ASL_QUERY_OP_GREATER);
|
||||
}
|
||||
|
||||
return asl_search(NULL, query);
|
||||
}
|
||||
|
||||
- (NSArray<FLEXSystemLogMessage *> *)allLogMessagesForCurrentProcess
|
||||
{
|
||||
aslresponse response = [self ASLMessageListForCurrentProcess];
|
||||
aslmsg aslMessage = NULL;
|
||||
|
||||
NSMutableArray<FLEXSystemLogMessage *> *logMessages = [NSMutableArray array];
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
[logMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
asl_release(response);
|
||||
|
||||
return logMessages;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// FLEXLogController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 3/17/19.
|
||||
// Copyright © 2019 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FLEXSystemLogMessage.h"
|
||||
|
||||
@protocol FLEXLogController <NSObject>
|
||||
|
||||
/// Guaranteed to call back on the main thread.
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler;
|
||||
|
||||
- (BOOL)startMonitoring;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// FLEXOSLogController.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 12/19/18.
|
||||
// Copyright © 2018 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXLogController.h"
|
||||
|
||||
#define FLEXOSLogAvailable() ([NSProcessInfo processInfo].operatingSystemVersion.majorVersion >= 10)
|
||||
|
||||
extern NSString * const kFLEXiOSPersistentOSLogKey;
|
||||
|
||||
/// The log controller used for iOS 10 and up.
|
||||
@interface FLEXOSLogController : NSObject <FLEXLogController>
|
||||
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler;
|
||||
|
||||
- (BOOL)startMonitoring;
|
||||
|
||||
/// Whether log messages are to be recorded and kept in-memory in the background.
|
||||
/// You do not need to initialize this value, only change it.
|
||||
@property (nonatomic) BOOL persistent;
|
||||
/// Used mostly internally, but also used by the log VC to persist messages
|
||||
/// that were created prior to enabling persistence.
|
||||
@property (nonatomic) NSMutableArray<FLEXSystemLogMessage *> *messages;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// FLEXOSLogController.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 12/19/18.
|
||||
// Copyright © 2018 Flipboard. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXOSLogController.h"
|
||||
#include <dlfcn.h>
|
||||
#include "ActivityStreamAPI.h"
|
||||
|
||||
NSString * const kFLEXiOSPersistentOSLogKey = @"com.flex.enablePersistentOSLogLogging";
|
||||
|
||||
static os_activity_stream_for_pid_t OSActivityStreamForPID;
|
||||
static os_activity_stream_resume_t OSActivityStreamResume;
|
||||
static os_activity_stream_cancel_t OSActivityStreamCancel;
|
||||
static os_log_copy_formatted_message_t OSLogCopyFormattedMessage;
|
||||
static os_activity_stream_set_event_handler_t OSActivityStreamSetEventHandler;
|
||||
static int (*proc_name)(int, char *, unsigned int);
|
||||
static int (*proc_listpids)(uint32_t, uint32_t, void*, int);
|
||||
static uint8_t (*OSLogGetType)(void *);
|
||||
|
||||
@interface FLEXOSLogController ()
|
||||
|
||||
+ (FLEXOSLogController *)sharedLogController;
|
||||
|
||||
@property (nonatomic) void (^updateHandler)(NSArray<FLEXSystemLogMessage *> *);
|
||||
|
||||
@property (nonatomic) BOOL canPrint;
|
||||
@property (nonatomic) int filterPid;
|
||||
@property (nonatomic) BOOL levelInfo;
|
||||
@property (nonatomic) BOOL subsystemInfo;
|
||||
|
||||
@property (nonatomic) os_activity_stream_t stream;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXOSLogController
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
// Persist logs when the app launches on iOS 10 if we have persitent logs turned on
|
||||
if (FLEXOSLogAvailable()) {
|
||||
BOOL persistent = [[NSUserDefaults standardUserDefaults] boolForKey:kFLEXiOSPersistentOSLogKey];
|
||||
if (persistent) {
|
||||
[self sharedLogController].persistent = YES;
|
||||
[[self sharedLogController] startMonitoring];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (instancetype)sharedLogController {
|
||||
static FLEXOSLogController *shared = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
shared = [self new];
|
||||
});
|
||||
|
||||
return shared;
|
||||
}
|
||||
|
||||
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler
|
||||
{
|
||||
FLEXOSLogController *shared = [self sharedLogController];
|
||||
shared.updateHandler = newMessagesHandler;
|
||||
return shared;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
NSAssert(FLEXOSLogAvailable(), @"os_log is only available on iOS 10 and up");
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_filterPid = [NSProcessInfo processInfo].processIdentifier;
|
||||
_levelInfo = NO;
|
||||
_subsystemInfo = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
OSActivityStreamCancel(self.stream);
|
||||
_stream = nil;
|
||||
}
|
||||
|
||||
- (void)setPersistent:(BOOL)persistent {
|
||||
if (_persistent == persistent) return;
|
||||
|
||||
_persistent = persistent;
|
||||
self.messages = persistent ? [NSMutableArray array] : nil;
|
||||
}
|
||||
|
||||
- (BOOL)startMonitoring {
|
||||
if (![self lookupSPICalls]) {
|
||||
// >= iOS 10 is required
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Are we already monitoring?
|
||||
if (self.stream) {
|
||||
// Should we send out the "persisted" messages?
|
||||
if (self.updateHandler && self.messages.count) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.updateHandler(self.messages);
|
||||
});
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Stream entry handler
|
||||
os_activity_stream_block_t block = ^bool(os_activity_stream_entry_t entry, int error) {
|
||||
return [self handleStreamEntry:entry error:error];
|
||||
};
|
||||
|
||||
// Controls which types of messages we see
|
||||
// 'Historical' appears to just show NSLog stuff
|
||||
uint32_t activity_stream_flags = OS_ACTIVITY_STREAM_HISTORICAL;
|
||||
activity_stream_flags |= OS_ACTIVITY_STREAM_PROCESS_ONLY;
|
||||
// activity_stream_flags |= OS_ACTIVITY_STREAM_PROCESS_ONLY;
|
||||
|
||||
self.stream = OSActivityStreamForPID(self.filterPid, activity_stream_flags, block);
|
||||
|
||||
// Specify the stream-related event handler
|
||||
OSActivityStreamSetEventHandler(self.stream, [self streamEventHandlerBlock]);
|
||||
// Start the stream
|
||||
OSActivityStreamResume(self.stream);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)lookupSPICalls {
|
||||
static BOOL hasSPI = NO;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
void *handle = dlopen("/System/Library/PrivateFrameworks/LoggingSupport.framework/LoggingSupport", RTLD_NOW);
|
||||
|
||||
OSActivityStreamForPID = (os_activity_stream_for_pid_t)dlsym(handle, "os_activity_stream_for_pid");
|
||||
OSActivityStreamResume = (os_activity_stream_resume_t)dlsym(handle, "os_activity_stream_resume");
|
||||
OSActivityStreamCancel = (os_activity_stream_cancel_t)dlsym(handle, "os_activity_stream_cancel");
|
||||
OSLogCopyFormattedMessage = (os_log_copy_formatted_message_t)dlsym(handle, "os_log_copy_formatted_message");
|
||||
OSActivityStreamSetEventHandler = (os_activity_stream_set_event_handler_t)dlsym(handle, "os_activity_stream_set_event_handler");
|
||||
proc_name = (int(*)(int, char *, unsigned int))dlsym(handle, "proc_name");
|
||||
proc_listpids = (int(*)(uint32_t, uint32_t, void*, int))dlsym(handle, "proc_listpids");
|
||||
OSLogGetType = (uint8_t(*)(void *))dlsym(handle, "os_log_get_type");
|
||||
|
||||
hasSPI = (OSActivityStreamForPID != NULL) &&
|
||||
(OSActivityStreamResume != NULL) &&
|
||||
(OSActivityStreamCancel != NULL) &&
|
||||
(OSLogCopyFormattedMessage != NULL) &&
|
||||
(OSActivityStreamSetEventHandler != NULL) &&
|
||||
(OSLogGetType != NULL) &&
|
||||
(proc_name != NULL);
|
||||
});
|
||||
|
||||
return hasSPI;
|
||||
}
|
||||
|
||||
- (BOOL)handleStreamEntry:(os_activity_stream_entry_t)entry error:(int)error {
|
||||
if (!self.canPrint || (self.filterPid != -1 && entry->pid != self.filterPid)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (!error && entry) {
|
||||
if (entry->type == OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE ||
|
||||
entry->type == OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE) {
|
||||
os_log_message_t log_message = &entry->log_message;
|
||||
|
||||
// Get date
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:log_message->tv_gmt.tv_sec];
|
||||
|
||||
// Get log message text
|
||||
const char *messageText = OSLogCopyFormattedMessage(log_message);
|
||||
// https://github.com/limneos/oslog/issues/1
|
||||
if (entry->log_message.format && !(strcmp(entry->log_message.format, messageText))) {
|
||||
messageText = (char *)entry->log_message.format;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
FLEXSystemLogMessage *message = [FLEXSystemLogMessage logMessageFromDate:date text:@(messageText)];
|
||||
if (self.persistent) {
|
||||
[self.messages addObject:message];
|
||||
}
|
||||
if (self.updateHandler) {
|
||||
self.updateHandler(@[message]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (os_activity_stream_event_block_t)streamEventHandlerBlock {
|
||||
return [^void(os_activity_stream_t stream, os_activity_stream_event_t event) {
|
||||
switch (event) {
|
||||
case OS_ACTIVITY_STREAM_EVENT_STARTED:
|
||||
self.canPrint = YES;
|
||||
break;
|
||||
case OS_ACTIVITY_STREAM_EVENT_STOPPED:
|
||||
break;
|
||||
case OS_ACTIVITY_STREAM_EVENT_FAILED:
|
||||
break;
|
||||
case OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED:
|
||||
break;
|
||||
case OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED:
|
||||
break;
|
||||
default:
|
||||
printf("=== Unhandled case ===\n");
|
||||
break;
|
||||
}
|
||||
} copy];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXSystemLogMessage.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/25/15.
|
||||
// Copyright (c) 2015 f. All rights reserved.
|
||||
@@ -8,14 +8,24 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <asl.h>
|
||||
#import "ActivityStreamAPI.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FLEXSystemLogMessage : NSObject
|
||||
|
||||
+ (instancetype)logMessageFromASLMessage:(aslmsg)aslMessage;
|
||||
//+ (instancetype)logMessageFromOSLog:(os_log_message_t)logMessage;
|
||||
+ (instancetype)logMessageFromDate:(NSDate *)date text:(NSString *)text;
|
||||
|
||||
@property (nonatomic, strong) NSDate *date;
|
||||
@property (nonatomic, copy) NSString *sender;
|
||||
@property (nonatomic, copy) NSString *messageText;
|
||||
@property (nonatomic, assign) long long messageID;
|
||||
// ASL specific properties
|
||||
@property (nonatomic, readonly, nullable) NSString *sender;
|
||||
@property (nonatomic, readonly, nullable) aslmsg aslMessage;
|
||||
|
||||
@property (nonatomic, readonly) NSDate *date;
|
||||
@property (nonatomic, readonly) NSString *messageText;
|
||||
@property (nonatomic, readonly) long long messageID;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXSystemLogMessage.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/25/15.
|
||||
// Copyright (c) 2015 f. All rights reserved.
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
+ (instancetype)logMessageFromASLMessage:(aslmsg)aslMessage
|
||||
{
|
||||
FLEXSystemLogMessage *logMessage = [[FLEXSystemLogMessage alloc] init];
|
||||
NSDate *date = nil;
|
||||
NSString *sender = nil, *text = nil;
|
||||
long long identifier = 0;
|
||||
|
||||
const char *timestamp = asl_get(aslMessage, ASL_KEY_TIME);
|
||||
if (timestamp) {
|
||||
@@ -21,30 +23,67 @@
|
||||
if (nanoseconds) {
|
||||
timeInterval += [@(nanoseconds) doubleValue] / NSEC_PER_SEC;
|
||||
}
|
||||
logMessage.date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
|
||||
date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
|
||||
}
|
||||
|
||||
const char *sender = asl_get(aslMessage, ASL_KEY_SENDER);
|
||||
if (sender) {
|
||||
logMessage.sender = @(sender);
|
||||
const char *s = asl_get(aslMessage, ASL_KEY_SENDER);
|
||||
if (s) {
|
||||
sender = @(s);
|
||||
}
|
||||
|
||||
const char *messageText = asl_get(aslMessage, ASL_KEY_MSG);
|
||||
if (messageText) {
|
||||
logMessage.messageText = @(messageText);
|
||||
text = @(messageText);
|
||||
}
|
||||
|
||||
const char *messageID = asl_get(aslMessage, ASL_KEY_MSG_ID);
|
||||
if (messageID) {
|
||||
logMessage.messageID = [@(messageID) longLongValue];
|
||||
identifier = [@(messageID) longLongValue];
|
||||
}
|
||||
|
||||
return logMessage;
|
||||
FLEXSystemLogMessage *message = [[self alloc] initWithDate:date sender:sender text:text messageID:identifier];
|
||||
message->_aslMessage = aslMessage;
|
||||
return message;
|
||||
}
|
||||
|
||||
+ (instancetype)logMessageFromOSLog:(os_log_message_t)logMessage
|
||||
{
|
||||
abort();
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (instancetype)logMessageFromDate:(NSDate *)date text:(NSString *)text
|
||||
{
|
||||
return [[self alloc] initWithDate:date sender:nil text:text messageID:0];
|
||||
}
|
||||
|
||||
- (id)initWithDate:(NSDate *)date sender:(NSString *)sender text:(NSString *)text messageID:(long long)identifier
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_date = date;
|
||||
_sender = sender;
|
||||
_messageText = text;
|
||||
_messageID = identifier;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
return [object isKindOfClass:[FLEXSystemLogMessage class]] && self.messageID == [object messageID];
|
||||
if ([object isKindOfClass:[self class]]) {
|
||||
if (self.messageID) {
|
||||
// Only ASL uses messageID, otherwise it is 0
|
||||
return self.messageID == [object messageID];
|
||||
} else {
|
||||
// Test message texts and dates for OS Log
|
||||
return [self.messageText isEqual:[object messageText]] &&
|
||||
[self.date isEqualToDate:[object date]];
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
@@ -52,4 +91,10 @@
|
||||
return (NSUInteger)self.messageID;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
NSString *escaped = [self.messageText stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
|
||||
return [NSString stringWithFormat:@"(%lu) %@", self.messageText.length, escaped];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXSystemLogTableViewCell.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/25/15.
|
||||
// Copyright (c) 2015 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXSystemLogTableViewCell.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/25/15.
|
||||
// Copyright (c) 2015 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXSystemLogTableViewController.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/19/15.
|
||||
// Copyright (c) 2015 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXSystemLogTableViewController.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 1/19/15.
|
||||
// Copyright (c) 2015 f. All rights reserved.
|
||||
@@ -8,17 +8,16 @@
|
||||
|
||||
#import "FLEXSystemLogTableViewController.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXSystemLogMessage.h"
|
||||
#import "FLEXASLLogController.h"
|
||||
#import "FLEXOSLogController.h"
|
||||
#import "FLEXSystemLogTableViewCell.h"
|
||||
#import <asl.h>
|
||||
|
||||
@interface FLEXSystemLogTableViewController () <UISearchResultsUpdating, UISearchControllerDelegate>
|
||||
|
||||
@property (nonatomic, strong) UISearchController *searchController;
|
||||
@property (nonatomic, readonly) id<FLEXLogController> logController;
|
||||
@property (nonatomic, readonly) NSMutableArray<FLEXSystemLogMessage *> *logMessages;
|
||||
@property (nonatomic, copy) NSArray<FLEXSystemLogMessage *> *filteredLogMessages;
|
||||
@property (nonatomic, strong) NSTimer *logUpdateTimer;
|
||||
@property (nonatomic, readonly) NSMutableIndexSet *logMessageIdentifiers;
|
||||
|
||||
@end
|
||||
|
||||
@@ -28,68 +27,56 @@
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
id logHandler = ^(NSArray<FLEXSystemLogMessage *> *newMessages) {
|
||||
self.title = @"System Log";
|
||||
|
||||
[self.logMessages addObjectsFromArray:newMessages];
|
||||
|
||||
// "Follow" the log as new messages stream in if we were previously near the bottom.
|
||||
BOOL wasNearBottom = self.tableView.contentOffset.y >= self.tableView.contentSize.height - self.tableView.frame.size.height - 100.0;
|
||||
[self.tableView reloadData];
|
||||
if (wasNearBottom) {
|
||||
[self scrollToLastRow];
|
||||
}
|
||||
};
|
||||
|
||||
_logMessages = [NSMutableArray array];
|
||||
_logMessageIdentifiers = [NSMutableIndexSet indexSet];
|
||||
if ([NSProcessInfo processInfo].operatingSystemVersion.majorVersion <= 9) {
|
||||
_logController = [FLEXASLLogController withUpdateHandler:logHandler];
|
||||
} else {
|
||||
_logController = [FLEXOSLogController withUpdateHandler:logHandler];
|
||||
}
|
||||
|
||||
[self.tableView registerClass:[FLEXSystemLogTableViewCell class] forCellReuseIdentifier:kFLEXSystemLogTableViewCellIdentifier];
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
self.title = @"Loading...";
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@" ⬇︎ " style:UIBarButtonItemStylePlain target:self action:@selector(scrollToLastRow)];
|
||||
|
||||
|
||||
UIBarButtonItem *scrollDown = [[UIBarButtonItem alloc] initWithTitle:@" ⬇︎ "
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(scrollToLastRow)];
|
||||
UIBarButtonItem *settings = [[UIBarButtonItem alloc] initWithTitle:@"Settings"
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(showLogSettings)];
|
||||
if (FLEXOSLogAvailable()) {
|
||||
self.navigationItem.rightBarButtonItems = @[scrollDown, settings];
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItem = scrollDown;
|
||||
}
|
||||
|
||||
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
|
||||
self.searchController.delegate = self;
|
||||
self.searchController.searchResultsUpdater = self;
|
||||
self.searchController.dimsBackgroundDuringPresentation = NO;
|
||||
self.tableView.tableHeaderView = self.searchController.searchBar;
|
||||
|
||||
[self updateLogMessages];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
NSTimeInterval updateInterval = 1.0;
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
// Querrying the ASL is much slower in the simulator. We need a longer polling interval to keep things repsonsive.
|
||||
updateInterval = 5.0;
|
||||
#endif
|
||||
|
||||
self.logUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:updateInterval target:self selector:@selector(updateLogMessages) userInfo:nil repeats:YES];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
[self.logUpdateTimer invalidate];
|
||||
}
|
||||
|
||||
- (void)updateLogMessages
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray<FLEXSystemLogMessage *> *newMessages = [self newLogMessagesForCurrentProcess];
|
||||
if (!newMessages.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.title = @"System Log";
|
||||
|
||||
[self.logMessages addObjectsFromArray:newMessages];
|
||||
for (FLEXSystemLogMessage *message in newMessages) {
|
||||
[self.logMessageIdentifiers addIndex:(NSUInteger)message.messageID];
|
||||
}
|
||||
|
||||
// "Follow" the log as new messages stream in if we were previously near the bottom.
|
||||
BOOL wasNearBottom = self.tableView.contentOffset.y >= self.tableView.contentSize.height - self.tableView.frame.size.height - 100.0;
|
||||
[self.tableView reloadData];
|
||||
if (wasNearBottom) {
|
||||
[self scrollToLastRow];
|
||||
}
|
||||
});
|
||||
});
|
||||
[self.logController startMonitoring];
|
||||
}
|
||||
|
||||
- (void)scrollToLastRow
|
||||
@@ -101,6 +88,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showLogSettings
|
||||
{
|
||||
FLEXOSLogController *logController = (FLEXOSLogController *)self.logController;
|
||||
BOOL persistent = [[NSUserDefaults standardUserDefaults] boolForKey:kFLEXiOSPersistentOSLogKey];
|
||||
NSString *toggle = persistent ? @"Disable" : @"Enable";
|
||||
NSString *title = [@"Persistent logging: " stringByAppendingString:persistent ? @"ON" : @"OFF"];
|
||||
NSString *body = @"In iOS 10 and up, ASL is gone. The OS Log API is much more limited. "
|
||||
"To get as close to the old behavior as possible, logs must be collected manually at launch and stored.\n\n"
|
||||
"Turn this feature on only when you need it.";
|
||||
|
||||
UIAlertController *settings = [UIAlertController alertControllerWithTitle:title message:body preferredStyle:UIAlertControllerStyleAlert];
|
||||
[settings addAction:[UIAlertAction actionWithTitle:toggle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:!persistent forKey:kFLEXiOSPersistentOSLogKey];
|
||||
logController.persistent = !persistent;
|
||||
[logController.messages addObjectsFromArray:self.logMessages];
|
||||
}]];
|
||||
[settings addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleCancel handler:nil]];
|
||||
|
||||
[self presentViewController:settings animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
@@ -110,7 +118,7 @@
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.searchController.isActive ? [self.filteredLogMessages count] : [self.logMessages count];
|
||||
return self.searchController.isActive ? self.filteredLogMessages.count : self.logMessages.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
@@ -149,9 +157,8 @@
|
||||
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
|
||||
{
|
||||
if (action == @selector(copy:)) {
|
||||
FLEXSystemLogMessage *logMessage = [self logMessageAtIndexPath:indexPath];
|
||||
NSString *stringToCopy = [FLEXSystemLogTableViewCell displayedTextForLogMessage:logMessage] ?: @"";
|
||||
[[UIPasteboard generalPasteboard] setString:stringToCopy];
|
||||
// We usually only want to copy the log message itself, not any metadata associated with it.
|
||||
[UIPasteboard generalPasteboard].string = [self logMessageAtIndexPath:indexPath].messageText;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,59 +186,4 @@
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Log Message Fetching
|
||||
|
||||
- (NSArray<FLEXSystemLogMessage *> *)newLogMessagesForCurrentProcess
|
||||
{
|
||||
if (!self.logMessages.count) {
|
||||
return [[self class] allLogMessagesForCurrentProcess];
|
||||
}
|
||||
|
||||
aslresponse response = [FLEXSystemLogTableViewController ASLMessageListForCurrentProcess];
|
||||
aslmsg aslMessage = NULL;
|
||||
|
||||
NSMutableArray<FLEXSystemLogMessage *> *newMessages = [NSMutableArray array];
|
||||
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
NSUInteger messageID = (NSUInteger)atoll(asl_get(aslMessage, ASL_KEY_MSG_ID));
|
||||
if (![self.logMessageIdentifiers containsIndex:messageID]) {
|
||||
[newMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
}
|
||||
|
||||
asl_release(response);
|
||||
return newMessages;
|
||||
}
|
||||
|
||||
+ (aslresponse)ASLMessageListForCurrentProcess
|
||||
{
|
||||
static NSString *pidString = nil;
|
||||
if (!pidString) {
|
||||
pidString = @([[NSProcessInfo processInfo] processIdentifier]).stringValue;
|
||||
}
|
||||
|
||||
// Create system log query object.
|
||||
asl_object_t query = asl_new(ASL_TYPE_QUERY);
|
||||
|
||||
// Filter for messages from the current process.
|
||||
// Note that this appears to happen by default on device, but is required in the simulator.
|
||||
asl_set_query(query, ASL_KEY_PID, pidString.UTF8String, ASL_QUERY_OP_EQUAL);
|
||||
|
||||
return asl_search(NULL, query);
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXSystemLogMessage *> *)allLogMessagesForCurrentProcess
|
||||
{
|
||||
aslresponse response = [self ASLMessageListForCurrentProcess];
|
||||
aslmsg aslMessage = NULL;
|
||||
|
||||
NSMutableArray<FLEXSystemLogMessage *> *logMessages = [NSMutableArray array];
|
||||
while ((aslMessage = asl_next(response))) {
|
||||
[logMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
||||
}
|
||||
asl_release(response);
|
||||
|
||||
return logMessages;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
==============================================================================
|
||||
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
|
||||
==============================================================================
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
---- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
||||
==============================================================================
|
||||
Software from third parties included in the LLVM Project:
|
||||
==============================================================================
|
||||
The LLVM Project contains third party software which is under different license
|
||||
terms. All such code will be identified clearly using at least one of two
|
||||
mechanisms:
|
||||
1) It will be in a separate directory tree with its own `LICENSE.txt` or
|
||||
`LICENSE` file at the top containing the specific license and restrictions
|
||||
which apply to that software, or
|
||||
2) It will contain specific license and restriction terms at the top of every
|
||||
file.
|
||||
|
||||
==============================================================================
|
||||
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2010 Apple Inc.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLDB Team
|
||||
|
||||
http://lldb.llvm.org/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLDB Team, copyright holders, nor the names of
|
||||
its contributors may be used to endorse or promote products derived from
|
||||
this Software without specific prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -15,4 +15,6 @@
|
||||
/// An array of FLEXGlobalsTableViewControllerEntry objects that have been registered by the user.
|
||||
@property (nonatomic, readonly, strong) NSArray<FLEXGlobalsTableViewControllerEntry *> *userGlobalEntries;
|
||||
|
||||
@property (nonatomic, readonly, strong) NSDictionary<NSString *, FLEXCustomContentViewerFuture> *customContentTypeViewers;
|
||||
|
||||
@end
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
@property (nonatomic, strong) FLEXExplorerViewController *explorerViewController;
|
||||
|
||||
@property (nonatomic, readonly, strong) NSMutableArray<FLEXGlobalsTableViewControllerEntry *> *userGlobalEntries;
|
||||
@property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, FLEXCustomContentViewerFuture> *customContentTypeViewers;
|
||||
|
||||
@end
|
||||
|
||||
@@ -45,6 +46,7 @@
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_userGlobalEntries = [NSMutableArray array];
|
||||
_customContentTypeViewers = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -288,6 +290,15 @@
|
||||
[self.userGlobalEntries addObject:entry];
|
||||
}
|
||||
|
||||
- (void)setCustomViewerForContentType:(NSString *)contentType viewControllerFutureBlock:(FLEXCustomContentViewerFuture)viewControllerFutureBlock
|
||||
{
|
||||
NSParameterAssert(contentType.length);
|
||||
NSParameterAssert(viewControllerFutureBlock);
|
||||
NSAssert([NSThread isMainThread], @"This method must be called from the main thread.");
|
||||
|
||||
self.customContentTypeViewers[contentType.lowercaseString] = viewControllerFutureBlock;
|
||||
}
|
||||
|
||||
- (void)tryScrollDown
|
||||
{
|
||||
UIScrollView *firstScrollView = [self firstScrollView];
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#import "FLEXImagePreviewViewController.h"
|
||||
#import "FLEXMultilineTableViewCell.h"
|
||||
#import "FLEXUtility.h"
|
||||
#import "FLEXManager+Private.h"
|
||||
|
||||
typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
@@ -425,6 +426,16 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
+ (UIViewController *)detailViewControllerForMIMEType:(NSString *)mimeType data:(NSData *)data
|
||||
{
|
||||
FLEXCustomContentViewerFuture makeCustomViewer = [FLEXManager sharedManager].customContentTypeViewers[mimeType.lowercaseString];
|
||||
|
||||
if (makeCustomViewer) {
|
||||
UIViewController *viewer = makeCustomViewer(data);
|
||||
|
||||
if (viewer) {
|
||||
return viewer;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME (RKO): Don't rely on UTF8 string encoding
|
||||
UIViewController *detailViewController = nil;
|
||||
if ([FLEXUtility isValidJSONData:data]) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXGlobalsTableViewControllerEntry.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Javier Soto on 7/26/14.
|
||||
// Copyright (c) 2014 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXGlobalsTableViewControllerEntry.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Javier Soto on 7/26/14.
|
||||
// Copyright (c) 2014 f. All rights reserved.
|
||||
@@ -22,4 +22,4 @@
|
||||
return entry;
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXLayerExplorerViewController.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 12/14/14.
|
||||
// Copyright (c) 2014 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXLayerExplorerViewController.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 12/14/14.
|
||||
// Copyright (c) 2014 f. All rights reserved.
|
||||
|
||||
@@ -367,7 +367,10 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
|
||||
id value = nil;
|
||||
if ([self canHaveInstanceState]) {
|
||||
FLEXPropertyBox *propertyBox = self.filteredProperties[index];
|
||||
NSString *typeString = [FLEXRuntimeUtility typeEncodingForProperty:propertyBox.property];
|
||||
const FLEXTypeEncoding *encoding = [typeString cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
value = [FLEXRuntimeUtility valueForProperty:propertyBox.property onObject:self.object];
|
||||
value = [FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:value type:encoding];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -449,7 +452,9 @@ typedef NS_ENUM(NSUInteger, FLEXMetadataKind) {
|
||||
id value = nil;
|
||||
if ([self canHaveInstanceState]) {
|
||||
FLEXIvarBox *ivarBox = self.filteredIvars[index];
|
||||
const FLEXTypeEncoding *encoding = ivar_getTypeEncoding(ivarBox.ivar);
|
||||
value = [FLEXRuntimeUtility valueForIvar:ivarBox.ivar onObject:self.object];
|
||||
value = [FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:value type:encoding];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
APPLE PUBLIC SOURCE LICENSE
|
||||
Version 2.0 - August 6, 2003
|
||||
|
||||
Please read this License carefully before downloading this software.
|
||||
By downloading or using this software, you are agreeing to be bound by
|
||||
the terms of this License. If you do not or cannot agree to the terms
|
||||
of this License, please do not download or use the software.
|
||||
|
||||
1. General; Definitions. This License applies to any program or other
|
||||
work which Apple Computer, Inc. ("Apple") makes publicly available and
|
||||
which contains a notice placed by Apple identifying such program or
|
||||
work as "Original Code" and stating that it is subject to the terms of
|
||||
this Apple Public Source License version 2.0 ("License"). As used in
|
||||
this License:
|
||||
|
||||
1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
|
||||
the grantor of rights, (i) claims of patents that are now or hereafter
|
||||
acquired, owned by or assigned to Apple and (ii) that cover subject
|
||||
matter contained in the Original Code, but only to the extent
|
||||
necessary to use, reproduce and/or distribute the Original Code
|
||||
without infringement; and (b) in the case where You are the grantor of
|
||||
rights, (i) claims of patents that are now or hereafter acquired,
|
||||
owned by or assigned to You and (ii) that cover subject matter in Your
|
||||
Modifications, taken alone or in combination with Original Code.
|
||||
|
||||
1.2 "Contributor" means any person or entity that creates or
|
||||
contributes to the creation of Modifications.
|
||||
|
||||
1.3 "Covered Code" means the Original Code, Modifications, the
|
||||
combination of Original Code and any Modifications, and/or any
|
||||
respective portions thereof.
|
||||
|
||||
1.4 "Externally Deploy" means: (a) to sublicense, distribute or
|
||||
otherwise make Covered Code available, directly or indirectly, to
|
||||
anyone other than You; and/or (b) to use Covered Code, alone or as
|
||||
part of a Larger Work, in any way to provide a service, including but
|
||||
not limited to delivery of content, through electronic communication
|
||||
with a client other than You.
|
||||
|
||||
1.5 "Larger Work" means a work which combines Covered Code or portions
|
||||
thereof with code not governed by the terms of this License.
|
||||
|
||||
1.6 "Modifications" mean any addition to, deletion from, and/or change
|
||||
to, the substance and/or structure of the Original Code, any previous
|
||||
Modifications, the combination of Original Code and any previous
|
||||
Modifications, and/or any respective portions thereof. When code is
|
||||
released as a series of files, a Modification is: (a) any addition to
|
||||
or deletion from the contents of a file containing Covered Code;
|
||||
and/or (b) any new file or other representation of computer program
|
||||
statements that contains any part of Covered Code.
|
||||
|
||||
1.7 "Original Code" means (a) the Source Code of a program or other
|
||||
work as originally made available by Apple under this License,
|
||||
including the Source Code of any updates or upgrades to such programs
|
||||
or works made available by Apple under this License, and that has been
|
||||
expressly identified by Apple as such in the header file(s) of such
|
||||
work; and (b) the object code compiled from such Source Code and
|
||||
originally made available by Apple under this License.
|
||||
|
||||
1.8 "Source Code" means the human readable form of a program or other
|
||||
work that is suitable for making modifications to it, including all
|
||||
modules it contains, plus any associated interface definition files,
|
||||
scripts used to control compilation and installation of an executable
|
||||
(object code).
|
||||
|
||||
1.9 "You" or "Your" means an individual or a legal entity exercising
|
||||
rights under this License. For legal entities, "You" or "Your"
|
||||
includes any entity which controls, is controlled by, or is under
|
||||
common control with, You, where "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of fifty percent
|
||||
(50%) or more of the outstanding shares or beneficial ownership of
|
||||
such entity.
|
||||
|
||||
2. Permitted Uses; Conditions & Restrictions. Subject to the terms
|
||||
and conditions of this License, Apple hereby grants You, effective on
|
||||
the date You accept this License and download the Original Code, a
|
||||
world-wide, royalty-free, non-exclusive license, to the extent of
|
||||
Apple's Applicable Patent Rights and copyrights covering the Original
|
||||
Code, to do the following:
|
||||
|
||||
2.1 Unmodified Code. You may use, reproduce, display, perform,
|
||||
internally distribute within Your organization, and Externally Deploy
|
||||
verbatim, unmodified copies of the Original Code, for commercial or
|
||||
non-commercial purposes, provided that in each instance:
|
||||
|
||||
(a) You must retain and reproduce in all copies of Original Code the
|
||||
copyright and other proprietary notices and disclaimers of Apple as
|
||||
they appear in the Original Code, and keep intact all notices in the
|
||||
Original Code that refer to this License; and
|
||||
|
||||
(b) You must include a copy of this License with every copy of Source
|
||||
Code of Covered Code and documentation You distribute or Externally
|
||||
Deploy, and You may not offer or impose any terms on such Source Code
|
||||
that alter or restrict this License or the recipients' rights
|
||||
hereunder, except as permitted under Section 6.
|
||||
|
||||
2.2 Modified Code. You may modify Covered Code and use, reproduce,
|
||||
display, perform, internally distribute within Your organization, and
|
||||
Externally Deploy Your Modifications and Covered Code, for commercial
|
||||
or non-commercial purposes, provided that in each instance You also
|
||||
meet all of these conditions:
|
||||
|
||||
(a) You must satisfy all the conditions of Section 2.1 with respect to
|
||||
the Source Code of the Covered Code;
|
||||
|
||||
(b) You must duplicate, to the extent it does not already exist, the
|
||||
notice in Exhibit A in each file of the Source Code of all Your
|
||||
Modifications, and cause the modified files to carry prominent notices
|
||||
stating that You changed the files and the date of any change; and
|
||||
|
||||
(c) If You Externally Deploy Your Modifications, You must make
|
||||
Source Code of all Your Externally Deployed Modifications either
|
||||
available to those to whom You have Externally Deployed Your
|
||||
Modifications, or publicly available. Source Code of Your Externally
|
||||
Deployed Modifications must be released under the terms set forth in
|
||||
this License, including the license grants set forth in Section 3
|
||||
below, for as long as you Externally Deploy the Covered Code or twelve
|
||||
(12) months from the date of initial External Deployment, whichever is
|
||||
longer. You should preferably distribute the Source Code of Your
|
||||
Externally Deployed Modifications electronically (e.g. download from a
|
||||
web site).
|
||||
|
||||
2.3 Distribution of Executable Versions. In addition, if You
|
||||
Externally Deploy Covered Code (Original Code and/or Modifications) in
|
||||
object code, executable form only, You must include a prominent
|
||||
notice, in the code itself as well as in related documentation,
|
||||
stating that Source Code of the Covered Code is available under the
|
||||
terms of this License with information on how and where to obtain such
|
||||
Source Code.
|
||||
|
||||
2.4 Third Party Rights. You expressly acknowledge and agree that
|
||||
although Apple and each Contributor grants the licenses to their
|
||||
respective portions of the Covered Code set forth herein, no
|
||||
assurances are provided by Apple or any Contributor that the Covered
|
||||
Code does not infringe the patent or other intellectual property
|
||||
rights of any other entity. Apple and each Contributor disclaim any
|
||||
liability to You for claims brought by any other entity based on
|
||||
infringement of intellectual property rights or otherwise. As a
|
||||
condition to exercising the rights and licenses granted hereunder, You
|
||||
hereby assume sole responsibility to secure any other intellectual
|
||||
property rights needed, if any. For example, if a third party patent
|
||||
license is required to allow You to distribute the Covered Code, it is
|
||||
Your responsibility to acquire that license before distributing the
|
||||
Covered Code.
|
||||
|
||||
3. Your Grants. In consideration of, and as a condition to, the
|
||||
licenses granted to You under this License, You hereby grant to any
|
||||
person or entity receiving or distributing Covered Code under this
|
||||
License a non-exclusive, royalty-free, perpetual, irrevocable license,
|
||||
under Your Applicable Patent Rights and other intellectual property
|
||||
rights (other than patent) owned or controlled by You, to use,
|
||||
reproduce, display, perform, modify, sublicense, distribute and
|
||||
Externally Deploy Your Modifications of the same scope and extent as
|
||||
Apple's licenses under Sections 2.1 and 2.2 above.
|
||||
|
||||
4. Larger Works. You may create a Larger Work by combining Covered
|
||||
Code with other code not governed by the terms of this License and
|
||||
distribute the Larger Work as a single product. In each such instance,
|
||||
You must make sure the requirements of this License are fulfilled for
|
||||
the Covered Code or any portion thereof.
|
||||
|
||||
5. Limitations on Patent License. Except as expressly stated in
|
||||
Section 2, no other patent rights, express or implied, are granted by
|
||||
Apple herein. Modifications and/or Larger Works may require additional
|
||||
patent licenses from Apple which Apple may grant in its sole
|
||||
discretion.
|
||||
|
||||
6. Additional Terms. You may choose to offer, and to charge a fee for,
|
||||
warranty, support, indemnity or liability obligations and/or other
|
||||
rights consistent with the scope of the license granted herein
|
||||
("Additional Terms") to one or more recipients of Covered Code.
|
||||
However, You may do so only on Your own behalf and as Your sole
|
||||
responsibility, and not on behalf of Apple or any Contributor. You
|
||||
must obtain the recipient's agreement that any such Additional Terms
|
||||
are offered by You alone, and You hereby agree to indemnify, defend
|
||||
and hold Apple and every Contributor harmless for any liability
|
||||
incurred by or claims asserted against Apple or such Contributor by
|
||||
reason of any such Additional Terms.
|
||||
|
||||
7. Versions of the License. Apple may publish revised and/or new
|
||||
versions of this License from time to time. Each version will be given
|
||||
a distinguishing version number. Once Original Code has been published
|
||||
under a particular version of this License, You may continue to use it
|
||||
under the terms of that version. You may also choose to use such
|
||||
Original Code under the terms of any subsequent version of this
|
||||
License published by Apple. No one other than Apple has the right to
|
||||
modify the terms applicable to Covered Code created under this
|
||||
License.
|
||||
|
||||
8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
|
||||
part pre-release, untested, or not fully tested works. The Covered
|
||||
Code may contain errors that could cause failures or loss of data, and
|
||||
may be incomplete or contain inaccuracies. You expressly acknowledge
|
||||
and agree that use of the Covered Code, or any portion thereof, is at
|
||||
Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
|
||||
WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
|
||||
APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
|
||||
PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
|
||||
ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
|
||||
NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
|
||||
MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
|
||||
PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
|
||||
PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
|
||||
INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
|
||||
FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
|
||||
THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
|
||||
ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
|
||||
ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
|
||||
AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
|
||||
You acknowledge that the Covered Code is not intended for use in the
|
||||
operation of nuclear facilities, aircraft navigation, communication
|
||||
systems, or air traffic control machines in which case the failure of
|
||||
the Covered Code could lead to death, personal injury, or severe
|
||||
physical or environmental damage.
|
||||
|
||||
9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
|
||||
EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
|
||||
TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
|
||||
ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
|
||||
TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
|
||||
REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
|
||||
INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
|
||||
TO YOU. In no event shall Apple's total liability to You for all
|
||||
damages (other than as may be required by applicable law) under this
|
||||
License exceed the amount of fifty dollars ($50.00).
|
||||
|
||||
10. Trademarks. This License does not grant any rights to use the
|
||||
trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
|
||||
"QuickTime", "QuickTime Streaming Server" or any other trademarks,
|
||||
service marks, logos or trade names belonging to Apple (collectively
|
||||
"Apple Marks") or to any trademark, service mark, logo or trade name
|
||||
belonging to any Contributor. You agree not to use any Apple Marks in
|
||||
or as part of the name of products derived from the Original Code or
|
||||
to endorse or promote products derived from the Original Code other
|
||||
than as expressly permitted by and in strict compliance at all times
|
||||
with Apple's third party trademark usage guidelines which are posted
|
||||
at http://www.apple.com/legal/guidelinesfor3rdparties.html.
|
||||
|
||||
11. Ownership. Subject to the licenses granted under this License,
|
||||
each Contributor retains all rights, title and interest in and to any
|
||||
Modifications made by such Contributor. Apple retains all rights,
|
||||
title and interest in and to the Original Code and any Modifications
|
||||
made by or on behalf of Apple ("Apple Modifications"), and such Apple
|
||||
Modifications will not be automatically subject to this License. Apple
|
||||
may, at its sole discretion, choose to license such Apple
|
||||
Modifications under this License, or on different terms from those
|
||||
contained in this License or may choose not to license them at all.
|
||||
|
||||
12. Termination.
|
||||
|
||||
12.1 Termination. This License and the rights granted hereunder will
|
||||
terminate:
|
||||
|
||||
(a) automatically without notice from Apple if You fail to comply with
|
||||
any term(s) of this License and fail to cure such breach within 30
|
||||
days of becoming aware of such breach;
|
||||
|
||||
(b) immediately in the event of the circumstances described in Section
|
||||
13.5(b); or
|
||||
|
||||
(c) automatically without notice from Apple if You, at any time during
|
||||
the term of this License, commence an action for patent infringement
|
||||
against Apple; provided that Apple did not first commence
|
||||
an action for patent infringement against You in that instance.
|
||||
|
||||
12.2 Effect of Termination. Upon termination, You agree to immediately
|
||||
stop any further use, reproduction, modification, sublicensing and
|
||||
distribution of the Covered Code. All sublicenses to the Covered Code
|
||||
which have been properly granted prior to termination shall survive
|
||||
any termination of this License. Provisions which, by their nature,
|
||||
should remain in effect beyond the termination of this License shall
|
||||
survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
|
||||
12.2 and 13. No party will be liable to any other for compensation,
|
||||
indemnity or damages of any sort solely as a result of terminating
|
||||
this License in accordance with its terms, and termination of this
|
||||
License will be without prejudice to any other right or remedy of
|
||||
any party.
|
||||
|
||||
13. Miscellaneous.
|
||||
|
||||
13.1 Government End Users. The Covered Code is a "commercial item" as
|
||||
defined in FAR 2.101. Government software and technical data rights in
|
||||
the Covered Code include only those rights customarily provided to the
|
||||
public as defined in this License. This customary commercial license
|
||||
in technical data and software is provided in accordance with FAR
|
||||
12.211 (Technical Data) and 12.212 (Computer Software) and, for
|
||||
Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
|
||||
Commercial Items) and 227.7202-3 (Rights in Commercial Computer
|
||||
Software or Computer Software Documentation). Accordingly, all U.S.
|
||||
Government End Users acquire Covered Code with only those rights set
|
||||
forth herein.
|
||||
|
||||
13.2 Relationship of Parties. This License will not be construed as
|
||||
creating an agency, partnership, joint venture or any other form of
|
||||
legal association between or among You, Apple or any Contributor, and
|
||||
You will not represent to the contrary, whether expressly, by
|
||||
implication, appearance or otherwise.
|
||||
|
||||
13.3 Independent Development. Nothing in this License will impair
|
||||
Apple's right to acquire, license, develop, have others develop for
|
||||
it, market and/or distribute technology or products that perform the
|
||||
same or similar functions as, or otherwise compete with,
|
||||
Modifications, Larger Works, technology or products that You may
|
||||
develop, produce, market or distribute.
|
||||
|
||||
13.4 Waiver; Construction. Failure by Apple or any Contributor to
|
||||
enforce any provision of this License will not be deemed a waiver of
|
||||
future enforcement of that or any other provision. Any law or
|
||||
regulation which provides that the language of a contract shall be
|
||||
construed against the drafter will not apply to this License.
|
||||
|
||||
13.5 Severability. (a) If for any reason a court of competent
|
||||
jurisdiction finds any provision of this License, or portion thereof,
|
||||
to be unenforceable, that provision of the License will be enforced to
|
||||
the maximum extent permissible so as to effect the economic benefits
|
||||
and intent of the parties, and the remainder of this License will
|
||||
continue in full force and effect. (b) Notwithstanding the foregoing,
|
||||
if applicable law prohibits or restricts You from fully and/or
|
||||
specifically complying with Sections 2 and/or 3 or prevents the
|
||||
enforceability of either of those Sections, this License will
|
||||
immediately terminate and You must immediately discontinue any use of
|
||||
the Covered Code and destroy all copies of it that are in your
|
||||
possession or control.
|
||||
|
||||
13.6 Dispute Resolution. Any litigation or other dispute resolution
|
||||
between You and Apple relating to this License shall take place in the
|
||||
Northern District of California, and You and Apple hereby consent to
|
||||
the personal jurisdiction of, and venue in, the state and federal
|
||||
courts within that District with respect to this License. The
|
||||
application of the United Nations Convention on Contracts for the
|
||||
International Sale of Goods is expressly excluded.
|
||||
|
||||
13.7 Entire Agreement; Governing Law. This License constitutes the
|
||||
entire agreement between the parties with respect to the subject
|
||||
matter hereof. This License shall be governed by the laws of the
|
||||
United States and the State of California, except that body of
|
||||
California law concerning conflicts of law.
|
||||
|
||||
Where You are located in the province of Quebec, Canada, the following
|
||||
clause applies: The parties hereby confirm that they have requested
|
||||
that this License and all related documents be drafted in English. Les
|
||||
parties ont exige que le present contrat et tous les documents
|
||||
connexes soient rediges en anglais.
|
||||
|
||||
EXHIBIT A.
|
||||
|
||||
"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
|
||||
Reserved.
|
||||
|
||||
This file contains Original Code and/or Modifications of Original Code
|
||||
as defined in and that are subject to the Apple Public Source License
|
||||
Version 2.0 (the 'License'). You may not use this file except in
|
||||
compliance with the License. Please obtain a copy of the License at
|
||||
http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
file.
|
||||
|
||||
The Original Code and all software distributed under the License are
|
||||
distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
Please see the License for the specific language governing rights and
|
||||
limitations under the License."
|
||||
@@ -73,6 +73,9 @@ static kern_return_t reader(__unused task_t remote_task, vm_address_t remote_add
|
||||
malloc_introspection_t *introspection = zone->introspect;
|
||||
NSString *zoneName = @(zone->zone_name);
|
||||
|
||||
// We only need to look at the default malloc zone.
|
||||
// This may explain why some zone functions are
|
||||
// sometimes invalid; perhaps not all zones support them?
|
||||
if (![zoneName isEqualToString:@"DefaultMallocZone"] || !introspection) {
|
||||
continue;
|
||||
}
|
||||
@@ -90,20 +93,23 @@ static kern_return_t reader(__unused task_t remote_task, vm_address_t remote_add
|
||||
// The largest realistic memory address varies by platform.
|
||||
// Only 48 bits are used by 64 bit machines while
|
||||
// 32 bit machines use all bits.
|
||||
#if __arm64__
|
||||
static uintptr_t MAX_REALISTIC_ADDRESS = 0xFFFFFFFFFFFF;
|
||||
//
|
||||
// __LP64__ is defined as 1 for both arm64 and x86_64
|
||||
// via: clang -dM -arch [arm64|x86_64] -E -x c /dev/null | grep LP
|
||||
#if __LP64__
|
||||
static uintptr_t MAX_REALISTIC_ADDRESS = 0x0000FFFFFFFFFFFF;
|
||||
BOOL lockZoneValid = lock_zone != nil && (uintptr_t)lock_zone < MAX_REALISTIC_ADDRESS;
|
||||
BOOL unlockZoneValid = unlock_zone != nil && (uintptr_t)unlock_zone < MAX_REALISTIC_ADDRESS;
|
||||
#else
|
||||
static uintptr_t MAX_REALISTIC_ADDRESS = INT_MAX;
|
||||
BOOL lockZoneValid = lock_zone != nil;
|
||||
BOOL unlockZoneValid = unlock_zone != nil;
|
||||
#endif
|
||||
|
||||
// There is little documentation on when and why
|
||||
// any of these function pointers might be NULL
|
||||
// or garbage, so we resort to checking for NULL
|
||||
// and impossible memory addresses at least
|
||||
if (lock_zone && unlock_zone &&
|
||||
introspection->enumerator &&
|
||||
(uintptr_t)lock_zone < MAX_REALISTIC_ADDRESS &&
|
||||
(uintptr_t)unlock_zone < MAX_REALISTIC_ADDRESS) {
|
||||
if (introspection->enumerator && lockZoneValid && unlockZoneValid) {
|
||||
lock_zone(zone);
|
||||
introspection->enumerator(TASK_NULL, (void *)&callback, MALLOC_PTR_IN_USE_RANGE_TYPE, (vm_address_t)zone, reader, &range_callback);
|
||||
unlock_zone(zone);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXKeyboardHelpViewController.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 9/19/15.
|
||||
// Copyright © 2015 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXKeyboardHelpViewController.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 9/19/15.
|
||||
// Copyright © 2015 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXMultilineTableViewCell.h
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 2/13/15.
|
||||
// Copyright (c) 2015 f. All rights reserved.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// FLEXMultilineTableViewCell.m
|
||||
// UICatalog
|
||||
// FLEX
|
||||
//
|
||||
// Created by Ryan Olson on 2/13/15.
|
||||
// Copyright (c) 2015 f. All rights reserved.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// FLEXObjcInternal.h
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 11/1/18.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @brief Assumes memory is valid and readable.
|
||||
/// @discussion objc-internal.h, objc-private.h, and objc-config.h
|
||||
/// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
|
||||
/// http://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
|
||||
/// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
|
||||
BOOL FLEXPointerIsValidObjcObject(const void * ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,309 @@
|
||||
//
|
||||
// FLEXObjcInternal.mm
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 11/1/18.
|
||||
//
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005-2007 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "FLEXObjcInternal.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <malloc/malloc.h>
|
||||
|
||||
#define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#define NEVER_INLINE inline __attribute__((noinline))
|
||||
|
||||
// The macros below are copied straight from
|
||||
// objc-internal.h, objc-private.h, objc-object.h, and objc-config.h with
|
||||
// as few modifications as possible. Changes are noted in boxed comments.
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-internal.h.auto.html
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-private.h.auto.html
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-config.h.auto.html
|
||||
// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-object.h.auto.html
|
||||
|
||||
/////////////////////
|
||||
// objc-internal.h //
|
||||
/////////////////////
|
||||
|
||||
#if TARGET_OS_OSX && __x86_64__
|
||||
// 64-bit Mac - tag bit is LSB
|
||||
# define OBJC_MSB_TAGGED_POINTERS 0
|
||||
#else
|
||||
// Everything else - tag bit is MSB
|
||||
# define OBJC_MSB_TAGGED_POINTERS 1
|
||||
#endif
|
||||
|
||||
#define _OBJC_TAG_INDEX_MASK 0x7
|
||||
// array slot includes the tag bit itself
|
||||
#define _OBJC_TAG_SLOT_COUNT 16
|
||||
#define _OBJC_TAG_SLOT_MASK 0xf
|
||||
|
||||
#define _OBJC_TAG_EXT_INDEX_MASK 0xff
|
||||
// array slot has no extra bits
|
||||
#define _OBJC_TAG_EXT_SLOT_COUNT 256
|
||||
#define _OBJC_TAG_EXT_SLOT_MASK 0xff
|
||||
|
||||
#if OBJC_MSB_TAGGED_POINTERS
|
||||
# define _OBJC_TAG_MASK (1UL<<63)
|
||||
# define _OBJC_TAG_INDEX_SHIFT 60
|
||||
# define _OBJC_TAG_SLOT_SHIFT 60
|
||||
# define _OBJC_TAG_PAYLOAD_LSHIFT 4
|
||||
# define _OBJC_TAG_PAYLOAD_RSHIFT 4
|
||||
# define _OBJC_TAG_EXT_MASK (0xfUL<<60)
|
||||
# define _OBJC_TAG_EXT_INDEX_SHIFT 52
|
||||
# define _OBJC_TAG_EXT_SLOT_SHIFT 52
|
||||
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
|
||||
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
|
||||
#else
|
||||
# define _OBJC_TAG_MASK 1UL
|
||||
# define _OBJC_TAG_INDEX_SHIFT 1
|
||||
# define _OBJC_TAG_SLOT_SHIFT 0
|
||||
# define _OBJC_TAG_PAYLOAD_LSHIFT 0
|
||||
# define _OBJC_TAG_PAYLOAD_RSHIFT 4
|
||||
# define _OBJC_TAG_EXT_MASK 0xfUL
|
||||
# define _OBJC_TAG_EXT_INDEX_SHIFT 4
|
||||
# define _OBJC_TAG_EXT_SLOT_SHIFT 4
|
||||
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
|
||||
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////
|
||||
// originally _objc_isTaggedPointer //
|
||||
//////////////////////////////////////
|
||||
static BOOL flex_isTaggedPointer(const void *ptr)
|
||||
{
|
||||
return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// objc-config.h //
|
||||
///////////////////
|
||||
|
||||
// Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa
|
||||
// field as an index into a class table.
|
||||
#if __ARM_ARCH_7K__ >= 2
|
||||
# define SUPPORT_INDEXED_ISA 1
|
||||
#else
|
||||
# define SUPPORT_INDEXED_ISA 0
|
||||
#endif
|
||||
|
||||
// Define SUPPORT_PACKED_ISA=1 on platforms that store the class in the isa
|
||||
// field as a maskable pointer with other data around it.
|
||||
#if (!__LP64__ || TARGET_OS_WIN32 || TARGET_OS_SIMULATOR)
|
||||
# define SUPPORT_PACKED_ISA 0
|
||||
#else
|
||||
# define SUPPORT_PACKED_ISA 1
|
||||
#endif
|
||||
|
||||
// Define SUPPORT_NONPOINTER_ISA=1 on any platform that may store something
|
||||
// in the isa field that is not a raw pointer.
|
||||
#if !SUPPORT_INDEXED_ISA && !SUPPORT_PACKED_ISA
|
||||
# define SUPPORT_NONPOINTER_ISA 0
|
||||
#else
|
||||
# define SUPPORT_NONPOINTER_ISA 1
|
||||
#endif
|
||||
|
||||
////////////////////
|
||||
// objc-private.h //
|
||||
////////////////////
|
||||
|
||||
union isa_t
|
||||
{
|
||||
isa_t() { }
|
||||
isa_t(uintptr_t value) : bits(value) { }
|
||||
|
||||
Class cls;
|
||||
uintptr_t bits;
|
||||
|
||||
#if SUPPORT_PACKED_ISA
|
||||
|
||||
// extra_rc must be the MSB-most field (so it matches carry/overflow flags)
|
||||
// nonpointer must be the LSB (fixme or get rid of it)
|
||||
// shiftcls must occupy the same bits that a real class pointer would
|
||||
// bits + RC_ONE is equivalent to extra_rc + 1
|
||||
// RC_HALF is the high bit of extra_rc (i.e. half of its range)
|
||||
|
||||
// future expansion:
|
||||
// uintptr_t fast_rr : 1; // no r/r overrides
|
||||
// uintptr_t lock : 2; // lock for atomic property, @synch
|
||||
// uintptr_t extraBytes : 1; // allocated with extra bytes
|
||||
|
||||
# if __arm64__
|
||||
# define ISA_MASK 0x0000000ffffffff8ULL
|
||||
# define ISA_MAGIC_MASK 0x000003f000000001ULL
|
||||
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
|
||||
struct {
|
||||
uintptr_t nonpointer : 1;
|
||||
uintptr_t has_assoc : 1;
|
||||
uintptr_t has_cxx_dtor : 1;
|
||||
uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
|
||||
uintptr_t magic : 6;
|
||||
uintptr_t weakly_referenced : 1;
|
||||
uintptr_t deallocating : 1;
|
||||
uintptr_t has_sidetable_rc : 1;
|
||||
uintptr_t extra_rc : 19;
|
||||
# define RC_ONE (1ULL<<45)
|
||||
# define RC_HALF (1ULL<<18)
|
||||
};
|
||||
|
||||
# elif __x86_64__
|
||||
# define ISA_MASK 0x00007ffffffffff8ULL
|
||||
# define ISA_MAGIC_MASK 0x001f800000000001ULL
|
||||
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
|
||||
struct {
|
||||
uintptr_t nonpointer : 1;
|
||||
uintptr_t has_assoc : 1;
|
||||
uintptr_t has_cxx_dtor : 1;
|
||||
uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
|
||||
uintptr_t magic : 6;
|
||||
uintptr_t weakly_referenced : 1;
|
||||
uintptr_t deallocating : 1;
|
||||
uintptr_t has_sidetable_rc : 1;
|
||||
uintptr_t extra_rc : 8;
|
||||
# define RC_ONE (1ULL<<56)
|
||||
# define RC_HALF (1ULL<<7)
|
||||
};
|
||||
|
||||
# else
|
||||
# error unknown architecture for packed isa
|
||||
# endif
|
||||
|
||||
// SUPPORT_PACKED_ISA
|
||||
#endif
|
||||
|
||||
|
||||
#if SUPPORT_INDEXED_ISA
|
||||
|
||||
# if __ARM_ARCH_7K__ >= 2
|
||||
|
||||
# define ISA_INDEX_IS_NPI 1
|
||||
# define ISA_INDEX_MASK 0x0001FFFC
|
||||
# define ISA_INDEX_SHIFT 2
|
||||
# define ISA_INDEX_BITS 15
|
||||
# define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
|
||||
# define ISA_INDEX_MAGIC_MASK 0x001E0001
|
||||
# define ISA_INDEX_MAGIC_VALUE 0x001C0001
|
||||
struct {
|
||||
uintptr_t nonpointer : 1;
|
||||
uintptr_t has_assoc : 1;
|
||||
uintptr_t indexcls : 15;
|
||||
uintptr_t magic : 4;
|
||||
uintptr_t has_cxx_dtor : 1;
|
||||
uintptr_t weakly_referenced : 1;
|
||||
uintptr_t deallocating : 1;
|
||||
uintptr_t has_sidetable_rc : 1;
|
||||
uintptr_t extra_rc : 7;
|
||||
# define RC_ONE (1ULL<<25)
|
||||
# define RC_HALF (1ULL<<6)
|
||||
};
|
||||
|
||||
# else
|
||||
# error unknown architecture for indexed isa
|
||||
# endif
|
||||
|
||||
// SUPPORT_INDEXED_ISA
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
///////////////////
|
||||
// objc-object.h //
|
||||
///////////////////
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// originally objc_object::isExtTaggedPointer //
|
||||
////////////////////////////////////////////////
|
||||
static BOOL flex_isExtTaggedPointer(const void *ptr)
|
||||
{
|
||||
return ((uintptr_t)ptr & _OBJC_TAG_EXT_MASK) == _OBJC_TAG_EXT_MASK;
|
||||
}
|
||||
|
||||
struct flex_objc_object {
|
||||
isa_t isa;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Returns nil on platforms without nonpointer isa. //
|
||||
// Supporting those platforms would be too complicated //
|
||||
// for such a niche feature anyway. - @NSExceptional //
|
||||
// //
|
||||
// Code modified from objc_object::ISA() on 11/04/18 //
|
||||
//////////////////////////////////////////////////////////
|
||||
static id flex_getIsa(const flex_objc_object *object) {
|
||||
#if SUPPORT_NONPOINTER_ISA
|
||||
if (object->isa.nonpointer) {
|
||||
return object_getClass((__bridge id)object);
|
||||
}
|
||||
return (__bridge Class)(void *)object->isa.bits;
|
||||
#else
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
// FLEXObjectInternal //
|
||||
// No Apple code beyond this point //
|
||||
/////////////////////////////////////
|
||||
|
||||
extern "C" {
|
||||
/// Assumes memory is valid and readable.
|
||||
/// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
|
||||
BOOL FLEXPointerIsValidObjcObject(const void * ptr)
|
||||
{
|
||||
uintptr_t pointer = (uintptr_t)ptr;
|
||||
|
||||
if (!ptr) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Tagged pointers have 0x1 set, no other valid pointers do
|
||||
// objc-internal.h -> _objc_isTaggedPointer()
|
||||
if (flex_isTaggedPointer(ptr) || flex_isExtTaggedPointer(ptr)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Check pointer alignment
|
||||
if ((pointer % sizeof(uintptr_t)) != 0) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// From LLDB:
|
||||
// Pointers in a class_t will only have bits 0 through 46 set,
|
||||
// so if any pointer has bits 47 through 63 high, we know that this is not a valid isa
|
||||
// http://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
|
||||
if ((pointer & 0xFFFF800000000000) != 0) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html :
|
||||
if (flex_getIsa((const flex_objc_object *)ptr)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,10 +25,44 @@ extern NSString *const kFLEXUtilityAttributeWeak;
|
||||
extern NSString *const kFLEXUtilityAttributeGarbageCollectable;
|
||||
extern NSString *const kFLEXUtilityAttributeOldStyleTypeEncoding;
|
||||
|
||||
typedef NS_ENUM(char, FLEXTypeEncoding)
|
||||
{
|
||||
FLEXTypeEncodingUnknown = '?',
|
||||
FLEXTypeEncodingChar = 'c',
|
||||
FLEXTypeEncodingInt = 'i',
|
||||
FLEXTypeEncodingShort = 's',
|
||||
FLEXTypeEncodingLong = 'l',
|
||||
FLEXTypeEncodingLongLong = 'q',
|
||||
FLEXTypeEncodingUnsignedChar = 'C',
|
||||
FLEXTypeEncodingUnsignedInt = 'I',
|
||||
FLEXTypeEncodingUnsignedShort = 'S',
|
||||
FLEXTypeEncodingUnsignedLong = 'L',
|
||||
FLEXTypeEncodingUnsignedLongLong = 'Q',
|
||||
FLEXTypeEncodingFloat = 'f',
|
||||
FLEXTypeEncodingDouble = 'd',
|
||||
FLEXTypeEncodingCBool = 'B',
|
||||
FLEXTypeEncodingVoid = 'v',
|
||||
FLEXTypeEncodingCString = '*',
|
||||
FLEXTypeEncodingObjcObject = '@',
|
||||
FLEXTypeEncodingObjcClass = '#',
|
||||
FLEXTypeEncodingSelector = ':',
|
||||
FLEXTypeEncodingArray = '[',
|
||||
FLEXTypeEncodingStruct = '{',
|
||||
FLEXTypeEncodingUnion = '(',
|
||||
FLEXTypeEncodingBitField = 'b',
|
||||
FLEXTypeEncodingPointer = '^',
|
||||
FLEXTypeEncodingConst = 'r'
|
||||
};
|
||||
|
||||
#define FLEXEncodeClass(class) ("@\"" #class "\"")
|
||||
|
||||
@interface FLEXRuntimeUtility : NSObject
|
||||
|
||||
// General Helpers
|
||||
+ (BOOL)pointerIsValidObjcObject:(const void *)pointer;
|
||||
/// Unwraps raw pointers to objects stored in NSValue, and re-boxes C strings into NSStrings.
|
||||
+ (id)potentiallyUnwrapBoxedPointer:(id)returnedObjectOrNil type:(const FLEXTypeEncoding *)returnType;
|
||||
|
||||
// Property Helpers
|
||||
+ (NSString *)prettyNameForProperty:(objc_property_t)property;
|
||||
+ (NSString *)typeEncodingForProperty:(objc_property_t)property;
|
||||
@@ -47,6 +81,7 @@ extern NSString *const kFLEXUtilityAttributeOldStyleTypeEncoding;
|
||||
// Method Helpers
|
||||
+ (NSString *)prettyNameForMethod:(Method)method isClassMethod:(BOOL)isClassMethod;
|
||||
+ (NSArray *)prettyArgumentComponentsForMethod:(Method)method;
|
||||
+ (FLEXTypeEncoding *)returnTypeForMethod:(Method)method;
|
||||
|
||||
// Method Calling/Field Editing
|
||||
+ (id)performSelector:(SEL)selector onObject:(id)object withArguments:(NSArray *)arguments error:(NSError * __autoreleasing *)error;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "FLEXObjcInternal.h"
|
||||
|
||||
// See https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6
|
||||
NSString *const kFLEXUtilityAttributeTypeEncoding = @"T";
|
||||
@@ -36,6 +37,57 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
@implementation FLEXRuntimeUtility
|
||||
|
||||
|
||||
#pragma mark - General Helpers (Public)
|
||||
|
||||
+ (BOOL)pointerIsValidObjcObject:(const void *)pointer
|
||||
{
|
||||
return FLEXPointerIsValidObjcObject(pointer);
|
||||
}
|
||||
|
||||
+ (id)potentiallyUnwrapBoxedPointer:(id)returnedObjectOrNil type:(const FLEXTypeEncoding *)returnType
|
||||
{
|
||||
if (!returnedObjectOrNil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSInteger i = 0;
|
||||
if (returnType[i] == FLEXTypeEncodingConst) {
|
||||
i++;
|
||||
}
|
||||
|
||||
BOOL returnsObjectOrClass = returnType[i] == FLEXTypeEncodingObjcObject ||
|
||||
returnType[i] == FLEXTypeEncodingObjcClass;
|
||||
BOOL returnsVoidPointer = returnType[i] == FLEXTypeEncodingPointer &&
|
||||
returnType[i+1] == FLEXTypeEncodingVoid;
|
||||
BOOL returnsCString = returnType[i] == FLEXTypeEncodingCString;
|
||||
|
||||
// If we got back an NSValue and the return type is not an object,
|
||||
// we check to see if the pointer is of a valid object. If not,
|
||||
// we just display the NSValue.
|
||||
if (!returnsObjectOrClass) {
|
||||
// Can only be NSValue since return type is not an object,
|
||||
// so we bail if this doesn't add up
|
||||
if (![returnedObjectOrNil isKindOfClass:[NSValue class]]) {
|
||||
return returnedObjectOrNil;
|
||||
}
|
||||
|
||||
NSValue *value = (NSValue *)returnedObjectOrNil;
|
||||
|
||||
if (returnsCString) {
|
||||
// Wrap char * in NSString
|
||||
const char *string = (const char *)value.pointerValue;
|
||||
returnedObjectOrNil = [NSString stringWithCString:string encoding:NSUTF8StringEncoding];
|
||||
} else if (returnsVoidPointer) {
|
||||
// Cast valid objects disguised as void * to id
|
||||
if ([FLEXRuntimeUtility pointerIsValidObjcObject:value.pointerValue]) {
|
||||
returnedObjectOrNil = (__bridge id)value.pointerValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnedObjectOrNil;
|
||||
}
|
||||
|
||||
#pragma mark - Property Helpers (Public)
|
||||
|
||||
+ (NSString *)prettyNameForProperty:(objc_property_t)property
|
||||
@@ -285,7 +337,7 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
|
||||
// this is a workaround cause method_getNumberOfArguments() returns wrong number for some methods
|
||||
if (selectorComponents.count == 1) {
|
||||
return [selectorComponents copy];
|
||||
return @[];
|
||||
}
|
||||
|
||||
if ([selectorComponents.lastObject isEqualToString:@""]) {
|
||||
@@ -303,6 +355,11 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
return components;
|
||||
}
|
||||
|
||||
+ (FLEXTypeEncoding *)returnTypeForMethod:(Method)method
|
||||
{
|
||||
return (FLEXTypeEncoding *)method_copyReturnType(method);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Method Calling/Field Editing (Public)
|
||||
|
||||
@@ -353,66 +410,67 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSUInteger bufferSize = 0;
|
||||
@try {
|
||||
NSUInteger bufferSize = 0;
|
||||
|
||||
// NSGetSizeAndAlignment barfs on type encoding for bitfields.
|
||||
NSGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL);
|
||||
|
||||
if (bufferSize > 0) {
|
||||
void *buffer = calloc(bufferSize, 1);
|
||||
[argumentValue getValue:buffer];
|
||||
[invocation setArgument:buffer atIndex:argumentIndex];
|
||||
free(buffer);
|
||||
}
|
||||
} @catch (NSException *exception) { }
|
||||
|
||||
if (bufferSize > 0) {
|
||||
void *buffer = calloc(bufferSize, 1);
|
||||
[argumentValue getValue:buffer];
|
||||
[invocation setArgument:buffer atIndex:argumentIndex];
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to invoke the invocation but guard against an exception being thrown.
|
||||
BOOL successfullyInvoked = NO;
|
||||
id returnObject = nil;
|
||||
@try {
|
||||
// Some methods are not fit to be called...
|
||||
// Looking at you -[UIResponder(UITextInputAdditions) _caretRect]
|
||||
[invocation invoke];
|
||||
successfullyInvoked = YES;
|
||||
|
||||
// Retreive the return value and box if necessary.
|
||||
const char *returnType = [methodSignature methodReturnType];
|
||||
|
||||
if (returnType[0] == @encode(id)[0] || returnType[0] == @encode(Class)[0]) {
|
||||
// Return value is an object.
|
||||
__unsafe_unretained id objectReturnedFromMethod = nil;
|
||||
[invocation getReturnValue:&objectReturnedFromMethod];
|
||||
returnObject = objectReturnedFromMethod;
|
||||
} else if (returnType[0] != @encode(void)[0]) {
|
||||
// Will use arbitrary buffer for return value and box it.
|
||||
void *returnValue = malloc([methodSignature methodReturnLength]);
|
||||
|
||||
if (returnValue) {
|
||||
[invocation getReturnValue:returnValue];
|
||||
returnObject = [self valueForPrimitivePointer:returnValue objCType:returnType];
|
||||
free(returnValue);
|
||||
}
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
// Bummer...
|
||||
if (error) {
|
||||
// "… on <class>" / "… on instance of <class>"
|
||||
NSString *class = NSStringFromClass([object class]);
|
||||
NSString *calledOn = object == [object class] ? class : [@"an instance of " stringByAppendingString:class];
|
||||
|
||||
|
||||
NSString *message = [NSString stringWithFormat:@"Exception '%@' thrown while performing selector '%@' on %@.\nReason:\n\n%@",
|
||||
exception.name,
|
||||
NSStringFromSelector(selector),
|
||||
calledOn,
|
||||
exception.reason];
|
||||
|
||||
|
||||
*error = [NSError errorWithDomain:FLEXRuntimeUtilityErrorDomain
|
||||
code:FLEXRuntimeUtilityErrorCodeInvocationFailed
|
||||
userInfo:@{ NSLocalizedDescriptionKey : message }];
|
||||
}
|
||||
}
|
||||
|
||||
// Retreive the return value and box if necessary.
|
||||
id returnObject = nil;
|
||||
if (successfullyInvoked) {
|
||||
const char *returnType = [methodSignature methodReturnType];
|
||||
if (returnType[0] == @encode(id)[0] || returnType[0] == @encode(Class)[0]) {
|
||||
__unsafe_unretained id objectReturnedFromMethod = nil;
|
||||
[invocation getReturnValue:&objectReturnedFromMethod];
|
||||
returnObject = objectReturnedFromMethod;
|
||||
} else if (returnType[0] != @encode(void)[0]) {
|
||||
void *returnValue = malloc([methodSignature methodReturnLength]);
|
||||
if (returnValue) {
|
||||
[invocation getReturnValue:returnValue];
|
||||
returnObject = [self valueForPrimitivePointer:returnValue objCType:returnType];
|
||||
free(returnValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnObject;
|
||||
}
|
||||
|
||||
|
||||
@@ -334,6 +334,11 @@
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = f;
|
||||
TargetAttributes = {
|
||||
5356823918F3656900BAAD62 = {
|
||||
DevelopmentTeam = S6N2F22V2Z;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 5356823518F3656900BAAD62 /* Build configuration list for PBXProject "UICatalog" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
@@ -540,6 +545,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
DEVELOPMENT_TEAM = S6N2F22V2Z;
|
||||
EXCLUDED_SOURCE_FILE_NAMES = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -560,6 +566,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
DEVELOPMENT_TEAM = S6N2F22V2Z;
|
||||
EXCLUDED_SOURCE_FILE_NAMES = "FLEX*";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
||||
@@ -166,10 +166,19 @@
|
||||
94AAF0381BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 94AAF0361BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
94AAF0391BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 94AAF0371BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m */; };
|
||||
94AAF03A1BAF2F0300DE8760 /* FLEXKeyboardShortcutManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 942DCD821BAE0AD300DB5DC2 /* FLEXKeyboardShortcutManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
C309B82F223ED64400B228EC /* FLEXLogController.h in Headers */ = {isa = PBXBuildFile; fileRef = C309B82D223ED64400B228EC /* FLEXLogController.h */; };
|
||||
C33E46AF223B02CD004BD0E6 /* FLEXASLLogController.h in Headers */ = {isa = PBXBuildFile; fileRef = C33E46AD223B02CD004BD0E6 /* FLEXASLLogController.h */; };
|
||||
C33E46B0223B02CD004BD0E6 /* FLEXASLLogController.m in Sources */ = {isa = PBXBuildFile; fileRef = C33E46AE223B02CD004BD0E6 /* FLEXASLLogController.m */; };
|
||||
C34EE30821CB23CC00BD3A7C /* FLEXOSLogController.h in Headers */ = {isa = PBXBuildFile; fileRef = C34EE30621CB23CC00BD3A7C /* FLEXOSLogController.h */; };
|
||||
C37A0C93218BAC9600848CA7 /* FLEXObjcInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = C37A0C91218BAC9600848CA7 /* FLEXObjcInternal.h */; };
|
||||
C37A0C94218BAC9600848CA7 /* FLEXObjcInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = C37A0C92218BAC9600848CA7 /* FLEXObjcInternal.mm */; };
|
||||
C395D6D921789BD800BEAD4D /* FLEXColorExplorerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C395D6D721789BD800BEAD4D /* FLEXColorExplorerViewController.h */; };
|
||||
C395D6DA21789BD800BEAD4D /* FLEXColorExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C395D6D821789BD800BEAD4D /* FLEXColorExplorerViewController.m */; };
|
||||
C3DA55FE21A76406005DDA60 /* FLEXMutableFieldEditorViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C3DA55FC21A76406005DDA60 /* FLEXMutableFieldEditorViewController.h */; };
|
||||
C3DA55FF21A76406005DDA60 /* FLEXMutableFieldEditorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C3DA55FD21A76406005DDA60 /* FLEXMutableFieldEditorViewController.m */; };
|
||||
C3DB9F642107FC9600B46809 /* FLEXObjectRef.h in Headers */ = {isa = PBXBuildFile; fileRef = C3DB9F622107FC9600B46809 /* FLEXObjectRef.h */; };
|
||||
C3DB9F652107FC9600B46809 /* FLEXObjectRef.m in Sources */ = {isa = PBXBuildFile; fileRef = C3DB9F632107FC9600B46809 /* FLEXObjectRef.m */; };
|
||||
C3DC287C223ED5F200F48AA6 /* FLEXOSLogController.m in Sources */ = {isa = PBXBuildFile; fileRef = C34EE30721CB23CC00BD3A7C /* FLEXOSLogController.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -346,8 +355,18 @@
|
||||
94A515241C4CA2080063292F /* FLEXToolbarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLEXToolbarItem.m; path = Classes/Toolbar/FLEXToolbarItem.m; sourceTree = SOURCE_ROOT; };
|
||||
94AAF0361BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXKeyboardHelpViewController.h; sourceTree = "<group>"; };
|
||||
94AAF0371BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXKeyboardHelpViewController.m; sourceTree = "<group>"; };
|
||||
C309B82D223ED64400B228EC /* FLEXLogController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXLogController.h; sourceTree = "<group>"; };
|
||||
C33E46AD223B02CD004BD0E6 /* FLEXASLLogController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXASLLogController.h; sourceTree = "<group>"; };
|
||||
C33E46AE223B02CD004BD0E6 /* FLEXASLLogController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXASLLogController.m; sourceTree = "<group>"; };
|
||||
C34EE30621CB23CC00BD3A7C /* FLEXOSLogController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXOSLogController.h; sourceTree = "<group>"; };
|
||||
C34EE30721CB23CC00BD3A7C /* FLEXOSLogController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXOSLogController.m; sourceTree = "<group>"; };
|
||||
C34EE30A21CB249E00BD3A7C /* ActivityStreamAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActivityStreamAPI.h; sourceTree = "<group>"; };
|
||||
C37A0C91218BAC9600848CA7 /* FLEXObjcInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXObjcInternal.h; sourceTree = "<group>"; };
|
||||
C37A0C92218BAC9600848CA7 /* FLEXObjcInternal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FLEXObjcInternal.mm; sourceTree = "<group>"; };
|
||||
C395D6D721789BD800BEAD4D /* FLEXColorExplorerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXColorExplorerViewController.h; sourceTree = "<group>"; };
|
||||
C395D6D821789BD800BEAD4D /* FLEXColorExplorerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXColorExplorerViewController.m; sourceTree = "<group>"; };
|
||||
C3DA55FC21A76406005DDA60 /* FLEXMutableFieldEditorViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXMutableFieldEditorViewController.h; sourceTree = "<group>"; };
|
||||
C3DA55FD21A76406005DDA60 /* FLEXMutableFieldEditorViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXMutableFieldEditorViewController.m; sourceTree = "<group>"; };
|
||||
C3DB9F622107FC9600B46809 /* FLEXObjectRef.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXObjectRef.h; sourceTree = "<group>"; };
|
||||
C3DB9F632107FC9600B46809 /* FLEXObjectRef.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXObjectRef.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -471,6 +490,8 @@
|
||||
3A4C94581B5B21410088C3F2 /* FLEXMultilineTableViewCell.m */,
|
||||
3A4C94591B5B21410088C3F2 /* FLEXResources.h */,
|
||||
3A4C945A1B5B21410088C3F2 /* FLEXResources.m */,
|
||||
C37A0C91218BAC9600848CA7 /* FLEXObjcInternal.h */,
|
||||
C37A0C92218BAC9600848CA7 /* FLEXObjcInternal.mm */,
|
||||
3A4C945B1B5B21410088C3F2 /* FLEXRuntimeUtility.h */,
|
||||
3A4C945C1B5B21410088C3F2 /* FLEXRuntimeUtility.m */,
|
||||
3A4C945D1B5B21410088C3F2 /* FLEXUtility.h */,
|
||||
@@ -500,12 +521,14 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A4C94671B5B21410088C3F2 /* ArgumentInputViews */,
|
||||
3A4C94821B5B21410088C3F2 /* FLEXDefaultEditorViewController.h */,
|
||||
3A4C94831B5B21410088C3F2 /* FLEXDefaultEditorViewController.m */,
|
||||
3A4C94841B5B21410088C3F2 /* FLEXFieldEditorView.h */,
|
||||
3A4C94851B5B21410088C3F2 /* FLEXFieldEditorView.m */,
|
||||
3A4C94861B5B21410088C3F2 /* FLEXFieldEditorViewController.h */,
|
||||
3A4C94871B5B21410088C3F2 /* FLEXFieldEditorViewController.m */,
|
||||
C3DA55FC21A76406005DDA60 /* FLEXMutableFieldEditorViewController.h */,
|
||||
C3DA55FD21A76406005DDA60 /* FLEXMutableFieldEditorViewController.m */,
|
||||
3A4C94821B5B21410088C3F2 /* FLEXDefaultEditorViewController.h */,
|
||||
3A4C94831B5B21410088C3F2 /* FLEXDefaultEditorViewController.m */,
|
||||
3A4C94881B5B21410088C3F2 /* FLEXIvarEditorViewController.h */,
|
||||
3A4C94891B5B21410088C3F2 /* FLEXIvarEditorViewController.m */,
|
||||
3A4C948A1B5B21410088C3F2 /* FLEXMethodCallingViewController.h */,
|
||||
@@ -564,6 +587,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
779B1EBF1C0C4D7C001F5E49 /* DatabaseBrowser */,
|
||||
3A4C94AD1B5B21410088C3F2 /* SystemLog */,
|
||||
3A4C949B1B5B21410088C3F2 /* FLEXClassesTableViewController.h */,
|
||||
3A4C949C1B5B21410088C3F2 /* FLEXClassesTableViewController.m */,
|
||||
3A4C949D1B5B21410088C3F2 /* FLEXFileBrowserFileOperationController.h */,
|
||||
@@ -586,7 +610,6 @@
|
||||
679F64851BD53B7B00A8C94C /* FLEXCookiesTableViewController.m */,
|
||||
3A4C94AB1B5B21410088C3F2 /* FLEXWebViewController.h */,
|
||||
3A4C94AC1B5B21410088C3F2 /* FLEXWebViewController.m */,
|
||||
3A4C94AD1B5B21410088C3F2 /* SystemLog */,
|
||||
);
|
||||
path = GlobalStateExplorers;
|
||||
sourceTree = "<group>";
|
||||
@@ -600,6 +623,12 @@
|
||||
3A4C94B11B5B21410088C3F2 /* FLEXSystemLogTableViewCell.m */,
|
||||
3A4C94B21B5B21410088C3F2 /* FLEXSystemLogTableViewController.h */,
|
||||
3A4C94B31B5B21410088C3F2 /* FLEXSystemLogTableViewController.m */,
|
||||
C309B82D223ED64400B228EC /* FLEXLogController.h */,
|
||||
C33E46AD223B02CD004BD0E6 /* FLEXASLLogController.h */,
|
||||
C33E46AE223B02CD004BD0E6 /* FLEXASLLogController.m */,
|
||||
C34EE30621CB23CC00BD3A7C /* FLEXOSLogController.h */,
|
||||
C34EE30721CB23CC00BD3A7C /* FLEXOSLogController.m */,
|
||||
C34EE30A21CB249E00BD3A7C /* ActivityStreamAPI.h */,
|
||||
);
|
||||
path = SystemLog;
|
||||
sourceTree = "<group>";
|
||||
@@ -701,6 +730,7 @@
|
||||
779B1EDA1C0C4D7C001F5E49 /* FLEXTableListViewController.h in Headers */,
|
||||
3A4C94ED1B5B21410088C3F2 /* FLEXArgumentInputColorView.h in Headers */,
|
||||
3A4C94EB1B5B21410088C3F2 /* FLEXImagePreviewViewController.h in Headers */,
|
||||
C3DA55FE21A76406005DDA60 /* FLEXMutableFieldEditorViewController.h in Headers */,
|
||||
3A4C95381B5B21410088C3F2 /* FLEXNetworkRecorder.h in Headers */,
|
||||
3A4C94251B5B20570088C3F2 /* FLEX.h in Headers */,
|
||||
3A4C95051B5B21410088C3F2 /* FLEXArgumentInputViewFactory.h in Headers */,
|
||||
@@ -710,6 +740,7 @@
|
||||
3A4C94FD1B5B21410088C3F2 /* FLEXArgumentInputStructView.h in Headers */,
|
||||
94A515141C4CA1C00063292F /* FLEXManager.h in Headers */,
|
||||
3A4C95201B5B21410088C3F2 /* FLEXFileBrowserFileOperationController.h in Headers */,
|
||||
C37A0C93218BAC9600848CA7 /* FLEXObjcInternal.h in Headers */,
|
||||
3A4C953E1B5B21410088C3F2 /* FLEXNetworkTransactionDetailTableViewController.h in Headers */,
|
||||
3A4C95301B5B21410088C3F2 /* FLEXSystemLogMessage.h in Headers */,
|
||||
3A4C95361B5B21410088C3F2 /* FLEXNetworkHistoryTableViewController.h in Headers */,
|
||||
@@ -734,6 +765,8 @@
|
||||
779B1ED61C0C4D7C001F5E49 /* FLEXTableContentViewController.h in Headers */,
|
||||
3A4C94C91B5B21410088C3F2 /* FLEXDefaultsExplorerViewController.h in Headers */,
|
||||
3A4C95221B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h in Headers */,
|
||||
C33E46AF223B02CD004BD0E6 /* FLEXASLLogController.h in Headers */,
|
||||
C34EE30821CB23CC00BD3A7C /* FLEXOSLogController.h in Headers */,
|
||||
3A4C94FF1B5B21410088C3F2 /* FLEXArgumentInputSwitchView.h in Headers */,
|
||||
3A4C94E71B5B21410088C3F2 /* FLEXHierarchyTableViewCell.h in Headers */,
|
||||
224D49AA1C673AB5000EAB86 /* FLEXSQLiteDatabaseManager.h in Headers */,
|
||||
@@ -742,6 +775,7 @@
|
||||
3A4C94C51B5B21410088C3F2 /* FLEXArrayExplorerViewController.h in Headers */,
|
||||
3A4C94CB1B5B21410088C3F2 /* FLEXDictionaryExplorerViewController.h in Headers */,
|
||||
3A4C95071B5B21410088C3F2 /* FLEXDefaultEditorViewController.h in Headers */,
|
||||
C309B82F223ED64400B228EC /* FLEXLogController.h in Headers */,
|
||||
94A5151F1C4CA1F10063292F /* FLEXWindow.h in Headers */,
|
||||
779B1ECE1C0C4D7C001F5E49 /* FLEXDatabaseManager.h in Headers */,
|
||||
3A4C94D51B5B21410088C3F2 /* FLEXObjectExplorerViewController.h in Headers */,
|
||||
@@ -844,6 +878,7 @@
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
);
|
||||
mainGroup = 3A4C94151B5B20570088C3F2;
|
||||
@@ -895,6 +930,7 @@
|
||||
3A4C95121B5B21410088C3F2 /* FLEXPropertyEditorViewController.m in Sources */,
|
||||
3A4C95391B5B21410088C3F2 /* FLEXNetworkRecorder.m in Sources */,
|
||||
3A4C950E1B5B21410088C3F2 /* FLEXIvarEditorViewController.m in Sources */,
|
||||
C3DC287C223ED5F200F48AA6 /* FLEXOSLogController.m in Sources */,
|
||||
3A4C95101B5B21410088C3F2 /* FLEXMethodCallingViewController.m in Sources */,
|
||||
3A4C94F61B5B21410088C3F2 /* FLEXArgumentInputJSONObjectView.m in Sources */,
|
||||
3A4C94EC1B5B21410088C3F2 /* FLEXImagePreviewViewController.m in Sources */,
|
||||
@@ -902,6 +938,7 @@
|
||||
94AAF0391BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m in Sources */,
|
||||
3A4C951F1B5B21410088C3F2 /* FLEXClassesTableViewController.m in Sources */,
|
||||
3A4C94C61B5B21410088C3F2 /* FLEXArrayExplorerViewController.m in Sources */,
|
||||
C3DA55FF21A76406005DDA60 /* FLEXMutableFieldEditorViewController.m in Sources */,
|
||||
3A4C95081B5B21410088C3F2 /* FLEXDefaultEditorViewController.m in Sources */,
|
||||
779B1ED11C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m in Sources */,
|
||||
3A4C94EE1B5B21410088C3F2 /* FLEXArgumentInputColorView.m in Sources */,
|
||||
@@ -939,6 +976,7 @@
|
||||
3A4C95351B5B21410088C3F2 /* FLEXSystemLogTableViewController.m in Sources */,
|
||||
3A4C95271B5B21410088C3F2 /* FLEXGlobalsTableViewController.m in Sources */,
|
||||
779B1ED31C0C4D7C001F5E49 /* FLEXTableColumnHeader.m in Sources */,
|
||||
C37A0C94218BAC9600848CA7 /* FLEXObjcInternal.mm in Sources */,
|
||||
3A4C94EA1B5B21410088C3F2 /* FLEXHierarchyTableViewController.m in Sources */,
|
||||
3A4C95331B5B21410088C3F2 /* FLEXSystemLogTableViewCell.m in Sources */,
|
||||
C3DB9F652107FC9600B46809 /* FLEXObjectRef.m in Sources */,
|
||||
@@ -956,6 +994,7 @@
|
||||
3A4C95231B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m in Sources */,
|
||||
3A4C950C1B5B21410088C3F2 /* FLEXFieldEditorViewController.m in Sources */,
|
||||
3A4C952D1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.m in Sources */,
|
||||
C33E46B0223B02CD004BD0E6 /* FLEXASLLogController.m in Sources */,
|
||||
3A4C953D1B5B21410088C3F2 /* FLEXNetworkTransaction.m in Sources */,
|
||||
3A4C94E81B5B21410088C3F2 /* FLEXHierarchyTableViewCell.m in Sources */,
|
||||
3A4C94C81B5B21410088C3F2 /* FLEXClassExplorerViewController.m in Sources */,
|
||||
|
||||
@@ -24,49 +24,43 @@
|
||||
|
||||
@implementation FLEXTestMethodList
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testExample {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
[self testMethodListForClass:[NSObject class]];
|
||||
[self testMethodListForClass:[NSArray class]];
|
||||
[self testMethodListForClass:[UIApplication class]];
|
||||
[self testMethodListForClass:[UIView class]];
|
||||
[self testMethodListForClass:[NSThread class]];
|
||||
[self testMethodListForClass:[CALayer class]];
|
||||
[self testMethodListForClass:[NSDictionary class]];
|
||||
[self testMethodListForClass:[NSProxy class]];
|
||||
[self testMethodListForClass:[NSData class]];
|
||||
[self testMethodListForClass:[FLEXManager class]];
|
||||
[self testMethodListForClass:[FLEXWindow class]];
|
||||
[self testMethodListForClass:[FLEXMultiColumnTableView class]];
|
||||
[self testMethodListForClass:[NSString class]];
|
||||
[self testMethodListForClass:[NSSet class]];
|
||||
[self testMethodListForClass:[NSUndoManager class]];
|
||||
[self testMethodListForClass:[NSMutableArray class]];
|
||||
[self testMethodListForClass:[NSMutableDictionary class]];
|
||||
[self testMethodListForClass:[NSException class]];
|
||||
[self testMethodListForClass:[UIImage class]];
|
||||
[self testMethodListForClass:[UIViewController class]];
|
||||
[self testMethodListForClass:[UIScreen class]];
|
||||
[self testMethodListForClass:[UIResponder class]];
|
||||
[self testMethodListForClass:[NSNumber class]];
|
||||
[self testMethodListForClass:[NSValue class]];
|
||||
[self testMethodListForClass:[NSError class]];
|
||||
[self testMethodListForClass:[NSNotificationCenter class]];
|
||||
[self testMethodListForClass:[NSUserActivity class]];
|
||||
[self testMethodListForClass:[NSUserDefaults class]];
|
||||
[self testMethodListForClass:[NSExpression class]];
|
||||
[self testMethodListForClass:[NSBundle class]];
|
||||
NSArray<Class> *classesToTest = @[
|
||||
[NSObject class],
|
||||
[NSArray class],
|
||||
[UIApplication class],
|
||||
[UIView class],
|
||||
[NSThread class],
|
||||
[CALayer class],
|
||||
[NSDictionary class],
|
||||
[NSProxy class],
|
||||
[NSData class],
|
||||
[FLEXManager class],
|
||||
[FLEXWindow class],
|
||||
[FLEXMultiColumnTableView class],
|
||||
[NSString class],
|
||||
[NSSet class],
|
||||
[NSUndoManager class],
|
||||
[NSMutableArray class],
|
||||
[NSMutableDictionary class],
|
||||
[NSException class],
|
||||
[UIImage class],
|
||||
[UIViewController class],
|
||||
[UIScreen class],
|
||||
[UIResponder class],
|
||||
[NSNumber class],
|
||||
[NSValue class],
|
||||
[NSError class],
|
||||
[NSNotificationCenter class],
|
||||
[NSUserActivity class],
|
||||
[NSUserDefaults class],
|
||||
[NSExpression class],
|
||||
[NSBundle class]
|
||||
];
|
||||
|
||||
for (Class cls in classesToTest) {
|
||||
[self testMethodListForClass:cls];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testMethodListForClass:(Class)class {
|
||||
@@ -75,27 +69,15 @@
|
||||
Method *methods = class_copyMethodList(class, &methodCount);
|
||||
for (unsigned int i = 0; i < methodCount; ++i) {
|
||||
Method method = methods[i];
|
||||
NSString *selectorName = NSStringFromSelector(method_getName(method));
|
||||
NSArray *prevWay = [self prettyArgumentComponentsForMethod:method];
|
||||
if (![prevWay count]) {
|
||||
prevWay = @[ selectorName ];
|
||||
}
|
||||
|
||||
NSArray *newWay = [FLEXRuntimeUtility prettyArgumentComponentsForMethod:method];
|
||||
|
||||
XCTAssert([newWay isEqual:prevWay]);
|
||||
XCTAssertEqualObjects(prevWay, newWay);
|
||||
}
|
||||
|
||||
free(methods);
|
||||
}
|
||||
|
||||
- (void)testPerformanceExample {
|
||||
// This is an example of a performance test case.
|
||||
[self measureBlock:^{
|
||||
// Put the code you want to measure the time of here.
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Method to test with
|
||||
|
||||
- (NSArray *)prettyArgumentComponentsForMethod:(Method)method {
|
||||
|
||||
Reference in New Issue
Block a user