#import #include "jni.h" #include #include #include #include #include "utils.h" CFTypeRef SecTaskCopyValueForEntitlement(void* task, NSString* entitlement, CFErrorRef _Nullable *error); void* SecTaskCreateFromSelf(CFAllocatorRef allocator); BOOL getEntitlementValue(NSString *key) { void *secTask = SecTaskCreateFromSelf(NULL); CFTypeRef value = SecTaskCopyValueForEntitlement(SecTaskCreateFromSelf(NULL), key, nil); if (value != nil) { CFRelease(value); } CFRelease(secTask); return value != nil && [(__bridge id)value boolValue]; } BOOL isJITEnabled(BOOL checkCSFlags) { if (!checkCSFlags && (getEntitlementValue(@"dynamic-codesigning") || isJailbroken)) { return YES; } int flags; csops(getpid(), 0, &flags, sizeof(flags)); return (flags & CS_DEBUGGED) != 0; } void openLink(UIViewController* sender, NSURL* link) { if (NSClassFromString(@"SFSafariViewController") == nil) { NSData *data = [link.absoluteString dataUsingEncoding:NSUTF8StringEncoding]; CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; [filter setValue:data forKey:@"inputMessage"]; UIImage *image = [UIImage imageWithCIImage:filter.outputImage scale:1.0 orientation:UIImageOrientationUp]; UIGraphicsBeginImageContextWithOptions(CGSizeMake(300, 300), NO, 0.0); CGRect frame = CGRectMake(0, 0, 300, 300); [image drawInRect:frame]; UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame]; imageView.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); UIAlertController* alert = [UIAlertController alertControllerWithTitle:nil message:link.absoluteString preferredStyle:UIAlertControllerStyleAlert]; UIViewController *vc = UIViewController.new; vc.view = imageView; [alert setValue:vc forKey:@"contentViewController"]; UIAlertAction* doneAction = [UIAlertAction actionWithTitle:localize(@"Done", nil) style:UIAlertActionStyleCancel handler:nil]; [alert addAction:doneAction]; [sender presentViewController:alert animated:YES completion:nil]; } else { SFSafariViewController *vc = [[SFSafariViewController alloc] initWithURL:link]; [sender presentViewController:vc animated:YES completion:nil]; } } NSMutableDictionary* parseJSONFromFile(NSString *path) { NSError *error; NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; if (content == nil) { NSLog(@"[ParseJSON] Error: could not read %@: %@", path, error.localizedDescription); return @{@"NSErrorObject": error}.mutableCopy; } NSData* data = [content dataUsingEncoding:NSUTF8StringEncoding]; NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error]; if (error) { NSLog(@"[ParseJSON] Error: could not parse JSON: %@", error.localizedDescription); return @{@"NSErrorObject": error}.mutableCopy; } return dict; } NSError* saveJSONToFile(NSDictionary *dict, NSString *path) { // TODO: handle rename NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error]; if (jsonData == nil) { return error; } BOOL success = [jsonData writeToFile:path options:NSDataWritingAtomic error:&error]; if (!success) { return error; } return nil; } NSString* localize(NSString* key, NSString* comment) { NSString *value = NSLocalizedString(key, nil); if (![NSLocale.preferredLanguages[0] isEqualToString:@"en"] && [value isEqualToString:key]) { NSString* path = [NSBundle.mainBundle pathForResource:@"en" ofType:@"lproj"]; NSBundle* languageBundle = [NSBundle bundleWithPath:path]; value = [languageBundle localizedStringForKey:key value:nil table:nil]; if ([value isEqualToString:key]) { value = [[NSBundle bundleWithIdentifier:@"com.apple.UIKit"] localizedStringForKey:key value:nil table:nil]; } } return value; } void customNSLog(const char *file, int lineNumber, const char *functionName, NSString *format, ...) { va_list ap; va_start (ap, format); NSString *body = [[NSString alloc] initWithFormat:format arguments:ap]; printf("%s", [body UTF8String]); if (![format hasSuffix:@"\n"]) { printf("\n"); } va_end (ap); } CGFloat MathUtils_dist(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) { const CGFloat x = (x2 - x1); const CGFloat y = (y2 - y1); return (CGFloat) hypot(x, y); } //Ported from https://www.arduino.cc/reference/en/language/functions/math/map/ CGFloat MathUtils_map(CGFloat x, CGFloat in_min, CGFloat in_max, CGFloat out_min, CGFloat out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } CGFloat dpToPx(CGFloat dp) { CGFloat screenScale = [[UIScreen mainScreen] scale]; return dp * screenScale; } CGFloat pxToDp(CGFloat px) { CGFloat screenScale = [[UIScreen mainScreen] scale]; return px / screenScale; } void setButtonPointerInteraction(UIButton *button) { button.pointerInteractionEnabled = YES; button.pointerStyleProvider = ^ UIPointerStyle* (UIButton* button, UIPointerEffect* proposedEffect, UIPointerShape* proposedShape) { UITargetedPreview *preview = [[UITargetedPreview alloc] initWithView:button]; return [NSClassFromString(@"UIPointerStyle") styleWithEffect:[NSClassFromString(@"UIPointerHighlightEffect") effectWithPreview:preview] shape:proposedShape]; }; }