mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-10-31 21:04:13 -04:00
159 lines
4.6 KiB
Objective-C
159 lines
4.6 KiB
Objective-C
//
|
|
// FLEXIvar.m
|
|
// FLEX
|
|
//
|
|
// Derived from MirrorKit.
|
|
// Created by Tanner on 6/30/15.
|
|
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
|
//
|
|
|
|
#import "FLEXIvar.h"
|
|
#import "FLEXRuntimeUtility.h"
|
|
#import "FLEXRuntimeSafety.h"
|
|
#import "FLEXTypeEncodingParser.h"
|
|
#import "NSString+FLEX.h"
|
|
#include "FLEXObjcInternal.h"
|
|
#include <dlfcn.h>
|
|
|
|
@interface FLEXIvar () {
|
|
NSString *_flex_description;
|
|
}
|
|
@end
|
|
|
|
@implementation FLEXIvar
|
|
|
|
#pragma mark Initializers
|
|
|
|
+ (instancetype)ivar:(Ivar)ivar {
|
|
return [[self alloc] initWithIvar:ivar];
|
|
}
|
|
|
|
+ (instancetype)named:(NSString *)name onClass:(Class)cls {
|
|
Ivar _Nullable ivar = class_getInstanceVariable(cls, name.UTF8String);
|
|
NSAssert(ivar, @"Cannot find ivar with name %@ on class %@", name, cls);
|
|
return [self ivar:ivar];
|
|
}
|
|
|
|
- (id)initWithIvar:(Ivar)ivar {
|
|
NSParameterAssert(ivar);
|
|
|
|
self = [super init];
|
|
if (self) {
|
|
_objc_ivar = ivar;
|
|
[self examine];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
#pragma mark Other
|
|
|
|
- (NSString *)description {
|
|
if (!_flex_description) {
|
|
NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.typeEncoding];
|
|
_flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType];
|
|
}
|
|
|
|
return _flex_description;
|
|
}
|
|
|
|
- (NSString *)debugDescription {
|
|
return [NSString stringWithFormat:@"<%@ name=%@, encoding=%@, offset=%ld>",
|
|
NSStringFromClass(self.class), self.name, self.typeEncoding, (long)self.offset];
|
|
}
|
|
|
|
- (void)examine {
|
|
_name = @(ivar_getName(self.objc_ivar) ?: "(nil)");
|
|
_offset = ivar_getOffset(self.objc_ivar);
|
|
_typeEncoding = @(ivar_getTypeEncoding(self.objc_ivar) ?: "");
|
|
|
|
NSString *typeForDetails = _typeEncoding;
|
|
NSString *sizeForDetails = nil;
|
|
if (_typeEncoding.length) {
|
|
_type = (FLEXTypeEncoding)[_typeEncoding characterAtIndex:0];
|
|
FLEXGetSizeAndAlignment(_typeEncoding.UTF8String, &_size, nil);
|
|
sizeForDetails = [@(_size).stringValue stringByAppendingString:@" bytes"];
|
|
} else {
|
|
_type = FLEXTypeEncodingNull;
|
|
typeForDetails = @"no type info";
|
|
sizeForDetails = @"unknown size";
|
|
}
|
|
|
|
Dl_info exeInfo;
|
|
if (dladdr(_objc_ivar, &exeInfo)) {
|
|
_imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
|
|
}
|
|
|
|
_details = [NSString stringWithFormat:
|
|
@"%@, offset %@ — %@",
|
|
sizeForDetails, @(_offset), typeForDetails
|
|
];
|
|
}
|
|
|
|
- (id)getValue:(id)target {
|
|
id value = nil;
|
|
if (!FLEXIvarIsSafe(_objc_ivar) ||
|
|
_type == FLEXTypeEncodingNull ||
|
|
FLEXPointerIsTaggedPointer(target)) {
|
|
return nil;
|
|
}
|
|
|
|
#ifdef __arm64__
|
|
// See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
|
|
if (self.type == FLEXTypeEncodingObjcClass && [self.name isEqualToString:@"isa"]) {
|
|
value = object_getClass(target);
|
|
} else
|
|
#endif
|
|
if (self.type == FLEXTypeEncodingObjcObject || self.type == FLEXTypeEncodingObjcClass) {
|
|
value = object_getIvar(target, self.objc_ivar);
|
|
} else {
|
|
void *pointer = (__bridge void *)target + self.offset;
|
|
value = [FLEXRuntimeUtility
|
|
valueForPrimitivePointer:pointer
|
|
objCType:self.typeEncoding.UTF8String
|
|
];
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
- (void)setValue:(id)value onObject:(id)target {
|
|
const char *typeEncodingCString = self.typeEncoding.UTF8String;
|
|
if (self.type == FLEXTypeEncodingObjcObject) {
|
|
object_setIvar(target, self.objc_ivar, value);
|
|
} else if ([value isKindOfClass:[NSValue class]]) {
|
|
// Primitive - unbox the NSValue.
|
|
NSValue *valueValue = (NSValue *)value;
|
|
|
|
// Make sure that the box contained the correct type.
|
|
NSAssert(
|
|
strcmp(valueValue.objCType, typeEncodingCString) == 0,
|
|
@"Type encoding mismatch (value: %s; ivar: %s) in setting ivar named: %@ on object: %@",
|
|
valueValue.objCType, typeEncodingCString, self.name, target
|
|
);
|
|
|
|
NSUInteger bufferSize = 0;
|
|
if (FLEXGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL)) {
|
|
void *buffer = calloc(bufferSize, 1);
|
|
[valueValue getValue:buffer];
|
|
void *pointer = (__bridge void *)target + self.offset;
|
|
memcpy(pointer, buffer, bufferSize);
|
|
free(buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (id)getPotentiallyUnboxedValue:(id)target {
|
|
NSString *type = self.typeEncoding;
|
|
if (type.flex_typeIsNonObjcPointer && type.flex_pointeeType != FLEXTypeEncodingVoid) {
|
|
return [self getValue:target];
|
|
}
|
|
|
|
return [FLEXRuntimeUtility
|
|
potentiallyUnwrapBoxedPointer:[self getValue:target]
|
|
type:type.UTF8String
|
|
];
|
|
}
|
|
|
|
@end
|