Oolite 1.91.0.7604-240417-a536cbe
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@end
153
154
155@implementation NSMutableString (OOExtensions)
156
157- (void) appendLine:(NSString *)line
158{
159 [self appendString:line ? [line stringByAppendingString:@"\n"] : (NSString *)@"\n"];
160}
161
162
163- (void) appendFormatLine:(NSString *)fmt, ...
164{
165 va_list args;
166 va_start(args, fmt);
167 [self appendFormatLine:fmt arguments:args];
168 va_end(args);
169}
170
171
172- (void) appendFormatLine:(NSString *)fmt arguments:(va_list)args
173{
174 NSString *formatted = [[NSString alloc] initWithFormat:fmt arguments:args];
175 [self appendLine:formatted];
176 [formatted release];
177}
178
179
180- (void) deleteCharacterAtIndex:(unsigned long)index
181{
182 [self deleteCharactersInRange:NSMakeRange(index, 1)];
183}
184
185@end
186
187
188NSString *OOTabString(NSUInteger count)
189{
190 NSString * const staticTabs[] =
191 {
192 @"",
193 @"\t",
194 @"\t\t",
195 @"\t\t\t",
196 @"\t\t\t\t",
197 @"\t\t\t\t\t", // 5
198 @"\t\t\t\t\t\t",
199 @"\t\t\t\t\t\t\t",
200 @"\t\t\t\t\t\t\t\t",
201 @"\t\t\t\t\t\t\t\t\t",
202 @"\t\t\t\t\t\t\t\t\t\t" // 10
203 };
204 enum { kStaticTabCount = sizeof staticTabs / sizeof *staticTabs };
205
206 if (count < kStaticTabCount)
207 {
208 return staticTabs[count];
209 }
210 else
211 {
212 return [staticTabs[kStaticTabCount - 1] stringByAppendingString:OOTabString(count - (kStaticTabCount - 1))];
213 }
214}
NSString * OOTabString(NSUInteger count)
unsigned count
return nil