Oolite 1.91.0.7645-241119-222d325
Loading...
Searching...
No Matches
NSStringOOExtensions.m
Go to the documentation of this file.
1/*
2
3NSStringOOExtensions.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
27#import "OOCocoa.h"
28
29
30@implementation NSString (OOExtensions)
31
32+ (instancetype) stringWithContentsOfUnicodeFile:(NSString *)path
33{
34 id result = nil;
35 BOOL OK = YES;
36 NSData *data = nil;
37 const uint8_t *bytes = NULL;
38 size_t length = 0;
39 const uint8_t *effectiveBytes = NULL;
40 size_t effectiveLength = 0;
41
42 data = [[NSData oo_dataWithOXZFile:path] retain];
43 if (data == nil) OK = NO;
44
45 if (OK)
46 {
47 length = [data length];
48 bytes = [data bytes];
49 }
50
51 if (OK && 2 <= length && (length % sizeof(unichar)) == 0)
52 {
53 // Could be UTF-16
54 unichar firstChar = bytes[0];
55 firstChar = (firstChar << 8) | bytes[1]; // Endianism doesn't matter, because we test both orders of BOM.
56 if (firstChar == 0xFFFE || firstChar == 0xFEFF)
57 {
58 // Consider it to be UTF-16.
59 result = [NSString stringWithCharacters:(unichar *)(bytes + sizeof(unichar)) length:(length / sizeof(unichar)) - 1];
60 if (result == nil) OK = NO;
61 }
62 }
63
64 if (OK && result == nil)
65 {
66 // Not UTF-16. Try UTF-8.
67 if (3 <= length && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
68 {
69 // File starts with UTF-8 BOM; skip it.
70 effectiveBytes = bytes + 3;
71 effectiveLength = length + 3;
72 }
73 else
74 {
75 effectiveBytes = bytes;
76 effectiveLength = length;
77 }
78
79 // Attempt to interpret as UTF-8
80 result = [[[NSString alloc] initWithBytes:effectiveBytes length:effectiveLength encoding:NSUTF8StringEncoding] autorelease];
81 }
82
83 if (OK && result == nil)
84 {
85 // Not UTF-16 or UTF-8. Use ISO-Latin-1 (which should work for any byte sequence).
86 result = [[[NSString alloc] initWithBytes:effectiveBytes length:effectiveLength encoding:NSISOLatin1StringEncoding] autorelease];
87 }
88
89 [data release];
90 return result;
91}
92
93
94+ (instancetype) stringWithUTF16String:(const unichar *)chars
95{
96 size_t length;
97 const unichar *end;
98
99 if (chars == NULL) return nil;
100
101 // Find length of string.
102 end = chars;
103 while (*end++) {}
104 length = end - chars - 1;
105
106 return [NSString stringWithCharacters:chars length:length];
107}
108
109
110- (NSData *) utf16DataWithBOM:(BOOL)includeByteOrderMark
111{
112 size_t lengthInChars;
113 size_t lengthInBytes;
114 unichar *buffer = NULL;
115 unichar *characters = NULL;
116
117 // Calculate sizes
118 lengthInChars = [self length];
119 lengthInBytes = lengthInChars * sizeof(unichar);
120 if (includeByteOrderMark) lengthInBytes += sizeof(unichar);
121
122 // Allocate buffer
123 buffer = malloc(lengthInBytes);
124 if (buffer == NULL) return nil;
125
126 // write BOM (native-endian) if desired
127 characters = buffer;
128 if (includeByteOrderMark)
129 {
130 *characters++ = 0xFEFF;
131 }
132
133 // Get the contents
134 [self getCharacters:characters];
135
136 // NSData takes ownership of the buffer.
137 return [NSData dataWithBytesNoCopy:buffer length:lengthInBytes freeWhenDone:YES];
138}
139
140
141- (uint32_t) oo_hash
142{
143 NSUInteger i, length = [self length];
144 uint32_t hash = 5381;
145 for (i = 0; i < length; i++)
146 {
147 hash = ((hash << 5) + hash) /* 33 * hash */ ^ [self characterAtIndex:i];
148 }
149 return hash;
150}
151
152
153- (NSString *)stringByTrimmingLeadingCharactersInSet:(NSCharacterSet *)characterSet
154{
155 NSRange rangeOfFirstWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]];
156 if (rangeOfFirstWantedCharacter.location == NSNotFound) return @"";
157
158 return [self substringFromIndex:rangeOfFirstWantedCharacter.location];
159}
160
161
163{
164 return [self stringByTrimmingLeadingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
165}
166
167
168- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet
169{
170 NSRange rangeOfLastWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet] options:NSBackwardsSearch];
171 if (rangeOfLastWantedCharacter.location == NSNotFound) return @"";
172
173 return [self substringToIndex:rangeOfLastWantedCharacter.location+1]; // non-inclusive
174}
175
176
178{
179 return [self stringByTrimmingTrailingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
180}
181
182@end
183
184
185@implementation NSMutableString (OOExtensions)
186
187- (void) appendLine:(NSString *)line
188{
189 [self appendString:line ? [line stringByAppendingString:@"\n"] : (NSString *)@"\n"];
190}
191
192
193- (void) appendFormatLine:(NSString *)fmt, ...
194{
195 va_list args;
196 va_start(args, fmt);
197 [self appendFormatLine:fmt arguments:args];
198 va_end(args);
199}
200
201
202- (void) appendFormatLine:(NSString *)fmt arguments:(va_list)args
203{
204 NSString *formatted = [[NSString alloc] initWithFormat:fmt arguments:args];
205 [self appendLine:formatted];
206 [formatted release];
207}
208
209
210- (void) deleteCharacterAtIndex:(unsigned long)index
211{
212 [self deleteCharactersInRange:NSMakeRange(index, 1)];
213}
214
215@end
216
217
218NSString *OOTabString(NSUInteger count)
219{
220 NSString * const staticTabs[] =
221 {
222 @"",
223 @"\t",
224 @"\t\t",
225 @"\t\t\t",
226 @"\t\t\t\t",
227 @"\t\t\t\t\t", // 5
228 @"\t\t\t\t\t\t",
229 @"\t\t\t\t\t\t\t",
230 @"\t\t\t\t\t\t\t\t",
231 @"\t\t\t\t\t\t\t\t\t",
232 @"\t\t\t\t\t\t\t\t\t\t" // 10
233 };
234 enum { kStaticTabCount = sizeof staticTabs / sizeof *staticTabs };
235
236 if (count < kStaticTabCount)
237 {
238 return staticTabs[count];
239 }
240 else
241 {
242 return [staticTabs[kStaticTabCount - 1] stringByAppendingString:OOTabString(count - (kStaticTabCount - 1))];
243 }
244}
NSString * OOTabString(NSUInteger count)
return self
unsigned count
return nil
NSString * stringByTrimmingTrailingWhitespaceAndNewlineCharacters()
NSString * stringByTrimmingLeadingWhitespaceAndNewlineCharacters()