// // NSString+Additions.m // Perforce // // Created by Adam Czubernat on 16.05.2013. // Copyright (c) 2013 Perforce Software, Inc. All rights reserved. // #import "NSString+Additions.h" @implementation NSString (Additions) + (NSString *)stringWithTimeInterval:(NSTimeInterval)timeInterval { if (timeInterval == INFINITY) return @"∞"; NSInteger time = (NSInteger)timeInterval; return [NSString stringWithFormat:@"%@%@%@", time < 3600 ? @"" : [NSString stringWithFormat:@"%02ld:", time/3600], time < 60 ? @"" : [NSString stringWithFormat:@"%02ld:", (time/60)%60], [NSString stringWithFormat:(time < 60 ? @"%lds" : @"%02ld"), time%60]]; } + (NSString *)stringWithByteCount:(NSInteger)bytes { NSString *units; int decimals = 0; CGFloat size = bytes; if (size < 1024.0f) units = @"bytes"; else if ((size /= 1024.0f) < 1024.0f) units = @"KB"; else if ((size /= 1024.0f) < 1024.0f) units = @"MB", decimals = 1; else size /= 1024.0f, units = @"GB", decimals = 2; return [NSString stringWithFormat:@"%.*f %@", decimals, size, units]; } - (NSString *)stringByRemovingPrefix:(NSString *)prefix { return ([self hasPrefix:prefix] ? [self substringFromIndex:prefix.length] : self); } - (NSString *)stringByRemovingSuffix:(NSString *)suffix { return ([self hasSuffix:suffix] ? [self substringToIndex:self.length - suffix.length] : self); } - (NSArray *)arrayOfArguments { CFStringRef string = (__bridge CFStringRef)self; CFIndex length = CFStringGetLength(string); NSMutableArray *array = [NSMutableArray arrayWithCapacity:length]; unichar quoteChar; CFIndex bufferLength = 0; unichar *buffer = malloc(sizeof(unichar) * length); BOOL inQuote = NO; for (CFIndex i=0; i<length; i++) { unichar c = CFStringGetCharacterAtIndex(string, i); if (!inQuote && (c==0x0020 || c==0x0009 || c==0x000A || c==0x000D || c==0x0085)) { if (bufferLength) { CFStringRef argument = CFStringCreateWithCharacters(NULL, buffer, bufferLength); [array addObject:CFBridgingRelease(argument)]; bufferLength = 0; } continue; } if ((c=='\'' || c=='"') && (!inQuote || c==quoteChar)) { inQuote = !inQuote; quoteChar = c; continue; } buffer[bufferLength++] = c; } if (bufferLength) { CFStringRef argument = CFStringCreateWithCharacters(NULL, buffer, bufferLength); [array addObject:CFBridgingRelease(argument)]; } free(buffer); return array; } - (CGSize)sizeWithFont:(NSFont *)font { return [self sizeWithAttributes:@{ NSFontAttributeName : font }]; } #pragma mark - Path support - (NSString *)stringByDeletingPath { NSRange range = { 0, self.length-1 }; range = [self rangeOfString:@"/" options:NSBackwardsSearch range:range]; NSUInteger loc = range.location; if (loc != NSNotFound) return [self substringToIndex:loc+1]; return self; } - (NSString *)stringByAppendingPath:(NSString *)path { return ([self hasSuffix:@"/"] ? [self stringByAppendingString:path] : [self stringByAppendingFormat:@"/%@", path]); } - (NSString *)stringByRenamingPath:(NSString *)newName { NSString *newPath = [[self stringByDeletingPath] stringByAppendingPath:newName]; return [self hasSuffix:@"/"] ? [newPath stringByAppendingString:@"/"] : newPath; } - (NSString *)directoryPath { if (self.length) return [self hasSuffix:@"/"] ? self : [self stringByAppendingString:@"/"]; return nil; } - (BOOL)isSubpath:(NSString *)base { NSString *path = [base directoryPath]; return [self hasPrefixCaseInsensitive:path]; } - (NSString *)relativePath:(NSString *)base { NSString *path = [base directoryPath]; if ([self hasPrefixCaseInsensitive:path]) return [self substringFromIndex:path.length]; return nil; } - (BOOL)hasSpecialCharacters { if([self rangeOfString:@"#"].location != NSNotFound) return true; if([self rangeOfString:@"*"].location != NSNotFound) return true; if([self rangeOfString:@"@"].location != NSNotFound) return true; if([self rangeOfString:@"%"].location != NSNotFound) { NSUInteger length = [self length]; NSRange range = NSMakeRange(0, length); while(range.location != NSNotFound) { range = [self rangeOfString: @"%" options:0 range:range]; if(range.location != NSNotFound) { if(range.location + 2 > length) { return true; } NSRange subrange = NSMakeRange(range.location, 3); NSString *code = [self substringWithRange:subrange]; if(!( [code isEqualToString:@"%25"] || [code isEqualToString:@"%23"] || [code isEqualToString:@"%2A"] || [code isEqualToString:@"%40"] )) { return true; } range = NSMakeRange(range.location + range.length, length - (range.location + range.length)); } } } return false; } - (BOOL)hasEncodedCharacters { if(([self rangeOfString:@"%25"].location != NSNotFound) || ([self rangeOfString:@"%23"].location != NSNotFound) || ([self rangeOfString:@"%2A"].location != NSNotFound) || ([self rangeOfString:@"%2a"].location != NSNotFound) || ([self rangeOfString:@"%40"].location != NSNotFound)) { return true; } else { return false; } } - (NSString *)encodePath { // force decoding to prevent double encoding NSString *newString = [self decodePath]; newString = [newString stringByReplacingOccurrencesOfString:@"%" withString:@"%25"]; newString = [newString stringByReplacingOccurrencesOfString:@"#" withString:@"%23"]; newString = [newString stringByReplacingOccurrencesOfString:@"*" withString:@"%2A"]; newString = [newString stringByReplacingOccurrencesOfString:@"@" withString:@"%40"]; return newString; } - (NSString *)encodeLucene { NSString *newString; newString = [self stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; newString = [newString stringByReplacingOccurrencesOfString:@"+" withString:@"\\+"]; newString = [newString stringByReplacingOccurrencesOfString:@"-" withString:@"\\-"]; newString = [newString stringByReplacingOccurrencesOfString:@"&&" withString:@"\\&&"]; newString = [newString stringByReplacingOccurrencesOfString:@"||" withString:@"\\||"]; newString = [newString stringByReplacingOccurrencesOfString:@"!" withString:@"\\!"]; newString = [newString stringByReplacingOccurrencesOfString:@"(" withString:@"\\("]; newString = [newString stringByReplacingOccurrencesOfString:@")" withString:@"\\)"]; newString = [newString stringByReplacingOccurrencesOfString:@"{" withString:@"\\{"]; newString = [newString stringByReplacingOccurrencesOfString:@"}" withString:@"\\}"]; newString = [newString stringByReplacingOccurrencesOfString:@"[" withString:@"\\["]; newString = [newString stringByReplacingOccurrencesOfString:@"]" withString:@"\\]"]; newString = [newString stringByReplacingOccurrencesOfString:@"^" withString:@"\\^"]; newString = [newString stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; newString = [newString stringByReplacingOccurrencesOfString:@"~" withString:@"\\~"]; newString = [newString stringByReplacingOccurrencesOfString:@"*" withString:@"\\*"]; newString = [newString stringByReplacingOccurrencesOfString:@"?" withString:@"\\?"]; newString = [newString stringByReplacingOccurrencesOfString:@":" withString:@"\\:"]; return newString; } - (NSString *)decodePath { NSString *newString; newString = [self stringByReplacingOccurrencesOfString:@"%23" withString:@"#"]; newString = [newString stringByReplacingOccurrencesOfString:@"%2A" withString:@"*"]; newString = [newString stringByReplacingOccurrencesOfString:@"%2a" withString:@"*"]; newString = [newString stringByReplacingOccurrencesOfString:@"%40" withString:@"@"]; newString = [newString stringByReplacingOccurrencesOfString:@"%25" withString:@"%"]; return newString; } #pragma mark - - (BOOL)isEqualCaseInsensitive:(NSString *)string { return string && [self caseInsensitiveCompare:string] == NSOrderedSame; } - (BOOL)isEmptyString { NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet]; return [self stringByTrimmingCharactersInSet:set].length == 0; } - (BOOL)hasPrefixCaseInsensitive:(NSString *)prefix { return prefix && [self rangeOfString:prefix options:NSAnchoredSearch | NSCaseInsensitiveSearch ].location != NSNotFound; } - (BOOL)hasSuffixCaseInsensitive:(NSString *)suffix { return suffix && [self rangeOfString:suffix options:NSAnchoredSearch | NSCaseInsensitiveSearch | NSBackwardsSearch ].location != NSNotFound; } @end
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 18548 | Robert Cowham | Merge from Main. | ||
#1 | 16507 | perforce_software | Move to main branch. | ||
//guest/perforce_software/piper/mac/R2.0/Perforce/Classes/Helpers/NSString+Additions.m | |||||
#1 | 12962 | alan_petersen |
Populate -o //guest/perforce_software/piper/mac/main/... //guest/perforce_software/piper/mac/R2.0/.... |
||
//guest/perforce_software/piper/mac/main/Perforce/Classes/Helpers/NSString+Additions.m | |||||
#2 | 12961 | alan_petersen |
Piper 2.0 Mega Update New Features/Functionality - Added help menu redirecting to URL. - Added readonly property for creating new workspaces. - Added html hyperlinks for Copy link functionality. - Added functionality for managing Finder Favorite items in sidebar. - Redesigned the way mapping is stored in Piper. - First version of syncing finder sidebar items with workspace mapping. - Small sorting improvements. - Creating Projects directory inside users home folder. - Adding Projects folder to finder sidebar item. - Creating and removing symbolic links accordingly to mapped folders. - Preventing duplicate names in symbolic links. - Refreshing symbolic links on mapping change inside application. - Storing workspace and server details in p4 configuration for other applications to use. - Added contextual menu items for Finder integration. - Added services menu for Adobe Illustrator integration. - Keyboard shortcuts for Illustrator integration. - Code refactoring and fixes for mapping issues. - Added Finder functionality to edit all files in folder. - Added user friendly message when editing a file using Finder outside the workspace. - Implemented hidden automatic login when opening application using Finder integration. - Logging to file in ~/Library/Logs - Unified workspace and all files views to show both local and depot files and folders. - Removed my workspace view references and logic. - Editing unmapped files on server. - First version of adding file to unmapped folders. - Showing opened by and edit actions in column details for all depot files. - Improved mappings functionality. - Enabled same feature options for mapped and unmapped folders and files. - Redesigned from scratch mapping and unmapping procedures for adding and removing files. - Implemented cleaning workspace using new mapping functionality. Removed debug overlay coloring. - Automated workspace creation - Improvements in editing files already mapped to workspace. - Implemented deleting remote files. - Implemented first version of move operation for remote files. - Removing last workspace information when disconnecting from workspace using app menu. - Implemented editing and submitting using symbolic links in project folder. New finder menu service for symbolic links Show in Piper which acts like share link functionality. - New icons for files and folders not tracked in the filesystem. - Improvements in showing file using share link. - Switched to new way of retrieving files in order to show user changes. - Redesigned and implemented new functionality for chaining operations with mapping. - Improvements and redesign of Edit/add actions to use new chaining logic . Fixed issue with file edit. - Improvements in window showing when using services. - Simplified file loading so the local files appears only when remote are also loaded. - Improved deleting of untracked files to avoid mapping and marking for delete. - Enabling simple copy paste and moving of remote and local files. - Added abort for exception handling in order to force crashing application on critical failures - Added custom exception handling for catching runtime errors to log and crash instead of continuing in unstable state. - Changed file copying to use mark for add . - Simplified and fixed responding file representations to mapping changes. Bug Fixes - Fixed crash when synchronizing. - Fixed sync issue when downloading directory without file size information. - Fixed issue with unread list crashing when file is not existing on disk. - Fixed incorrect sync progress calculation. - Removed relative path issues. - Fixed many of case-sensitivity problems. - Fixed deprecated methods and related issues in OS X 10.10. - Fixed folder rename not updating in column view. Revised and fixed many potential problems from implicit casting. - Fixed missing sync button on fast sync completion. - Refreshing mapping on synchronization. Fixed symbolic links not appearing until app is restarted. - Fixed latest crashing of autosync. - Fixed loading indicator issues. - Fixed and redesigned submit dialog to work correctly with Submit All Files option in Finder. - Fixed multiple error messages on network outage. Redesigned showing errors in main window. - Fixed opening random locations when using Finder integration. - Fixed issue when panel was detached from parent window. - Fixed bug when creating new workspace wouldn't store default settings. - Fixed memory issues with network operations. - Fixes in relogging mappings and file listing. - Improvements in editing unmapped files. - Fixed crash when adding file outside workspace. - Fixed breadcrumbs control issue. - Fixed issue with double parent folders when opening unmapped files. - Fixed crashes on sync after mapping new files. - Fixed issue with editing file using Finder -- Merging code and additional fixes in add button functionality. - Fixed unsync not working - Fixed submit panel issue not selecting files with different name case. - Fixed missing revert and sync to workspace actions in some cases. - Fixed issue with Submit and Edit finder actions. Improvements in stability of finder integration. - Fixed issue with unsubmitted folders breaking status of files inside. - Fixed issue with added files not showing correct icon and status. - Fixed bug with file edit resulting in a new directory named exactly like a file. - Fixed issue with reloading of subpath resulting in untracked folders. - Fixed mapping issue when result was always view mapping not relative. - Fixed submit panel showing more than once. - Fixed illustrator services not working. - Fixed userdefaults preferences problem with workspace name being null. - Fixed userdefaults keypath problem of dot-containing workspace names. - Forcing recreating of browser to possibly prevent pre-10.10 errors with automatic workspace selection. - Fixed adding file to depot not presenting correct icon. - Fixed issues with reverting a file that was marked for add. - Presenting error when trying to submit untracked files. - Fixed issue when submit files service crashed when using unmapped files. - Fixed file representation disappearing when removing file. - Fixed issue with symlinks resolving working on 10.10 only. Issue related to workspace selection not showing. - Fixed error panel method calls unavailable in Mac OS versions before 10.10. Issue related to hanging error panels. - Fixed removing a local file resulting in action progress freezing. - Fixed open file not working after edit. - Fixing crash when mapping changed. Issue related to moving local file to unmapped folder and other similar cases. |
||
#1 | 11252 | alan_petersen | Rename/move file(s) | ||
//guest/perforce_software/piper/mac/Perforce/Classes/Helpers/NSString+Additions.m | |||||
#1 | 10744 | alan_petersen | Rename/move file(s) | ||
//guest/perforce_software/piper/Perforce/Classes/Helpers/NSString+Additions.m | |||||
#1 | 8919 | Matt Attaway | Initial add of Piper, a lightweight Perforce client for artists and designers. |