From 46d20228ae7965256c689a1a92313209b70de8f1 Mon Sep 17 00:00:00 2001 From: michael starke Date: Tue, 7 Nov 2017 18:24:36 +0100 Subject: [PATCH] started refactoring autotype system to use tokenizer --- MacPass/MPToken.h | 22 ++++++ MacPass/MPToken.m | 147 +++++++++++++++++++++++++++++++++++++ MacPassTests/MPTestToken.m | 32 ++++++++ 3 files changed, 201 insertions(+) create mode 100644 MacPass/MPToken.h create mode 100644 MacPass/MPToken.m create mode 100644 MacPassTests/MPTestToken.m diff --git a/MacPass/MPToken.h b/MacPass/MPToken.h new file mode 100644 index 00000000..cddd50d6 --- /dev/null +++ b/MacPass/MPToken.h @@ -0,0 +1,22 @@ +// +// MPToken.h +// MacPass +// +// Created by Michael Starke on 07.11.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MPToken : NSObject + +@property (readonly, copy) NSString *value; + ++ (NSArray *)tokenizeString:(NSString *)string; +- (instancetype)initWithValue:(NSString *)value NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MacPass/MPToken.m b/MacPass/MPToken.m new file mode 100644 index 00000000..cb9be4f3 --- /dev/null +++ b/MacPass/MPToken.m @@ -0,0 +1,147 @@ +// +// MPToken.m +// MacPass +// +// Created by Michael Starke on 07.11.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import "MPToken.h" + +#import +#import + +@interface NSString (MPTokenExtension) +@property (nonatomic, readonly) BOOL isOpenCurlyBraket; +@property (nonatomic, readonly) BOOL isClosingCurlyBraket; +@end + +@implementation NSString (MPTokenExtension) + +- (BOOL)isOpenCurlyBraket { + return [self isEqualToString:@"{"]; +} + +- (BOOL)isClosingCurlyBraket { + return [self isEqualToString:@"}"]; +} + +@end + +@interface MPToken () + +@property (copy) NSString *value; + +@end + +typedef NS_ENUM(NSInteger, MPTokenizeState) { + MPTokenizeStateNormal, + MPTokenizeStateCompoundToken, + MPTokenizerStateError +}; + +@implementation MPToken + +/** + * Mapping for modifier to CGEventFlags. + * + * @return dictionary with commands as keys and CGEventFlags as wrapped values + */ ++ (NSDictionary *)_modifierCommands { + static NSDictionary *modifierCommands; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + modifierCommands = @{ + kKPKAutotypeAlt : @(kCGEventFlagMaskAlternate), + kKPKAutotypeControl : @(kCGEventFlagMaskControl), + kKPKAutotypeShift : @(kCGEventFlagMaskShift) + }; + }); + return modifierCommands; +} + ++ (NSArray *)tokenizeString:(NSString *)string { + if(!string) { + return nil; + } + __block NSMutableString *tokenValue = [[NSMutableString alloc] init]; + __block MPTokenizeState state = MPTokenizeStateNormal; + __block NSMutableArray *tokens = [[NSMutableArray alloc] initWithCapacity:MAX(1,string.length)]; + [string enumerateSubstringsInRange:NSMakeRange(0, string.length) + options:NSStringEnumerationByComposedCharacterSequences + usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) { + switch(state) { + case MPTokenizeStateNormal: { + if(substring.isOpenCurlyBraket) { + [tokenValue setString:@"{"]; + state = MPTokenizeStateCompoundToken; + } + else if(substring.isClosingCurlyBraket) { + state = MPTokenizerStateError; + } + else { + MPToken *token = [[MPToken alloc] initWithValue:substring]; + if(token) { + [tokens addObject:token]; + } + else { + state = MPTokenizerStateError; + } + } + break; + } + case MPTokenizeStateCompoundToken: { + if(substring.isOpenCurlyBraket) { + state = MPTokenizerStateError; + } + else if(substring.isClosingCurlyBraket) { + state = MPTokenizeStateNormal; + [tokenValue appendString:@"}"]; + MPToken *token = [[MPToken alloc] initWithValue:tokenValue]; + if(token) { + [tokens addObject:token]; + } + else { + state = MPTokenizerStateError; + } + /* clear tokenvalue */ + [tokenValue setString:@""]; + } + else { + [tokenValue appendString:substring]; + } + break; + } + case MPTokenizerStateError: + default: + state = MPTokenizerStateError; + *stop = YES; + break; + } + }]; + return [tokens copy]; +} + +- (instancetype)init { + self = [self initWithValue:@""]; + return self; +} + +- (instancetype)initWithValue:(NSString *)value { + if(!value) { + [[NSException exceptionWithName:NSInvalidArgumentException reason:@"Token vale cannot be nil!" userInfo:nil] raise]; + self = nil; + return self; + } + self = [super init]; + if(self) { + _value = [value copy]; + } + return self; +} + +- (NSString *)description { + return self.value.description; +} + +@end diff --git a/MacPassTests/MPTestToken.m b/MacPassTests/MPTestToken.m new file mode 100644 index 00000000..a79c7971 --- /dev/null +++ b/MacPassTests/MPTestToken.m @@ -0,0 +1,32 @@ +// +// MPTestToken.m +// MacPassTests +// +// Created by Michael Starke on 07.11.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import +#import "MPToken.h" + +@interface MPTestToken : XCTestCase + +@end + +@implementation MPTestToken + +- (void)setUp { + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testTokenizing { + NSArray *tokens =[MPToken tokenizeString:@"{^}{USERNAME}^S+H{SPACE}"]; + XCTAssertEqual(7, tokens.count); +} + + +@end