mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-08-25 11:55:28 -04:00
added files via upload
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// FLEXRuntimeKeyPathTokenizer.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner on 3/22/17.
|
||||
// Copyright © 2017 Tanner Bennett. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXRuntimeKeyPathTokenizer.h"
|
||||
|
||||
#define TBCountOfStringOccurence(target, str) ([target componentsSeparatedByString:str].count - 1)
|
||||
|
||||
@implementation FLEXRuntimeKeyPathTokenizer
|
||||
|
||||
#pragma mark Initialization
|
||||
|
||||
static NSCharacterSet *firstAllowed = nil;
|
||||
static NSCharacterSet *identifierAllowed = nil;
|
||||
static NSCharacterSet *filenameAllowed = nil;
|
||||
static NSCharacterSet *keyPathDisallowed = nil;
|
||||
static NSCharacterSet *methodAllowed = nil;
|
||||
+ (void)initialize {
|
||||
if (self == [self class]) {
|
||||
NSString *_methodFirstAllowed = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
|
||||
NSString *_identifierAllowed = [_methodFirstAllowed stringByAppendingString:@"1234567890"];
|
||||
NSString *_methodAllowedSansType = [_identifierAllowed stringByAppendingString:@":"];
|
||||
NSString *_filenameNameAllowed = [_identifierAllowed stringByAppendingString:@"-+?!"];
|
||||
firstAllowed = [NSCharacterSet characterSetWithCharactersInString:_methodFirstAllowed];
|
||||
identifierAllowed = [NSCharacterSet characterSetWithCharactersInString:_identifierAllowed];
|
||||
filenameAllowed = [NSCharacterSet characterSetWithCharactersInString:_filenameNameAllowed];
|
||||
methodAllowed = [NSCharacterSet characterSetWithCharactersInString:_methodAllowedSansType];
|
||||
|
||||
NSString *_kpDisallowed = [_identifierAllowed stringByAppendingString:@"-+:\\.*"];
|
||||
keyPathDisallowed = [NSCharacterSet characterSetWithCharactersInString:_kpDisallowed].invertedSet;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Public
|
||||
|
||||
+ (FLEXRuntimeKeyPath *)tokenizeString:(NSString *)userInput {
|
||||
if (!userInput.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSUInteger tokens = [self tokenCountOfString:userInput];
|
||||
if (tokens == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([userInput containsString:@"**"]) {
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
|
||||
NSNumber *instance = nil;
|
||||
NSScanner *scanner = [NSScanner scannerWithString:userInput];
|
||||
FLEXSearchToken *bundle = [self scanToken:scanner allowed:filenameAllowed first:filenameAllowed];
|
||||
FLEXSearchToken *cls = [self scanToken:scanner allowed:identifierAllowed first:firstAllowed];
|
||||
FLEXSearchToken *method = tokens > 2 ? [self scanMethodToken:scanner instance:&instance] : nil;
|
||||
|
||||
return [FLEXRuntimeKeyPath bundle:bundle
|
||||
class:cls
|
||||
method:method
|
||||
isInstance:instance
|
||||
string:userInput];
|
||||
}
|
||||
|
||||
+ (BOOL)allowedInKeyPath:(NSString *)text {
|
||||
if (!text.length) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return [text rangeOfCharacterFromSet:keyPathDisallowed].location == NSNotFound;
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
+ (NSUInteger)tokenCountOfString:(NSString *)userInput {
|
||||
NSUInteger escapedCount = TBCountOfStringOccurence(userInput, @"\\.");
|
||||
NSUInteger tokenCount = TBCountOfStringOccurence(userInput, @".") - escapedCount + 1;
|
||||
|
||||
return tokenCount;
|
||||
}
|
||||
|
||||
+ (FLEXSearchToken *)scanToken:(NSScanner *)scanner allowed:(NSCharacterSet *)allowedChars first:(NSCharacterSet *)first {
|
||||
if (scanner.isAtEnd) {
|
||||
if ([scanner.string hasSuffix:@"."] && ![scanner.string hasSuffix:@"\\."]) {
|
||||
return [FLEXSearchToken string:nil options:TBWildcardOptionsAny];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
TBWildcardOptions options = TBWildcardOptionsNone;
|
||||
NSMutableString *token = [NSMutableString new];
|
||||
|
||||
// Token cannot start with '.'
|
||||
if ([scanner scanString:@"." intoString:nil]) {
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
|
||||
if ([scanner scanString:@"*." intoString:nil]) {
|
||||
return [FLEXSearchToken string:nil options:TBWildcardOptionsAny];
|
||||
} else if ([scanner scanString:@"*" intoString:nil]) {
|
||||
if (scanner.isAtEnd) {
|
||||
return FLEXSearchToken.any;
|
||||
}
|
||||
|
||||
options |= TBWildcardOptionsPrefix;
|
||||
}
|
||||
|
||||
NSString *tmp = nil;
|
||||
BOOL stop = NO, didScanDelimiter = NO, didScanFirstAllowed = NO;
|
||||
NSCharacterSet *disallowed = allowedChars.invertedSet;
|
||||
while (!stop && ![scanner scanString:@"." intoString:&tmp] && !scanner.isAtEnd) {
|
||||
// Scan word chars
|
||||
// In this block, we have not scanned anything yet, except maybe leading '\' or '\.'
|
||||
if (!didScanFirstAllowed) {
|
||||
if ([scanner scanCharactersFromSet:first intoString:&tmp]) {
|
||||
[token appendString:tmp];
|
||||
didScanFirstAllowed = YES;
|
||||
} else if ([scanner scanString:@"\\" intoString:nil]) {
|
||||
if (options == TBWildcardOptionsPrefix && [scanner scanString:@"." intoString:nil]) {
|
||||
[token appendString:@"."];
|
||||
} else if (scanner.isAtEnd && options == TBWildcardOptionsPrefix) {
|
||||
// Only allow standalone '\' if prefixed by '*'
|
||||
return FLEXSearchToken.any;
|
||||
} else {
|
||||
// Token starts with a number, period, or something else not allowed,
|
||||
// or token is a standalone '\' with no '*' prefix
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
} else {
|
||||
// Token starts with a number, period, or something else not allowed
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
} else if ([scanner scanCharactersFromSet:allowedChars intoString:&tmp]) {
|
||||
[token appendString:tmp];
|
||||
}
|
||||
// Scan '\.' or trailing '\'
|
||||
else if ([scanner scanString:@"\\" intoString:nil]) {
|
||||
if ([scanner scanString:@"." intoString:nil]) {
|
||||
[token appendString:@"."];
|
||||
} else if (scanner.isAtEnd) {
|
||||
// Ignore forward slash not followed by period if at end
|
||||
return [FLEXSearchToken string:token options:options | TBWildcardOptionsSuffix];
|
||||
} else {
|
||||
// Only periods can follow a forward slash
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
}
|
||||
// Scan '*.'
|
||||
else if ([scanner scanString:@"*." intoString:nil]) {
|
||||
options |= TBWildcardOptionsSuffix;
|
||||
stop = YES;
|
||||
didScanDelimiter = YES;
|
||||
}
|
||||
// Scan '*' not followed by .
|
||||
else if ([scanner scanString:@"*" intoString:nil]) {
|
||||
if (!scanner.isAtEnd) {
|
||||
// Invalid token, wildcard in middle of token
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
} else if ([scanner scanCharactersFromSet:disallowed intoString:nil]) {
|
||||
// Invalid token, invalid characters
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
}
|
||||
|
||||
// Did we scan a trailing, un-escsaped '.'?
|
||||
if ([tmp isEqualToString:@"."]) {
|
||||
didScanDelimiter = YES;
|
||||
}
|
||||
|
||||
if (!didScanDelimiter) {
|
||||
options |= TBWildcardOptionsSuffix;
|
||||
}
|
||||
|
||||
return [FLEXSearchToken string:token options:options];
|
||||
}
|
||||
|
||||
+ (FLEXSearchToken *)scanMethodToken:(NSScanner *)scanner instance:(NSNumber **)instance {
|
||||
if (scanner.isAtEnd) {
|
||||
if ([scanner.string hasSuffix:@"."]) {
|
||||
return [FLEXSearchToken string:nil options:TBWildcardOptionsAny];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([scanner.string hasSuffix:@"."] && ![scanner.string hasSuffix:@"\\."]) {
|
||||
// Methods cannot end with '.' except for '\.'
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
|
||||
if ([scanner scanString:@"-" intoString:nil]) {
|
||||
*instance = @YES;
|
||||
} else if ([scanner scanString:@"+" intoString:nil]) {
|
||||
*instance = @NO;
|
||||
} else {
|
||||
if ([scanner scanString:@"*" intoString:nil]) {
|
||||
// Just checking... It has to start with one of these three!
|
||||
scanner.scanLocation--;
|
||||
} else {
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
}
|
||||
|
||||
// -*foo not allowed
|
||||
if (*instance && [scanner scanString:@"*" intoString:nil]) {
|
||||
@throw NSInternalInconsistencyException;
|
||||
}
|
||||
|
||||
if (scanner.isAtEnd) {
|
||||
return [FLEXSearchToken string:@"" options:TBWildcardOptionsSuffix];
|
||||
}
|
||||
|
||||
return [self scanToken:scanner allowed:methodAllowed first:firstAllowed];
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user