diff options
Diffstat (limited to 'libs/cocos2d/Support')
22 files changed, 4245 insertions, 0 deletions
diff --git a/libs/cocos2d/Support/CCArray.h b/libs/cocos2d/Support/CCArray.h new file mode 100755 index 0000000..0c7b2b8 --- /dev/null +++ b/libs/cocos2d/Support/CCArray.h | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | |||
26 | #import "ccCArray.h" | ||
27 | |||
28 | |||
29 | /** A faster alternative of NSArray. | ||
30 | CCArray uses internally a c-array. | ||
31 | @since v0.99.4 | ||
32 | */ | ||
33 | |||
34 | |||
35 | /** @def CCARRAY_FOREACH | ||
36 | A convience macro to iterate over a CCArray using. It is faster than the "fast enumeration" interface. | ||
37 | @since v0.99.4 | ||
38 | */ | ||
39 | |||
40 | #define CCARRAY_FOREACH(__array__, __object__) \ | ||
41 | if (__array__ && __array__->data->num > 0) \ | ||
42 | for(id *__arr__ = __array__->data->arr, *end = __array__->data->arr + __array__->data->num-1; \ | ||
43 | __arr__ <= end && ((__object__ = *__arr__) != nil || true); \ | ||
44 | __arr__++) | ||
45 | |||
46 | @interface CCArray : NSObject <NSFastEnumeration, NSCoding, NSCopying> | ||
47 | { | ||
48 | @public ccArray *data; | ||
49 | } | ||
50 | |||
51 | + (id) array; | ||
52 | + (id) arrayWithCapacity:(NSUInteger)capacity; | ||
53 | + (id) arrayWithArray:(CCArray*)otherArray; | ||
54 | + (id) arrayWithNSArray:(NSArray*)otherArray; | ||
55 | |||
56 | |||
57 | - (id) initWithCapacity:(NSUInteger)capacity; | ||
58 | - (id) initWithArray:(CCArray*)otherArray; | ||
59 | - (id) initWithNSArray:(NSArray*)otherArray; | ||
60 | |||
61 | |||
62 | // Querying an Array | ||
63 | |||
64 | - (NSUInteger) count; | ||
65 | - (NSUInteger) capacity; | ||
66 | - (NSUInteger) indexOfObject:(id)object; | ||
67 | - (id) objectAtIndex:(NSUInteger)index; | ||
68 | - (BOOL) containsObject:(id)object; | ||
69 | - (id) randomObject; | ||
70 | - (id) lastObject; | ||
71 | - (NSArray*) getNSArray; | ||
72 | |||
73 | |||
74 | // Adding Objects | ||
75 | |||
76 | - (void) addObject:(id)object; | ||
77 | - (void) addObjectsFromArray:(CCArray*)otherArray; | ||
78 | - (void) addObjectsFromNSArray:(NSArray*)otherArray; | ||
79 | - (void) insertObject:(id)object atIndex:(NSUInteger)index; | ||
80 | |||
81 | |||
82 | // Removing Objects | ||
83 | |||
84 | - (void) removeLastObject; | ||
85 | - (void) removeObject:(id)object; | ||
86 | - (void) removeObjectAtIndex:(NSUInteger)index; | ||
87 | - (void) removeObjectsInArray:(CCArray*)otherArray; | ||
88 | - (void) removeAllObjects; | ||
89 | - (void) fastRemoveObject:(id)object; | ||
90 | - (void) fastRemoveObjectAtIndex:(NSUInteger)index; | ||
91 | |||
92 | |||
93 | // Rearranging Content | ||
94 | |||
95 | - (void) exchangeObject:(id)object1 withObject:(id)object2; | ||
96 | - (void) exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2; | ||
97 | - (void) reverseObjects; | ||
98 | - (void) reduceMemoryFootprint; | ||
99 | |||
100 | // Sending Messages to Elements | ||
101 | |||
102 | - (void) makeObjectsPerformSelector:(SEL)aSelector; | ||
103 | - (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object; | ||
104 | |||
105 | |||
106 | @end | ||
diff --git a/libs/cocos2d/Support/CCArray.m b/libs/cocos2d/Support/CCArray.m new file mode 100755 index 0000000..a48a5f3 --- /dev/null +++ b/libs/cocos2d/Support/CCArray.m | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #import "CCArray.h" | ||
26 | #import "../ccMacros.h" | ||
27 | |||
28 | |||
29 | @implementation CCArray | ||
30 | |||
31 | + (id) array | ||
32 | { | ||
33 | return [[[self alloc] init] autorelease]; | ||
34 | } | ||
35 | |||
36 | + (id) arrayWithCapacity:(NSUInteger)capacity | ||
37 | { | ||
38 | return [[[self alloc] initWithCapacity:capacity] autorelease]; | ||
39 | } | ||
40 | |||
41 | + (id) arrayWithArray:(CCArray*)otherArray | ||
42 | { | ||
43 | return [[(CCArray*)[self alloc] initWithArray:otherArray] autorelease]; | ||
44 | } | ||
45 | |||
46 | + (id) arrayWithNSArray:(NSArray*)otherArray | ||
47 | { | ||
48 | return [[(CCArray*)[self alloc] initWithNSArray:otherArray] autorelease]; | ||
49 | } | ||
50 | |||
51 | - (id) init | ||
52 | { | ||
53 | self = [self initWithCapacity:2]; | ||
54 | return self; | ||
55 | } | ||
56 | |||
57 | - (id) initWithCapacity:(NSUInteger)capacity | ||
58 | { | ||
59 | self = [super init]; | ||
60 | if (self != nil) { | ||
61 | data = ccArrayNew(capacity); | ||
62 | } | ||
63 | return self; | ||
64 | } | ||
65 | |||
66 | - (id) initWithArray:(CCArray*)otherArray | ||
67 | { | ||
68 | self = [self initWithCapacity:otherArray->data->num]; | ||
69 | if (self != nil) { | ||
70 | [self addObjectsFromArray:otherArray]; | ||
71 | } | ||
72 | return self; | ||
73 | } | ||
74 | |||
75 | - (id) initWithNSArray:(NSArray*)otherArray | ||
76 | { | ||
77 | self = [self initWithCapacity:otherArray.count]; | ||
78 | if (self != nil) { | ||
79 | [self addObjectsFromNSArray:otherArray]; | ||
80 | } | ||
81 | return self; | ||
82 | } | ||
83 | |||
84 | - (id) initWithCoder:(NSCoder*)coder | ||
85 | { | ||
86 | self = [self initWithNSArray:[coder decodeObjectForKey:@"nsarray"]]; | ||
87 | return self; | ||
88 | } | ||
89 | |||
90 | |||
91 | #pragma mark Querying an Array | ||
92 | |||
93 | - (NSUInteger) count | ||
94 | { | ||
95 | return data->num; | ||
96 | } | ||
97 | |||
98 | - (NSUInteger) capacity | ||
99 | { | ||
100 | return data->max; | ||
101 | } | ||
102 | |||
103 | - (NSUInteger) indexOfObject:(id)object | ||
104 | { | ||
105 | return ccArrayGetIndexOfObject(data, object); | ||
106 | } | ||
107 | |||
108 | - (id) objectAtIndex:(NSUInteger)index | ||
109 | { | ||
110 | NSAssert2( index < data->num, @"index out of range in objectAtIndex(%d), index %i", data->num, index ); | ||
111 | |||
112 | return data->arr[index]; | ||
113 | } | ||
114 | |||
115 | - (BOOL) containsObject:(id)object | ||
116 | { | ||
117 | return ccArrayContainsObject(data, object); | ||
118 | } | ||
119 | |||
120 | - (id) lastObject | ||
121 | { | ||
122 | if( data->num > 0 ) | ||
123 | return data->arr[data->num-1]; | ||
124 | return nil; | ||
125 | } | ||
126 | |||
127 | - (id) randomObject | ||
128 | { | ||
129 | if(data->num==0) return nil; | ||
130 | return data->arr[(int)(data->num*CCRANDOM_0_1())]; | ||
131 | } | ||
132 | |||
133 | - (NSArray*) getNSArray | ||
134 | { | ||
135 | return [NSArray arrayWithObjects:data->arr count:data->num]; | ||
136 | } | ||
137 | |||
138 | |||
139 | #pragma mark Adding Objects | ||
140 | |||
141 | - (void) addObject:(id)object | ||
142 | { | ||
143 | ccArrayAppendObjectWithResize(data, object); | ||
144 | } | ||
145 | |||
146 | - (void) addObjectsFromArray:(CCArray*)otherArray | ||
147 | { | ||
148 | ccArrayAppendArrayWithResize(data, otherArray->data); | ||
149 | } | ||
150 | |||
151 | - (void) addObjectsFromNSArray:(NSArray*)otherArray | ||
152 | { | ||
153 | ccArrayEnsureExtraCapacity(data, otherArray.count); | ||
154 | for(id object in otherArray) | ||
155 | ccArrayAppendObject(data, object); | ||
156 | } | ||
157 | |||
158 | - (void) insertObject:(id)object atIndex:(NSUInteger)index | ||
159 | { | ||
160 | ccArrayInsertObjectAtIndex(data, object, index); | ||
161 | } | ||
162 | |||
163 | |||
164 | #pragma mark Removing Objects | ||
165 | |||
166 | - (void) removeObject:(id)object | ||
167 | { | ||
168 | ccArrayRemoveObject(data, object); | ||
169 | } | ||
170 | |||
171 | - (void) removeObjectAtIndex:(NSUInteger)index | ||
172 | { | ||
173 | ccArrayRemoveObjectAtIndex(data, index); | ||
174 | } | ||
175 | |||
176 | - (void) fastRemoveObject:(id)object | ||
177 | { | ||
178 | ccArrayFastRemoveObject(data, object); | ||
179 | } | ||
180 | |||
181 | - (void) fastRemoveObjectAtIndex:(NSUInteger)index | ||
182 | { | ||
183 | ccArrayFastRemoveObjectAtIndex(data, index); | ||
184 | } | ||
185 | |||
186 | - (void) removeObjectsInArray:(CCArray*)otherArray | ||
187 | { | ||
188 | ccArrayRemoveArray(data, otherArray->data); | ||
189 | } | ||
190 | |||
191 | - (void) removeLastObject | ||
192 | { | ||
193 | NSAssert( data->num > 0, @"no objects added" ); | ||
194 | |||
195 | ccArrayRemoveObjectAtIndex(data, data->num-1); | ||
196 | } | ||
197 | |||
198 | - (void) removeAllObjects | ||
199 | { | ||
200 | ccArrayRemoveAllObjects(data); | ||
201 | } | ||
202 | |||
203 | |||
204 | #pragma mark Rearranging Content | ||
205 | |||
206 | - (void) exchangeObject:(id)object1 withObject:(id)object2 | ||
207 | { | ||
208 | NSUInteger index1 = ccArrayGetIndexOfObject(data, object1); | ||
209 | if(index1 == NSNotFound) return; | ||
210 | NSUInteger index2 = ccArrayGetIndexOfObject(data, object2); | ||
211 | if(index2 == NSNotFound) return; | ||
212 | |||
213 | ccArraySwapObjectsAtIndexes(data, index1, index2); | ||
214 | } | ||
215 | |||
216 | - (void) exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 | ||
217 | { | ||
218 | ccArraySwapObjectsAtIndexes(data, index1, index2); | ||
219 | } | ||
220 | |||
221 | - (void) reverseObjects | ||
222 | { | ||
223 | if (data->num > 1) | ||
224 | { | ||
225 | //floor it since in case of a oneven number the number of swaps stays the same | ||
226 | int count = (int) floorf(data->num/2.f); | ||
227 | NSUInteger maxIndex = data->num - 1; | ||
228 | |||
229 | for (int i = 0; i < count ; i++) | ||
230 | { | ||
231 | ccArraySwapObjectsAtIndexes(data, i, maxIndex); | ||
232 | maxIndex--; | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | - (void) reduceMemoryFootprint | ||
238 | { | ||
239 | ccArrayShrink(data); | ||
240 | } | ||
241 | |||
242 | #pragma mark Sending Messages to Elements | ||
243 | |||
244 | - (void) makeObjectsPerformSelector:(SEL)aSelector | ||
245 | { | ||
246 | ccArrayMakeObjectsPerformSelector(data, aSelector); | ||
247 | } | ||
248 | |||
249 | - (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object | ||
250 | { | ||
251 | ccArrayMakeObjectsPerformSelectorWithObject(data, aSelector, object); | ||
252 | } | ||
253 | |||
254 | |||
255 | #pragma mark CCArray - NSFastEnumeration protocol | ||
256 | |||
257 | - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len | ||
258 | { | ||
259 | if(state->state == 1) return 0; | ||
260 | |||
261 | state->mutationsPtr = (unsigned long *)self; | ||
262 | state->itemsPtr = &data->arr[0]; | ||
263 | state->state = 1; | ||
264 | return data->num; | ||
265 | } | ||
266 | |||
267 | |||
268 | #pragma mark CCArray - NSCopying protocol | ||
269 | |||
270 | - (id)copyWithZone:(NSZone *)zone | ||
271 | { | ||
272 | NSArray *nsArray = [self getNSArray]; | ||
273 | CCArray *newArray = [[[self class] allocWithZone:zone] initWithNSArray:nsArray]; | ||
274 | return newArray; | ||
275 | } | ||
276 | |||
277 | - (void) encodeWithCoder:(NSCoder *)coder | ||
278 | { | ||
279 | [coder encodeObject:[self getNSArray] forKey:@"nsarray"]; | ||
280 | } | ||
281 | |||
282 | #pragma mark | ||
283 | |||
284 | - (void) dealloc | ||
285 | { | ||
286 | ccArrayFree(data); | ||
287 | [super dealloc]; | ||
288 | } | ||
289 | |||
290 | @end | ||
diff --git a/libs/cocos2d/Support/CCFileUtils.h b/libs/cocos2d/Support/CCFileUtils.h new file mode 100755 index 0000000..0455202 --- /dev/null +++ b/libs/cocos2d/Support/CCFileUtils.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
5 | * Copyright (c) 2011 Zynga Inc. | ||
6 | * | ||
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
8 | * of this software and associated documentation files (the "Software"), to deal | ||
9 | * in the Software without restriction, including without limitation the rights | ||
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
11 | * copies of the Software, and to permit persons to whom the Software is | ||
12 | * furnished to do so, subject to the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice shall be included in | ||
15 | * all copies or substantial portions of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
23 | * THE SOFTWARE. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | |||
28 | #import <Foundation/Foundation.h> | ||
29 | |||
30 | |||
31 | /** Helper class to handle file operations */ | ||
32 | @interface CCFileUtils : NSObject | ||
33 | { | ||
34 | } | ||
35 | |||
36 | /** Returns the fullpath of an filename. | ||
37 | |||
38 | If this method is when Retina Display is enabled, then the | ||
39 | Retina Display suffix will be appended to the file (See ccConfig.h). | ||
40 | |||
41 | If the Retina Display image doesn't exist, then it will return the "non-Retina Display" image | ||
42 | |||
43 | */ | ||
44 | +(NSString*) fullPathFromRelativePath:(NSString*) relPath; | ||
45 | @end | ||
46 | |||
47 | /** loads a file into memory. | ||
48 | the caller should release the allocated buffer. | ||
49 | |||
50 | @returns the size of the allocated buffer | ||
51 | @since v0.99.5 | ||
52 | */ | ||
53 | NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out); | ||
54 | |||
55 | |||
56 | /** removes the HD suffix from a path | ||
57 | |||
58 | @returns NSString * without the HD suffix | ||
59 | @since v0.99.5 | ||
60 | */ | ||
61 | NSString *ccRemoveHDSuffixFromFile( NSString *path ); | ||
62 | |||
diff --git a/libs/cocos2d/Support/CCFileUtils.m b/libs/cocos2d/Support/CCFileUtils.m new file mode 100755 index 0000000..6d33799 --- /dev/null +++ b/libs/cocos2d/Support/CCFileUtils.m | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
5 | * Copyright (c) 2011 Zynga Inc. | ||
6 | * | ||
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
8 | * of this software and associated documentation files (the "Software"), to deal | ||
9 | * in the Software without restriction, including without limitation the rights | ||
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
11 | * copies of the Software, and to permit persons to whom the Software is | ||
12 | * furnished to do so, subject to the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice shall be included in | ||
15 | * all copies or substantial portions of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
23 | * THE SOFTWARE. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | |||
28 | #import <Availability.h> | ||
29 | #import "CCFileUtils.h" | ||
30 | #import "../CCConfiguration.h" | ||
31 | #import "../ccMacros.h" | ||
32 | #import "../ccConfig.h" | ||
33 | |||
34 | static NSFileManager *__localFileManager=nil; | ||
35 | |||
36 | // | ||
37 | NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out) | ||
38 | { | ||
39 | NSCAssert( out, @"ccLoadFileIntoMemory: invalid 'out' parameter"); | ||
40 | NSCAssert( &*out, @"ccLoadFileIntoMemory: invalid 'out' parameter"); | ||
41 | |||
42 | size_t size = 0; | ||
43 | FILE *f = fopen(filename, "rb"); | ||
44 | if( !f ) { | ||
45 | *out = NULL; | ||
46 | return -1; | ||
47 | } | ||
48 | |||
49 | fseek(f, 0, SEEK_END); | ||
50 | size = ftell(f); | ||
51 | fseek(f, 0, SEEK_SET); | ||
52 | |||
53 | *out = malloc(size); | ||
54 | size_t read = fread(*out, 1, size, f); | ||
55 | if( read != size ) { | ||
56 | free(*out); | ||
57 | *out = NULL; | ||
58 | return -1; | ||
59 | } | ||
60 | |||
61 | fclose(f); | ||
62 | |||
63 | return size; | ||
64 | } | ||
65 | |||
66 | NSString *ccRemoveHDSuffixFromFile( NSString *path ) | ||
67 | { | ||
68 | #if CC_IS_RETINA_DISPLAY_SUPPORTED | ||
69 | |||
70 | if( CC_CONTENT_SCALE_FACTOR() == 2 ) { | ||
71 | |||
72 | NSString *name = [path lastPathComponent]; | ||
73 | |||
74 | // check if path already has the suffix. | ||
75 | if( [name rangeOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX].location != NSNotFound ) { | ||
76 | |||
77 | CCLOG(@"cocos2d: Filename(%@) contains %@ suffix. Removing it. See cocos2d issue #1040", path, CC_RETINA_DISPLAY_FILENAME_SUFFIX); | ||
78 | |||
79 | NSString *newLastname = [name stringByReplacingOccurrencesOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX withString:@""]; | ||
80 | |||
81 | NSString *pathWithoutLastname = [path stringByDeletingLastPathComponent]; | ||
82 | return [pathWithoutLastname stringByAppendingPathComponent:newLastname]; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | #endif // CC_IS_RETINA_DISPLAY_SUPPORTED | ||
87 | |||
88 | return path; | ||
89 | |||
90 | } | ||
91 | |||
92 | |||
93 | @implementation CCFileUtils | ||
94 | |||
95 | +(void) initialize | ||
96 | { | ||
97 | if( self == [CCFileUtils class] ) | ||
98 | __localFileManager = [[NSFileManager alloc] init]; | ||
99 | } | ||
100 | |||
101 | +(NSString*) getDoubleResolutionImage:(NSString*)path | ||
102 | { | ||
103 | #if CC_IS_RETINA_DISPLAY_SUPPORTED | ||
104 | |||
105 | if( CC_CONTENT_SCALE_FACTOR() == 2 ) | ||
106 | { | ||
107 | |||
108 | NSString *pathWithoutExtension = [path stringByDeletingPathExtension]; | ||
109 | NSString *name = [pathWithoutExtension lastPathComponent]; | ||
110 | |||
111 | // check if path already has the suffix. | ||
112 | if( [name rangeOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX].location != NSNotFound ) { | ||
113 | |||
114 | CCLOG(@"cocos2d: WARNING Filename(%@) already has the suffix %@. Using it.", name, CC_RETINA_DISPLAY_FILENAME_SUFFIX); | ||
115 | return path; | ||
116 | } | ||
117 | |||
118 | |||
119 | NSString *extension = [path pathExtension]; | ||
120 | |||
121 | if( [extension isEqualToString:@"ccz"] || [extension isEqualToString:@"gz"] ) | ||
122 | { | ||
123 | // All ccz / gz files should be in the format filename.xxx.ccz | ||
124 | // so we need to pull off the .xxx part of the extension as well | ||
125 | extension = [NSString stringWithFormat:@"%@.%@", [pathWithoutExtension pathExtension], extension]; | ||
126 | pathWithoutExtension = [pathWithoutExtension stringByDeletingPathExtension]; | ||
127 | } | ||
128 | |||
129 | |||
130 | NSString *retinaName = [pathWithoutExtension stringByAppendingString:CC_RETINA_DISPLAY_FILENAME_SUFFIX]; | ||
131 | retinaName = [retinaName stringByAppendingPathExtension:extension]; | ||
132 | |||
133 | if( [__localFileManager fileExistsAtPath:retinaName] ) | ||
134 | return retinaName; | ||
135 | |||
136 | CCLOG(@"cocos2d: CCFileUtils: Warning HD file not found: %@", [retinaName lastPathComponent] ); | ||
137 | } | ||
138 | |||
139 | #endif // CC_IS_RETINA_DISPLAY_SUPPORTED | ||
140 | |||
141 | return path; | ||
142 | } | ||
143 | |||
144 | +(NSString*) fullPathFromRelativePath:(NSString*) relPath | ||
145 | { | ||
146 | NSAssert(relPath != nil, @"CCFileUtils: Invalid path"); | ||
147 | |||
148 | NSString *fullpath = nil; | ||
149 | |||
150 | // only if it is not an absolute path | ||
151 | if( ! [relPath isAbsolutePath] ) | ||
152 | { | ||
153 | NSString *file = [relPath lastPathComponent]; | ||
154 | NSString *imageDirectory = [relPath stringByDeletingLastPathComponent]; | ||
155 | |||
156 | fullpath = [[NSBundle mainBundle] pathForResource:file | ||
157 | ofType:nil | ||
158 | inDirectory:imageDirectory]; | ||
159 | } | ||
160 | |||
161 | if (fullpath == nil) | ||
162 | fullpath = relPath; | ||
163 | |||
164 | fullpath = [self getDoubleResolutionImage:fullpath]; | ||
165 | |||
166 | return fullpath; | ||
167 | } | ||
168 | |||
169 | @end | ||
diff --git a/libs/cocos2d/Support/CCProfiling.h b/libs/cocos2d/Support/CCProfiling.h new file mode 100755 index 0000000..b241fb9 --- /dev/null +++ b/libs/cocos2d/Support/CCProfiling.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Stuart Carnie | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import <Foundation/Foundation.h> | ||
28 | #import <sys/time.h> | ||
29 | |||
30 | @class CCProfilingTimer; | ||
31 | |||
32 | @interface CCProfiler : NSObject { | ||
33 | NSMutableArray* activeTimers; | ||
34 | } | ||
35 | |||
36 | + (CCProfiler*)sharedProfiler; | ||
37 | + (CCProfilingTimer*)timerWithName:(NSString*)timerName andInstance:(id)instance; | ||
38 | + (void)releaseTimer:(CCProfilingTimer*)timer; | ||
39 | - (void)displayTimers; | ||
40 | |||
41 | @end | ||
42 | |||
43 | |||
44 | @interface CCProfilingTimer : NSObject { | ||
45 | NSString* name; | ||
46 | struct timeval startTime; | ||
47 | double averageTime; | ||
48 | } | ||
49 | |||
50 | @end | ||
51 | |||
52 | extern void CCProfilingBeginTimingBlock(CCProfilingTimer* timer); | ||
53 | extern void CCProfilingEndTimingBlock(CCProfilingTimer* timer); | ||
diff --git a/libs/cocos2d/Support/CCProfiling.m b/libs/cocos2d/Support/CCProfiling.m new file mode 100755 index 0000000..13c8c81 --- /dev/null +++ b/libs/cocos2d/Support/CCProfiling.m | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Stuart Carnie | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import "../ccConfig.h" | ||
27 | |||
28 | #if CC_ENABLE_PROFILERS | ||
29 | |||
30 | #import "CCProfiling.h" | ||
31 | |||
32 | @interface CCProfilingTimer() | ||
33 | - (id)initWithName:(NSString*)timerName andInstance:(id)instance; | ||
34 | @end | ||
35 | |||
36 | @implementation CCProfiler | ||
37 | |||
38 | static CCProfiler* g_sharedProfiler; | ||
39 | |||
40 | + (CCProfiler*)sharedProfiler { | ||
41 | if (!g_sharedProfiler) | ||
42 | g_sharedProfiler = [[CCProfiler alloc] init]; | ||
43 | |||
44 | return g_sharedProfiler; | ||
45 | } | ||
46 | |||
47 | + (CCProfilingTimer*)timerWithName:(NSString*)timerName andInstance:(id)instance { | ||
48 | CCProfiler* p = [CCProfiler sharedProfiler]; | ||
49 | CCProfilingTimer* t = [[CCProfilingTimer alloc] initWithName:timerName andInstance:instance]; | ||
50 | [p->activeTimers addObject:t]; | ||
51 | [t release]; | ||
52 | return t; | ||
53 | } | ||
54 | |||
55 | + (void)releaseTimer:(CCProfilingTimer*)timer { | ||
56 | CCProfiler* p = [CCProfiler sharedProfiler]; | ||
57 | [p->activeTimers removeObject:timer]; | ||
58 | } | ||
59 | |||
60 | - (id)init { | ||
61 | if (!(self = [super init])) return nil; | ||
62 | |||
63 | activeTimers = [[NSMutableArray alloc] init]; | ||
64 | |||
65 | return self; | ||
66 | } | ||
67 | |||
68 | - (void)dealloc { | ||
69 | [activeTimers release]; | ||
70 | [super dealloc]; | ||
71 | } | ||
72 | |||
73 | - (void)displayTimers { | ||
74 | for (id timer in activeTimers) { | ||
75 | printf("%s\n", [[timer description] cStringUsingEncoding:[NSString defaultCStringEncoding]]); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | @end | ||
80 | |||
81 | @implementation CCProfilingTimer | ||
82 | |||
83 | - (id)initWithName:(NSString*)timerName andInstance:(id)instance { | ||
84 | if (!(self = [super init])) return nil; | ||
85 | |||
86 | name = [[NSString stringWithFormat:@"%@ (0x%.8x)", timerName, instance] retain]; | ||
87 | |||
88 | return self; | ||
89 | } | ||
90 | |||
91 | - (void)dealloc { | ||
92 | [name release]; | ||
93 | [super dealloc]; | ||
94 | } | ||
95 | |||
96 | - (NSString*)description { | ||
97 | return [NSString stringWithFormat:@"%@ : avg time, %fms", name, averageTime]; | ||
98 | } | ||
99 | |||
100 | void CCProfilingBeginTimingBlock(CCProfilingTimer* timer) { | ||
101 | gettimeofday(&timer->startTime, NULL); | ||
102 | } | ||
103 | |||
104 | typedef unsigned int uint32; | ||
105 | void CCProfilingEndTimingBlock(CCProfilingTimer* timer) { | ||
106 | struct timeval currentTime; | ||
107 | gettimeofday(¤tTime, NULL); | ||
108 | timersub(¤tTime, &timer->startTime, ¤tTime); | ||
109 | double duration = currentTime.tv_sec * 1000.0 + currentTime.tv_usec / 1000.0; | ||
110 | |||
111 | // return in milliseconds | ||
112 | timer->averageTime = (timer->averageTime + duration) / 2.0f; | ||
113 | } | ||
114 | |||
115 | @end | ||
116 | |||
117 | #endif | ||
diff --git a/libs/cocos2d/Support/CGPointExtension.h b/libs/cocos2d/Support/CGPointExtension.h new file mode 100755 index 0000000..96edeb7 --- /dev/null +++ b/libs/cocos2d/Support/CGPointExtension.h | |||
@@ -0,0 +1,334 @@ | |||
1 | /* cocos2d for iPhone | ||
2 | * http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2007 Scott Lembcke | ||
5 | * | ||
6 | * Copyright (c) 2010 Lam Pham | ||
7 | * | ||
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
9 | * of this software and associated documentation files (the "Software"), to deal | ||
10 | * in the Software without restriction, including without limitation the rights | ||
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
12 | * copies of the Software, and to permit persons to whom the Software is | ||
13 | * furnished to do so, subject to the following conditions: | ||
14 | * | ||
15 | * The above copyright notice and this permission notice shall be included in | ||
16 | * all copies or substantial portions of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
24 | * SOFTWARE. | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * Some of the functions were based on Chipmunk's cpVect.h. | ||
29 | */ | ||
30 | |||
31 | /** | ||
32 | @file | ||
33 | CGPoint extensions based on Chipmunk's cpVect file. | ||
34 | These extensions work both with CGPoint and cpVect. | ||
35 | |||
36 | The "ccp" prefix means: "CoCos2d Point" | ||
37 | |||
38 | Examples: | ||
39 | - ccpAdd( ccp(1,1), ccp(2,2) ); // preferred cocos2d way | ||
40 | - ccpAdd( CGPointMake(1,1), CGPointMake(2,2) ); // also ok but more verbose | ||
41 | |||
42 | - cpvadd( cpv(1,1), cpv(2,2) ); // way of the chipmunk | ||
43 | - ccpAdd( cpv(1,1), cpv(2,2) ); // mixing chipmunk and cocos2d (avoid) | ||
44 | - cpvadd( CGPointMake(1,1), CGPointMake(2,2) ); // mixing chipmunk and CG (avoid) | ||
45 | */ | ||
46 | |||
47 | #import <Availability.h> | ||
48 | |||
49 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
50 | #import <CoreGraphics/CGGeometry.h> | ||
51 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
52 | #import <Foundation/Foundation.h> | ||
53 | #endif | ||
54 | |||
55 | #import <math.h> | ||
56 | #import <objc/objc.h> | ||
57 | |||
58 | #ifdef __cplusplus | ||
59 | extern "C" { | ||
60 | #endif | ||
61 | |||
62 | /** Helper macro that creates a CGPoint | ||
63 | @return CGPoint | ||
64 | @since v0.7.2 | ||
65 | */ | ||
66 | #define ccp(__X__,__Y__) CGPointMake(__X__,__Y__) | ||
67 | |||
68 | |||
69 | /** Returns opposite of point. | ||
70 | @return CGPoint | ||
71 | @since v0.7.2 | ||
72 | */ | ||
73 | static inline CGPoint | ||
74 | ccpNeg(const CGPoint v) | ||
75 | { | ||
76 | return ccp(-v.x, -v.y); | ||
77 | } | ||
78 | |||
79 | /** Calculates sum of two points. | ||
80 | @return CGPoint | ||
81 | @since v0.7.2 | ||
82 | */ | ||
83 | static inline CGPoint | ||
84 | ccpAdd(const CGPoint v1, const CGPoint v2) | ||
85 | { | ||
86 | return ccp(v1.x + v2.x, v1.y + v2.y); | ||
87 | } | ||
88 | |||
89 | /** Calculates difference of two points. | ||
90 | @return CGPoint | ||
91 | @since v0.7.2 | ||
92 | */ | ||
93 | static inline CGPoint | ||
94 | ccpSub(const CGPoint v1, const CGPoint v2) | ||
95 | { | ||
96 | return ccp(v1.x - v2.x, v1.y - v2.y); | ||
97 | } | ||
98 | |||
99 | /** Returns point multiplied by given factor. | ||
100 | @return CGPoint | ||
101 | @since v0.7.2 | ||
102 | */ | ||
103 | static inline CGPoint | ||
104 | ccpMult(const CGPoint v, const CGFloat s) | ||
105 | { | ||
106 | return ccp(v.x*s, v.y*s); | ||
107 | } | ||
108 | |||
109 | /** Calculates midpoint between two points. | ||
110 | @return CGPoint | ||
111 | @since v0.7.2 | ||
112 | */ | ||
113 | static inline CGPoint | ||
114 | ccpMidpoint(const CGPoint v1, const CGPoint v2) | ||
115 | { | ||
116 | return ccpMult(ccpAdd(v1, v2), 0.5f); | ||
117 | } | ||
118 | |||
119 | /** Calculates dot product of two points. | ||
120 | @return CGFloat | ||
121 | @since v0.7.2 | ||
122 | */ | ||
123 | static inline CGFloat | ||
124 | ccpDot(const CGPoint v1, const CGPoint v2) | ||
125 | { | ||
126 | return v1.x*v2.x + v1.y*v2.y; | ||
127 | } | ||
128 | |||
129 | /** Calculates cross product of two points. | ||
130 | @return CGFloat | ||
131 | @since v0.7.2 | ||
132 | */ | ||
133 | static inline CGFloat | ||
134 | ccpCross(const CGPoint v1, const CGPoint v2) | ||
135 | { | ||
136 | return v1.x*v2.y - v1.y*v2.x; | ||
137 | } | ||
138 | |||
139 | /** Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0 | ||
140 | @return CGPoint | ||
141 | @since v0.7.2 | ||
142 | */ | ||
143 | static inline CGPoint | ||
144 | ccpPerp(const CGPoint v) | ||
145 | { | ||
146 | return ccp(-v.y, v.x); | ||
147 | } | ||
148 | |||
149 | /** Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0 | ||
150 | @return CGPoint | ||
151 | @since v0.7.2 | ||
152 | */ | ||
153 | static inline CGPoint | ||
154 | ccpRPerp(const CGPoint v) | ||
155 | { | ||
156 | return ccp(v.y, -v.x); | ||
157 | } | ||
158 | |||
159 | /** Calculates the projection of v1 over v2. | ||
160 | @return CGPoint | ||
161 | @since v0.7.2 | ||
162 | */ | ||
163 | static inline CGPoint | ||
164 | ccpProject(const CGPoint v1, const CGPoint v2) | ||
165 | { | ||
166 | return ccpMult(v2, ccpDot(v1, v2)/ccpDot(v2, v2)); | ||
167 | } | ||
168 | |||
169 | /** Rotates two points. | ||
170 | @return CGPoint | ||
171 | @since v0.7.2 | ||
172 | */ | ||
173 | static inline CGPoint | ||
174 | ccpRotate(const CGPoint v1, const CGPoint v2) | ||
175 | { | ||
176 | return ccp(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x); | ||
177 | } | ||
178 | |||
179 | /** Unrotates two points. | ||
180 | @return CGPoint | ||
181 | @since v0.7.2 | ||
182 | */ | ||
183 | static inline CGPoint | ||
184 | ccpUnrotate(const CGPoint v1, const CGPoint v2) | ||
185 | { | ||
186 | return ccp(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y); | ||
187 | } | ||
188 | |||
189 | /** Calculates the square length of a CGPoint (not calling sqrt() ) | ||
190 | @return CGFloat | ||
191 | @since v0.7.2 | ||
192 | */ | ||
193 | static inline CGFloat | ||
194 | ccpLengthSQ(const CGPoint v) | ||
195 | { | ||
196 | return ccpDot(v, v); | ||
197 | } | ||
198 | |||
199 | /** Calculates distance between point an origin | ||
200 | @return CGFloat | ||
201 | @since v0.7.2 | ||
202 | */ | ||
203 | CGFloat ccpLength(const CGPoint v); | ||
204 | |||
205 | /** Calculates the distance between two points | ||
206 | @return CGFloat | ||
207 | @since v0.7.2 | ||
208 | */ | ||
209 | CGFloat ccpDistance(const CGPoint v1, const CGPoint v2); | ||
210 | |||
211 | /** Returns point multiplied to a length of 1. | ||
212 | @return CGPoint | ||
213 | @since v0.7.2 | ||
214 | */ | ||
215 | CGPoint ccpNormalize(const CGPoint v); | ||
216 | |||
217 | /** Converts radians to a normalized vector. | ||
218 | @return CGPoint | ||
219 | @since v0.7.2 | ||
220 | */ | ||
221 | CGPoint ccpForAngle(const CGFloat a); | ||
222 | |||
223 | /** Converts a vector to radians. | ||
224 | @return CGFloat | ||
225 | @since v0.7.2 | ||
226 | */ | ||
227 | CGFloat ccpToAngle(const CGPoint v); | ||
228 | |||
229 | |||
230 | /** Clamp a value between from and to. | ||
231 | @since v0.99.1 | ||
232 | */ | ||
233 | float clampf(float value, float min_inclusive, float max_inclusive); | ||
234 | |||
235 | /** Clamp a point between from and to. | ||
236 | @since v0.99.1 | ||
237 | */ | ||
238 | CGPoint ccpClamp(CGPoint p, CGPoint from, CGPoint to); | ||
239 | |||
240 | /** Quickly convert CGSize to a CGPoint | ||
241 | @since v0.99.1 | ||
242 | */ | ||
243 | CGPoint ccpFromSize(CGSize s); | ||
244 | |||
245 | /** Run a math operation function on each point component | ||
246 | * absf, fllorf, ceilf, roundf | ||
247 | * any function that has the signature: float func(float); | ||
248 | * For example: let's try to take the floor of x,y | ||
249 | * ccpCompOp(p,floorf); | ||
250 | @since v0.99.1 | ||
251 | */ | ||
252 | CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float)); | ||
253 | |||
254 | /** Linear Interpolation between two points a and b | ||
255 | @returns | ||
256 | alpha == 0 ? a | ||
257 | alpha == 1 ? b | ||
258 | otherwise a value between a..b | ||
259 | @since v0.99.1 | ||
260 | */ | ||
261 | CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha); | ||
262 | |||
263 | |||
264 | /** @returns if points have fuzzy equality which means equal with some degree of variance. | ||
265 | @since v0.99.1 | ||
266 | */ | ||
267 | BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float variance); | ||
268 | |||
269 | |||
270 | /** Multiplies a nd b components, a.x*b.x, a.y*b.y | ||
271 | @returns a component-wise multiplication | ||
272 | @since v0.99.1 | ||
273 | */ | ||
274 | CGPoint ccpCompMult(CGPoint a, CGPoint b); | ||
275 | |||
276 | /** @returns the signed angle in radians between two vector directions | ||
277 | @since v0.99.1 | ||
278 | */ | ||
279 | float ccpAngleSigned(CGPoint a, CGPoint b); | ||
280 | |||
281 | /** @returns the angle in radians between two vector directions | ||
282 | @since v0.99.1 | ||
283 | */ | ||
284 | float ccpAngle(CGPoint a, CGPoint b); | ||
285 | |||
286 | /** Rotates a point counter clockwise by the angle around a pivot | ||
287 | @param v is the point to rotate | ||
288 | @param pivot is the pivot, naturally | ||
289 | @param angle is the angle of rotation cw in radians | ||
290 | @returns the rotated point | ||
291 | @since v0.99.1 | ||
292 | */ | ||
293 | CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle); | ||
294 | |||
295 | /** A general line-line intersection test | ||
296 | @param p1 | ||
297 | is the startpoint for the first line P1 = (p1 - p2) | ||
298 | @param p2 | ||
299 | is the endpoint for the first line P1 = (p1 - p2) | ||
300 | @param p3 | ||
301 | is the startpoint for the second line P2 = (p3 - p4) | ||
302 | @param p4 | ||
303 | is the endpoint for the second line P2 = (p3 - p4) | ||
304 | @param s | ||
305 | is the range for a hitpoint in P1 (pa = p1 + s*(p2 - p1)) | ||
306 | @param t | ||
307 | is the range for a hitpoint in P3 (pa = p2 + t*(p4 - p3)) | ||
308 | @return bool | ||
309 | indicating successful intersection of a line | ||
310 | note that to truly test intersection for segments we have to make | ||
311 | sure that s & t lie within [0..1] and for rays, make sure s & t > 0 | ||
312 | the hit point is p3 + t * (p4 - p3); | ||
313 | the hit point also is p1 + s * (p2 - p1); | ||
314 | @since v0.99.1 | ||
315 | */ | ||
316 | BOOL ccpLineIntersect(CGPoint p1, CGPoint p2, | ||
317 | CGPoint p3, CGPoint p4, | ||
318 | float *s, float *t); | ||
319 | |||
320 | /* | ||
321 | ccpSegmentIntersect returns YES if Segment A-B intersects with segment C-D | ||
322 | @since v1.0.0 | ||
323 | */ | ||
324 | BOOL ccpSegmentIntersect(CGPoint A, CGPoint B, CGPoint C, CGPoint D); | ||
325 | |||
326 | /* | ||
327 | ccpIntersectPoint returns the intersection point of line A-B, C-D | ||
328 | @since v1.0.0 | ||
329 | */ | ||
330 | CGPoint ccpIntersectPoint(CGPoint A, CGPoint B, CGPoint C, CGPoint D); | ||
331 | |||
332 | #ifdef __cplusplus | ||
333 | } | ||
334 | #endif | ||
diff --git a/libs/cocos2d/Support/CGPointExtension.m b/libs/cocos2d/Support/CGPointExtension.m new file mode 100755 index 0000000..b06859d --- /dev/null +++ b/libs/cocos2d/Support/CGPointExtension.m | |||
@@ -0,0 +1,196 @@ | |||
1 | /* cocos2d for iPhone | ||
2 | * http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2007 Scott Lembcke | ||
5 | * | ||
6 | * Copyright (c) 2010 Lam Pham | ||
7 | * | ||
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
9 | * of this software and associated documentation files (the "Software"), to deal | ||
10 | * in the Software without restriction, including without limitation the rights | ||
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
12 | * copies of the Software, and to permit persons to whom the Software is | ||
13 | * furnished to do so, subject to the following conditions: | ||
14 | * | ||
15 | * The above copyright notice and this permission notice shall be included in | ||
16 | * all copies or substantial portions of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
24 | * SOFTWARE. | ||
25 | */ | ||
26 | |||
27 | #include "stdio.h" | ||
28 | #include "math.h" | ||
29 | |||
30 | #import "../ccMacros.h" // CC_SWAP | ||
31 | #include "CGPointExtension.h" | ||
32 | |||
33 | #define kCGPointEpsilon FLT_EPSILON | ||
34 | |||
35 | CGFloat | ||
36 | ccpLength(const CGPoint v) | ||
37 | { | ||
38 | return sqrtf(ccpLengthSQ(v)); | ||
39 | } | ||
40 | |||
41 | CGFloat | ||
42 | ccpDistance(const CGPoint v1, const CGPoint v2) | ||
43 | { | ||
44 | return ccpLength(ccpSub(v1, v2)); | ||
45 | } | ||
46 | |||
47 | CGPoint | ||
48 | ccpNormalize(const CGPoint v) | ||
49 | { | ||
50 | return ccpMult(v, 1.0f/ccpLength(v)); | ||
51 | } | ||
52 | |||
53 | CGPoint | ||
54 | ccpForAngle(const CGFloat a) | ||
55 | { | ||
56 | return ccp(cosf(a), sinf(a)); | ||
57 | } | ||
58 | |||
59 | CGFloat | ||
60 | ccpToAngle(const CGPoint v) | ||
61 | { | ||
62 | return atan2f(v.y, v.x); | ||
63 | } | ||
64 | |||
65 | CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha) | ||
66 | { | ||
67 | return ccpAdd(ccpMult(a, 1.f - alpha), ccpMult(b, alpha)); | ||
68 | } | ||
69 | |||
70 | float clampf(float value, float min_inclusive, float max_inclusive) | ||
71 | { | ||
72 | if (min_inclusive > max_inclusive) { | ||
73 | CC_SWAP(min_inclusive,max_inclusive); | ||
74 | } | ||
75 | return value < min_inclusive ? min_inclusive : value < max_inclusive? value : max_inclusive; | ||
76 | } | ||
77 | |||
78 | CGPoint ccpClamp(CGPoint p, CGPoint min_inclusive, CGPoint max_inclusive) | ||
79 | { | ||
80 | return ccp(clampf(p.x,min_inclusive.x,max_inclusive.x), clampf(p.y, min_inclusive.y, max_inclusive.y)); | ||
81 | } | ||
82 | |||
83 | CGPoint ccpFromSize(CGSize s) | ||
84 | { | ||
85 | return ccp(s.width, s.height); | ||
86 | } | ||
87 | |||
88 | CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float)) | ||
89 | { | ||
90 | return ccp(opFunc(p.x), opFunc(p.y)); | ||
91 | } | ||
92 | |||
93 | BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float var) | ||
94 | { | ||
95 | if(a.x - var <= b.x && b.x <= a.x + var) | ||
96 | if(a.y - var <= b.y && b.y <= a.y + var) | ||
97 | return true; | ||
98 | return false; | ||
99 | } | ||
100 | |||
101 | CGPoint ccpCompMult(CGPoint a, CGPoint b) | ||
102 | { | ||
103 | return ccp(a.x * b.x, a.y * b.y); | ||
104 | } | ||
105 | |||
106 | float ccpAngleSigned(CGPoint a, CGPoint b) | ||
107 | { | ||
108 | CGPoint a2 = ccpNormalize(a); | ||
109 | CGPoint b2 = ccpNormalize(b); | ||
110 | float angle = atan2f(a2.x * b2.y - a2.y * b2.x, ccpDot(a2, b2)); | ||
111 | if( fabs(angle) < kCGPointEpsilon ) return 0.f; | ||
112 | return angle; | ||
113 | } | ||
114 | |||
115 | CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle) | ||
116 | { | ||
117 | CGPoint r = ccpSub(v, pivot); | ||
118 | float cosa = cosf(angle), sina = sinf(angle); | ||
119 | float t = r.x; | ||
120 | r.x = t*cosa - r.y*sina + pivot.x; | ||
121 | r.y = t*sina + r.y*cosa + pivot.y; | ||
122 | return r; | ||
123 | } | ||
124 | |||
125 | |||
126 | BOOL ccpSegmentIntersect(CGPoint A, CGPoint B, CGPoint C, CGPoint D) | ||
127 | { | ||
128 | float S, T; | ||
129 | |||
130 | if( ccpLineIntersect(A, B, C, D, &S, &T ) | ||
131 | && (S >= 0.0f && S <= 1.0f && T >= 0.0f && T <= 1.0f) ) | ||
132 | return YES; | ||
133 | |||
134 | return NO; | ||
135 | } | ||
136 | |||
137 | CGPoint ccpIntersectPoint(CGPoint A, CGPoint B, CGPoint C, CGPoint D) | ||
138 | { | ||
139 | float S, T; | ||
140 | |||
141 | if( ccpLineIntersect(A, B, C, D, &S, &T) ) { | ||
142 | // Point of intersection | ||
143 | CGPoint P; | ||
144 | P.x = A.x + S * (B.x - A.x); | ||
145 | P.y = A.y + S * (B.y - A.y); | ||
146 | return P; | ||
147 | } | ||
148 | |||
149 | return CGPointZero; | ||
150 | } | ||
151 | |||
152 | BOOL ccpLineIntersect(CGPoint A, CGPoint B, | ||
153 | CGPoint C, CGPoint D, | ||
154 | float *S, float *T) | ||
155 | { | ||
156 | // FAIL: Line undefined | ||
157 | if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) return NO; | ||
158 | |||
159 | const float BAx = B.x - A.x; | ||
160 | const float BAy = B.y - A.y; | ||
161 | const float DCx = D.x - C.x; | ||
162 | const float DCy = D.y - C.y; | ||
163 | const float ACx = A.x - C.x; | ||
164 | const float ACy = A.y - C.y; | ||
165 | |||
166 | const float denom = DCy*BAx - DCx*BAy; | ||
167 | |||
168 | *S = DCx*ACy - DCy*ACx; | ||
169 | *T = BAx*ACy - BAy*ACx; | ||
170 | |||
171 | if (denom == 0) { | ||
172 | if (*S == 0 || *T == 0) { | ||
173 | // Lines incident | ||
174 | return YES; | ||
175 | } | ||
176 | // Lines parallel and not incident | ||
177 | return NO; | ||
178 | } | ||
179 | |||
180 | *S = *S / denom; | ||
181 | *T = *T / denom; | ||
182 | |||
183 | // Point of intersection | ||
184 | // CGPoint P; | ||
185 | // P.x = A.x + *S * (B.x - A.x); | ||
186 | // P.y = A.y + *S * (B.y - A.y); | ||
187 | |||
188 | return YES; | ||
189 | } | ||
190 | |||
191 | float ccpAngle(CGPoint a, CGPoint b) | ||
192 | { | ||
193 | float angle = acosf(ccpDot(ccpNormalize(a), ccpNormalize(b))); | ||
194 | if( fabs(angle) < kCGPointEpsilon ) return 0.f; | ||
195 | return angle; | ||
196 | } | ||
diff --git a/libs/cocos2d/Support/OpenGL_Internal.h b/libs/cocos2d/Support/OpenGL_Internal.h new file mode 100755 index 0000000..4789683 --- /dev/null +++ b/libs/cocos2d/Support/OpenGL_Internal.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | |||
3 | ===== IMPORTANT ===== | ||
4 | |||
5 | This is sample code demonstrating API, technology or techniques in development. | ||
6 | Although this sample code has been reviewed for technical accuracy, it is not | ||
7 | final. Apple is supplying this information to help you plan for the adoption of | ||
8 | the technologies and programming interfaces described herein. This information | ||
9 | is subject to change, and software implemented based on this sample code should | ||
10 | be tested with final operating system software and final documentation. Newer | ||
11 | versions of this sample code may be provided with future seeds of the API or | ||
12 | technology. For information about updates to this and other developer | ||
13 | documentation, view the New & Updated sidebars in subsequent documentation | ||
14 | seeds. | ||
15 | |||
16 | ===================== | ||
17 | |||
18 | File: OpenGL_Internal.h | ||
19 | Abstract: This file is included for support purposes and isn't necessary for | ||
20 | understanding this sample. | ||
21 | |||
22 | Version: 1.0 | ||
23 | |||
24 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
25 | ("Apple") in consideration of your agreement to the following terms, and your | ||
26 | use, installation, modification or redistribution of this Apple software | ||
27 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
28 | please do not use, install, modify or redistribute this Apple software. | ||
29 | |||
30 | In consideration of your agreement to abide by the following terms, and subject | ||
31 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
32 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
33 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
34 | modifications, in source and/or binary forms; provided that if you redistribute | ||
35 | the Apple Software in its entirety and without modifications, you must retain | ||
36 | this notice and the following text and disclaimers in all such redistributions | ||
37 | of the Apple Software. | ||
38 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
39 | to endorse or promote products derived from the Apple Software without specific | ||
40 | prior written permission from Apple. Except as expressly stated in this notice, | ||
41 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
42 | including but not limited to any patent rights that may be infringed by your | ||
43 | derivative works or by other works in which the Apple Software may be | ||
44 | incorporated. | ||
45 | |||
46 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
47 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
48 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
49 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
50 | COMBINATION WITH YOUR PRODUCTS. | ||
51 | |||
52 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
53 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
54 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
55 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
56 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
57 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
58 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
59 | |||
60 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
61 | |||
62 | */ | ||
63 | |||
64 | /* Generic error reporting */ | ||
65 | #define REPORT_ERROR(__FORMAT__, ...) printf("%s: %s\n", __FUNCTION__, [[NSString stringWithFormat:__FORMAT__, __VA_ARGS__] UTF8String]) | ||
66 | |||
67 | /* EAGL and GL functions calling wrappers that log on error */ | ||
68 | #define CALL_EAGL_FUNCTION(__FUNC__, ...) ({ EAGLError __error = __FUNC__( __VA_ARGS__ ); if(__error != kEAGLErrorSuccess) printf("%s() called from %s returned error %i\n", #__FUNC__, __FUNCTION__, __error); (__error ? NO : YES); }) | ||
69 | //#define CHECK_GL_ERROR() ({ GLenum __error = glGetError(); if(__error) printf("OpenGL error 0x%04X in %s\n", __error, __FUNCTION__); (__error ? NO : YES); }) | ||
70 | #define CHECK_GL_ERROR() ({ GLenum __error = glGetError(); if(__error) printf("OpenGL error 0x%04X in %s\n", __error, __FUNCTION__); }) | ||
71 | |||
72 | /* Optional delegate methods support */ | ||
73 | #ifndef __DELEGATE_IVAR__ | ||
74 | #define __DELEGATE_IVAR__ _delegate | ||
75 | #endif | ||
76 | #ifndef __DELEGATE_METHODS_IVAR__ | ||
77 | #define __DELEGATE_METHODS_IVAR__ _delegateMethods | ||
78 | #endif | ||
79 | #define TEST_DELEGATE_METHOD_BIT(__BIT__) (self->__DELEGATE_METHODS_IVAR__ & (1 << __BIT__)) | ||
80 | #define SET_DELEGATE_METHOD_BIT(__BIT__, __NAME__) { if([self->__DELEGATE_IVAR__ respondsToSelector:@selector(__NAME__)]) self->__DELEGATE_METHODS_IVAR__ |= (1 << __BIT__); else self->__DELEGATE_METHODS_IVAR__ &= ~(1 << __BIT__); } | ||
diff --git a/libs/cocos2d/Support/TGAlib.h b/libs/cocos2d/Support/TGAlib.h new file mode 100755 index 0000000..247084e --- /dev/null +++ b/libs/cocos2d/Support/TGAlib.h | |||
@@ -0,0 +1,55 @@ | |||
1 | // | ||
2 | // TGA lib for cocos2d-iphone | ||
3 | // | ||
4 | // sources from: http://www.lighthouse3d.com/opengl/terrain/index.php3?tgasource | ||
5 | // | ||
6 | |||
7 | //#ifndef TGA_LIB | ||
8 | //#define TGA_LIB | ||
9 | |||
10 | /** | ||
11 | @file | ||
12 | TGA image support | ||
13 | */ | ||
14 | |||
15 | enum { | ||
16 | TGA_OK, | ||
17 | TGA_ERROR_FILE_OPEN, | ||
18 | TGA_ERROR_READING_FILE, | ||
19 | TGA_ERROR_INDEXED_COLOR, | ||
20 | TGA_ERROR_MEMORY, | ||
21 | TGA_ERROR_COMPRESSED_FILE, | ||
22 | }; | ||
23 | |||
24 | /** TGA format */ | ||
25 | typedef struct sImageTGA { | ||
26 | int status; | ||
27 | unsigned char type, pixelDepth; | ||
28 | |||
29 | /** map width */ | ||
30 | short int width; | ||
31 | |||
32 | /** map height */ | ||
33 | short int height; | ||
34 | |||
35 | /** raw data */ | ||
36 | unsigned char *imageData; | ||
37 | int flipped; | ||
38 | } tImageTGA; | ||
39 | |||
40 | /// load the image header fields. We only keep those that matter! | ||
41 | void tgaLoadHeader(FILE *file, tImageTGA *info); | ||
42 | |||
43 | /// loads the image pixels. You shouldn't call this function directly | ||
44 | void tgaLoadImageData(FILE *file, tImageTGA *info); | ||
45 | |||
46 | /// this is the function to call when we want to load an image | ||
47 | tImageTGA * tgaLoad(const char *filename); | ||
48 | |||
49 | // /converts RGB to greyscale | ||
50 | void tgaRGBtogreyscale(tImageTGA *info); | ||
51 | |||
52 | /// releases the memory used for the image | ||
53 | void tgaDestroy(tImageTGA *info); | ||
54 | |||
55 | //#endif // TGA_LIB | ||
diff --git a/libs/cocos2d/Support/TGAlib.m b/libs/cocos2d/Support/TGAlib.m new file mode 100755 index 0000000..11303b4 --- /dev/null +++ b/libs/cocos2d/Support/TGAlib.m | |||
@@ -0,0 +1,274 @@ | |||
1 | // | ||
2 | // TGA lib for cocos2d-iphone | ||
3 | // | ||
4 | // sources from: http://www.lighthouse3d.com/opengl/terrain/index.php3?tgasource | ||
5 | // | ||
6 | // TGA RLE compression support by Ernesto Corvi | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | |||
12 | #import "TGAlib.h" | ||
13 | |||
14 | void tgaLoadRLEImageData(FILE *file, tImageTGA *info); | ||
15 | void tgaFlipImage( tImageTGA *info ); | ||
16 | |||
17 | // load the image header fields. We only keep those that matter! | ||
18 | void tgaLoadHeader(FILE *file, tImageTGA *info) { | ||
19 | unsigned char cGarbage; | ||
20 | short int iGarbage; | ||
21 | |||
22 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
23 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
24 | |||
25 | // type must be 2 or 3 | ||
26 | fread(&info->type, sizeof(unsigned char), 1, file); | ||
27 | |||
28 | fread(&iGarbage, sizeof(short int), 1, file); | ||
29 | fread(&iGarbage, sizeof(short int), 1, file); | ||
30 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
31 | fread(&iGarbage, sizeof(short int), 1, file); | ||
32 | fread(&iGarbage, sizeof(short int), 1, file); | ||
33 | |||
34 | fread(&info->width, sizeof(short int), 1, file); | ||
35 | fread(&info->height, sizeof(short int), 1, file); | ||
36 | fread(&info->pixelDepth, sizeof(unsigned char), 1, file); | ||
37 | |||
38 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
39 | |||
40 | info->flipped = 0; | ||
41 | if ( cGarbage & 0x20 ) info->flipped = 1; | ||
42 | } | ||
43 | |||
44 | // loads the image pixels. You shouldn't call this function directly | ||
45 | void tgaLoadImageData(FILE *file, tImageTGA *info) { | ||
46 | |||
47 | int mode,total,i; | ||
48 | unsigned char aux; | ||
49 | |||
50 | // mode equal the number of components for each pixel | ||
51 | mode = info->pixelDepth / 8; | ||
52 | // total is the number of unsigned chars we'll have to read | ||
53 | total = info->height * info->width * mode; | ||
54 | |||
55 | fread(info->imageData,sizeof(unsigned char),total,file); | ||
56 | |||
57 | // mode=3 or 4 implies that the image is RGB(A). However TGA | ||
58 | // stores it as BGR(A) so we'll have to swap R and B. | ||
59 | if (mode >= 3) | ||
60 | for (i=0; i < total; i+= mode) { | ||
61 | aux = info->imageData[i]; | ||
62 | info->imageData[i] = info->imageData[i+2]; | ||
63 | info->imageData[i+2] = aux; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | // loads the RLE encoded image pixels. You shouldn't call this function directly | ||
68 | void tgaLoadRLEImageData(FILE *file, tImageTGA *info) | ||
69 | { | ||
70 | unsigned int mode,total,i, index = 0; | ||
71 | unsigned char aux[4], runlength = 0; | ||
72 | unsigned int skip = 0, flag = 0; | ||
73 | |||
74 | // mode equal the number of components for each pixel | ||
75 | mode = info->pixelDepth / 8; | ||
76 | // total is the number of unsigned chars we'll have to read | ||
77 | total = info->height * info->width; | ||
78 | |||
79 | for( i = 0; i < total; i++ ) | ||
80 | { | ||
81 | // if we have a run length pending, run it | ||
82 | if ( runlength != 0 ) | ||
83 | { | ||
84 | // we do, update the run length count | ||
85 | runlength--; | ||
86 | skip = (flag != 0); | ||
87 | } | ||
88 | else | ||
89 | { | ||
90 | // otherwise, read in the run length token | ||
91 | if ( fread(&runlength,sizeof(unsigned char),1,file) != 1 ) | ||
92 | return; | ||
93 | |||
94 | // see if it's a RLE encoded sequence | ||
95 | flag = runlength & 0x80; | ||
96 | if ( flag ) runlength -= 128; | ||
97 | skip = 0; | ||
98 | } | ||
99 | |||
100 | // do we need to skip reading this pixel? | ||
101 | if ( !skip ) | ||
102 | { | ||
103 | // no, read in the pixel data | ||
104 | if ( fread(aux,sizeof(unsigned char),mode,file) != mode ) | ||
105 | return; | ||
106 | |||
107 | // mode=3 or 4 implies that the image is RGB(A). However TGA | ||
108 | // stores it as BGR(A) so we'll have to swap R and B. | ||
109 | if ( mode >= 3 ) | ||
110 | { | ||
111 | unsigned char tmp; | ||
112 | |||
113 | tmp = aux[0]; | ||
114 | aux[0] = aux[2]; | ||
115 | aux[2] = tmp; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // add the pixel to our image | ||
120 | memcpy(&info->imageData[index], aux, mode); | ||
121 | index += mode; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | void tgaFlipImage( tImageTGA *info ) | ||
126 | { | ||
127 | // mode equal the number of components for each pixel | ||
128 | int mode = info->pixelDepth / 8; | ||
129 | int rowbytes = info->width*mode; | ||
130 | unsigned char *row = (unsigned char *)malloc(rowbytes); | ||
131 | int y; | ||
132 | |||
133 | if (row == NULL) return; | ||
134 | |||
135 | for( y = 0; y < (info->height/2); y++ ) | ||
136 | { | ||
137 | memcpy(row, &info->imageData[y*rowbytes],rowbytes); | ||
138 | memcpy(&info->imageData[y*rowbytes], &info->imageData[(info->height-(y+1))*rowbytes], rowbytes); | ||
139 | memcpy(&info->imageData[(info->height-(y+1))*rowbytes], row, rowbytes); | ||
140 | } | ||
141 | |||
142 | free(row); | ||
143 | info->flipped = 0; | ||
144 | } | ||
145 | |||
146 | // this is the function to call when we want to load an image | ||
147 | tImageTGA * tgaLoad(const char *filename) { | ||
148 | |||
149 | FILE *file; | ||
150 | tImageTGA *info; | ||
151 | int mode,total; | ||
152 | |||
153 | // allocate memory for the info struct and check! | ||
154 | info = (tImageTGA *)malloc(sizeof(tImageTGA)); | ||
155 | if (info == NULL) | ||
156 | return(NULL); | ||
157 | |||
158 | |||
159 | // open the file for reading (binary mode) | ||
160 | file = fopen(filename, "rb"); | ||
161 | if (file == NULL) { | ||
162 | info->status = TGA_ERROR_FILE_OPEN; | ||
163 | return(info); | ||
164 | } | ||
165 | |||
166 | // load the header | ||
167 | tgaLoadHeader(file,info); | ||
168 | |||
169 | // check for errors when loading the header | ||
170 | if (ferror(file)) { | ||
171 | info->status = TGA_ERROR_READING_FILE; | ||
172 | fclose(file); | ||
173 | return(info); | ||
174 | } | ||
175 | |||
176 | // check if the image is color indexed | ||
177 | if (info->type == 1) { | ||
178 | info->status = TGA_ERROR_INDEXED_COLOR; | ||
179 | fclose(file); | ||
180 | return(info); | ||
181 | } | ||
182 | // check for other types (compressed images) | ||
183 | if ((info->type != 2) && (info->type !=3) && (info->type !=10) ) { | ||
184 | info->status = TGA_ERROR_COMPRESSED_FILE; | ||
185 | fclose(file); | ||
186 | return(info); | ||
187 | } | ||
188 | |||
189 | // mode equals the number of image components | ||
190 | mode = info->pixelDepth / 8; | ||
191 | // total is the number of unsigned chars to read | ||
192 | total = info->height * info->width * mode; | ||
193 | // allocate memory for image pixels | ||
194 | info->imageData = (unsigned char *)malloc(sizeof(unsigned char) * | ||
195 | total); | ||
196 | |||
197 | // check to make sure we have the memory required | ||
198 | if (info->imageData == NULL) { | ||
199 | info->status = TGA_ERROR_MEMORY; | ||
200 | fclose(file); | ||
201 | return(info); | ||
202 | } | ||
203 | // finally load the image pixels | ||
204 | if ( info->type == 10 ) | ||
205 | tgaLoadRLEImageData(file, info); | ||
206 | else | ||
207 | tgaLoadImageData(file,info); | ||
208 | |||
209 | // check for errors when reading the pixels | ||
210 | if (ferror(file)) { | ||
211 | info->status = TGA_ERROR_READING_FILE; | ||
212 | fclose(file); | ||
213 | return(info); | ||
214 | } | ||
215 | fclose(file); | ||
216 | info->status = TGA_OK; | ||
217 | |||
218 | if ( info->flipped ) | ||
219 | { | ||
220 | tgaFlipImage( info ); | ||
221 | if ( info->flipped ) info->status = TGA_ERROR_MEMORY; | ||
222 | } | ||
223 | |||
224 | return(info); | ||
225 | } | ||
226 | |||
227 | // converts RGB to greyscale | ||
228 | void tgaRGBtogreyscale(tImageTGA *info) { | ||
229 | |||
230 | int mode,i,j; | ||
231 | |||
232 | unsigned char *newImageData; | ||
233 | |||
234 | // if the image is already greyscale do nothing | ||
235 | if (info->pixelDepth == 8) | ||
236 | return; | ||
237 | |||
238 | // compute the number of actual components | ||
239 | mode = info->pixelDepth / 8; | ||
240 | |||
241 | // allocate an array for the new image data | ||
242 | newImageData = (unsigned char *)malloc(sizeof(unsigned char) * | ||
243 | info->height * info->width); | ||
244 | if (newImageData == NULL) { | ||
245 | return; | ||
246 | } | ||
247 | |||
248 | // convert pixels: greyscale = o.30 * R + 0.59 * G + 0.11 * B | ||
249 | for (i = 0,j = 0; j < info->width * info->height; i +=mode, j++) | ||
250 | newImageData[j] = | ||
251 | (unsigned char)(0.30 * info->imageData[i] + | ||
252 | 0.59 * info->imageData[i+1] + | ||
253 | 0.11 * info->imageData[i+2]); | ||
254 | |||
255 | |||
256 | //free old image data | ||
257 | free(info->imageData); | ||
258 | |||
259 | // reassign pixelDepth and type according to the new image type | ||
260 | info->pixelDepth = 8; | ||
261 | info->type = 3; | ||
262 | // reassing imageData to the new array. | ||
263 | info->imageData = newImageData; | ||
264 | } | ||
265 | |||
266 | // releases the memory used for the image | ||
267 | void tgaDestroy(tImageTGA *info) { | ||
268 | |||
269 | if (info != NULL) { | ||
270 | if (info->imageData != NULL) | ||
271 | free(info->imageData); | ||
272 | free(info); | ||
273 | } | ||
274 | } | ||
diff --git a/libs/cocos2d/Support/TransformUtils.h b/libs/cocos2d/Support/TransformUtils.h new file mode 100755 index 0000000..49fde35 --- /dev/null +++ b/libs/cocos2d/Support/TransformUtils.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import <Availability.h> | ||
27 | |||
28 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
29 | #import <UIKit/UIKit.h> | ||
30 | #import <OpenGLES/ES1/gl.h> | ||
31 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
32 | #import <OpenGL/gl.h> | ||
33 | #import <Foundation/Foundation.h> | ||
34 | #endif | ||
35 | |||
36 | void CGAffineToGL(const CGAffineTransform *t, GLfloat *m); | ||
37 | void GLToCGAffine(const GLfloat *m, CGAffineTransform *t); | ||
diff --git a/libs/cocos2d/Support/TransformUtils.m b/libs/cocos2d/Support/TransformUtils.m new file mode 100755 index 0000000..9caecf0 --- /dev/null +++ b/libs/cocos2d/Support/TransformUtils.m | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "TransformUtils.h" | ||
28 | |||
29 | void CGAffineToGL(const CGAffineTransform *t, GLfloat *m) | ||
30 | { | ||
31 | // | m[0] m[4] m[8] m[12] | | m11 m21 m31 m41 | | a c 0 tx | | ||
32 | // | m[1] m[5] m[9] m[13] | | m12 m22 m32 m42 | | b d 0 ty | | ||
33 | // | m[2] m[6] m[10] m[14] | <=> | m13 m23 m33 m43 | <=> | 0 0 1 0 | | ||
34 | // | m[3] m[7] m[11] m[15] | | m14 m24 m34 m44 | | 0 0 0 1 | | ||
35 | |||
36 | m[2] = m[3] = m[6] = m[7] = m[8] = m[9] = m[11] = m[14] = 0.0f; | ||
37 | m[10] = m[15] = 1.0f; | ||
38 | m[0] = t->a; m[4] = t->c; m[12] = t->tx; | ||
39 | m[1] = t->b; m[5] = t->d; m[13] = t->ty; | ||
40 | } | ||
41 | |||
42 | void GLToCGAffine(const GLfloat *m, CGAffineTransform *t) | ||
43 | { | ||
44 | t->a = m[0]; t->c = m[4]; t->tx = m[12]; | ||
45 | t->b = m[1]; t->d = m[5]; t->ty = m[13]; | ||
46 | } | ||
diff --git a/libs/cocos2d/Support/ZipUtils.h b/libs/cocos2d/Support/ZipUtils.h new file mode 100755 index 0000000..363f911 --- /dev/null +++ b/libs/cocos2d/Support/ZipUtils.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* cocos2d for iPhone | ||
2 | * | ||
3 | * http://www.cocos2d-iphone.org | ||
4 | * | ||
5 | * | ||
6 | * inflateMemory_ based on zlib example code | ||
7 | * http://www.zlib.net | ||
8 | * | ||
9 | * Some ideas were taken from: | ||
10 | * http://themanaworld.org/ | ||
11 | * from the mapreader.cpp file | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __CC_ZIP_UTILS_H | ||
16 | #define __CC_ZIP_UTILS_H | ||
17 | |||
18 | #import <stdint.h> | ||
19 | |||
20 | #ifdef __cplusplus | ||
21 | extern "C" { | ||
22 | #endif | ||
23 | |||
24 | /* XXX: pragma pack ??? */ | ||
25 | /** @struct CCZHeader | ||
26 | */ | ||
27 | struct CCZHeader { | ||
28 | uint8_t sig[4]; // signature. Should be 'CCZ!' 4 bytes | ||
29 | uint16_t compression_type; // should 0 | ||
30 | uint16_t version; // should be 2 (although version type==1 is also supported) | ||
31 | uint32_t reserved; // Reserverd for users. | ||
32 | uint32_t len; // size of the uncompressed file | ||
33 | }; | ||
34 | |||
35 | enum { | ||
36 | CCZ_COMPRESSION_ZLIB, // zlib format. | ||
37 | CCZ_COMPRESSION_BZIP2, // bzip2 format (not supported yet) | ||
38 | CCZ_COMPRESSION_GZIP, // gzip format (not supported yet) | ||
39 | CCZ_COMPRESSION_NONE, // plain (not supported yet) | ||
40 | }; | ||
41 | |||
42 | /** @file | ||
43 | * Zip helper functions | ||
44 | */ | ||
45 | |||
46 | /** | ||
47 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
48 | * expected to be freed by the caller. | ||
49 | * | ||
50 | * It will allocate 256k for the destination buffer. If it is not enought it will multiply the previous buffer size per 2, until there is enough memory. | ||
51 | * @returns the length of the deflated buffer | ||
52 | * | ||
53 | @since v0.8.1 | ||
54 | */ | ||
55 | int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out); | ||
56 | |||
57 | /** | ||
58 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
59 | * expected to be freed by the caller. | ||
60 | * | ||
61 | * outLenghtHint is assumed to be the needed room to allocate the inflated buffer. | ||
62 | * | ||
63 | * @returns the length of the deflated buffer | ||
64 | * | ||
65 | @since v1.0.0 | ||
66 | */ | ||
67 | int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLenghtHint ); | ||
68 | |||
69 | |||
70 | /** inflates a GZip file into memory | ||
71 | * | ||
72 | * @returns the length of the deflated buffer | ||
73 | * | ||
74 | * @since v0.99.5 | ||
75 | */ | ||
76 | int ccInflateGZipFile(const char *filename, unsigned char **out); | ||
77 | |||
78 | /** inflates a CCZ file into memory | ||
79 | * | ||
80 | * @returns the length of the deflated buffer | ||
81 | * | ||
82 | * @since v0.99.5 | ||
83 | */ | ||
84 | int ccInflateCCZFile(const char *filename, unsigned char **out); | ||
85 | |||
86 | |||
87 | #ifdef __cplusplus | ||
88 | } | ||
89 | #endif | ||
90 | |||
91 | #endif // __CC_ZIP_UTILS_H | ||
diff --git a/libs/cocos2d/Support/ZipUtils.m b/libs/cocos2d/Support/ZipUtils.m new file mode 100755 index 0000000..ccd8bbc --- /dev/null +++ b/libs/cocos2d/Support/ZipUtils.m | |||
@@ -0,0 +1,251 @@ | |||
1 | /* cocos2d for iPhone | ||
2 | * | ||
3 | * http://www.cocos2d-iphone.org | ||
4 | * | ||
5 | * | ||
6 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
7 | * expected to be freed by the caller. | ||
8 | * | ||
9 | * inflateMemory_ based on zlib example code | ||
10 | * http://www.zlib.net | ||
11 | * | ||
12 | * Some ideas were taken from: | ||
13 | * http://themanaworld.org/ | ||
14 | * from the mapreader.cpp file | ||
15 | */ | ||
16 | |||
17 | #import <Availability.h> | ||
18 | |||
19 | #import <zlib.h> | ||
20 | #import <stdlib.h> | ||
21 | #import <assert.h> | ||
22 | #import <stdio.h> | ||
23 | |||
24 | #import "ZipUtils.h" | ||
25 | #import "CCFileUtils.h" | ||
26 | #import "../ccMacros.h" | ||
27 | |||
28 | // memory in iPhone is precious | ||
29 | // Should buffer factor be 1.5 instead of 2 ? | ||
30 | #define BUFFER_INC_FACTOR (2) | ||
31 | |||
32 | static int inflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int *outLength, unsigned int outLenghtHint ) | ||
33 | { | ||
34 | /* ret value */ | ||
35 | int err = Z_OK; | ||
36 | |||
37 | int bufferSize = outLenghtHint; | ||
38 | *out = (unsigned char*) malloc(bufferSize); | ||
39 | |||
40 | z_stream d_stream; /* decompression stream */ | ||
41 | d_stream.zalloc = (alloc_func)0; | ||
42 | d_stream.zfree = (free_func)0; | ||
43 | d_stream.opaque = (voidpf)0; | ||
44 | |||
45 | d_stream.next_in = in; | ||
46 | d_stream.avail_in = inLength; | ||
47 | d_stream.next_out = *out; | ||
48 | d_stream.avail_out = bufferSize; | ||
49 | |||
50 | /* window size to hold 256k */ | ||
51 | if( (err = inflateInit2(&d_stream, 15 + 32)) != Z_OK ) | ||
52 | return err; | ||
53 | |||
54 | for (;;) { | ||
55 | err = inflate(&d_stream, Z_NO_FLUSH); | ||
56 | |||
57 | if (err == Z_STREAM_END) | ||
58 | break; | ||
59 | |||
60 | switch (err) { | ||
61 | case Z_NEED_DICT: | ||
62 | err = Z_DATA_ERROR; | ||
63 | case Z_DATA_ERROR: | ||
64 | case Z_MEM_ERROR: | ||
65 | inflateEnd(&d_stream); | ||
66 | return err; | ||
67 | } | ||
68 | |||
69 | // not enough memory ? | ||
70 | if (err != Z_STREAM_END) { | ||
71 | |||
72 | unsigned char *tmp = realloc(*out, bufferSize * BUFFER_INC_FACTOR); | ||
73 | |||
74 | /* not enough memory, ouch */ | ||
75 | if (! tmp ) { | ||
76 | CCLOG(@"cocos2d: ZipUtils: realloc failed"); | ||
77 | inflateEnd(&d_stream); | ||
78 | return Z_MEM_ERROR; | ||
79 | } | ||
80 | /* only assign to *out if tmp is valid. it's not guaranteed that realloc will reuse the memory */ | ||
81 | *out = tmp; | ||
82 | |||
83 | d_stream.next_out = *out + bufferSize; | ||
84 | d_stream.avail_out = bufferSize; | ||
85 | bufferSize *= BUFFER_INC_FACTOR; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | |||
90 | *outLength = bufferSize - d_stream.avail_out; | ||
91 | err = inflateEnd(&d_stream); | ||
92 | return err; | ||
93 | } | ||
94 | |||
95 | int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLengthHint ) | ||
96 | { | ||
97 | unsigned int outLength = 0; | ||
98 | int err = inflateMemoryWithHint(in, inLength, out, &outLength, outLengthHint ); | ||
99 | |||
100 | if (err != Z_OK || *out == NULL) { | ||
101 | if (err == Z_MEM_ERROR) | ||
102 | CCLOG(@"cocos2d: ZipUtils: Out of memory while decompressing map data!"); | ||
103 | |||
104 | else if (err == Z_VERSION_ERROR) | ||
105 | CCLOG(@"cocos2d: ZipUtils: Incompatible zlib version!"); | ||
106 | |||
107 | else if (err == Z_DATA_ERROR) | ||
108 | CCLOG(@"cocos2d: ZipUtils: Incorrect zlib compressed data!"); | ||
109 | |||
110 | else | ||
111 | CCLOG(@"cocos2d: ZipUtils: Unknown error while decompressing map data!"); | ||
112 | |||
113 | free(*out); | ||
114 | *out = NULL; | ||
115 | outLength = 0; | ||
116 | } | ||
117 | |||
118 | return outLength; | ||
119 | } | ||
120 | |||
121 | int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out) | ||
122 | { | ||
123 | // 256k for hint | ||
124 | return ccInflateMemoryWithHint(in, inLength, out, 256 * 1024 ); | ||
125 | } | ||
126 | |||
127 | int ccInflateGZipFile(const char *path, unsigned char **out) | ||
128 | { | ||
129 | int len; | ||
130 | unsigned int offset = 0; | ||
131 | |||
132 | NSCAssert( out, @"ccInflateGZipFile: invalid 'out' parameter"); | ||
133 | NSCAssert( &*out, @"ccInflateGZipFile: invalid 'out' parameter"); | ||
134 | |||
135 | gzFile inFile = gzopen(path, "rb"); | ||
136 | if( inFile == NULL ) { | ||
137 | CCLOG(@"cocos2d: ZipUtils: error open gzip file: %s", path); | ||
138 | return -1; | ||
139 | } | ||
140 | |||
141 | /* 512k initial decompress buffer */ | ||
142 | int bufferSize = 512 * 1024; | ||
143 | unsigned int totalBufferSize = bufferSize; | ||
144 | |||
145 | *out = malloc( bufferSize ); | ||
146 | if( ! out ) { | ||
147 | CCLOG(@"cocos2d: ZipUtils: out of memory"); | ||
148 | return -1; | ||
149 | } | ||
150 | |||
151 | for (;;) { | ||
152 | len = gzread(inFile, *out + offset, bufferSize); | ||
153 | if (len < 0) { | ||
154 | CCLOG(@"cocos2d: ZipUtils: error in gzread"); | ||
155 | free( *out ); | ||
156 | *out = NULL; | ||
157 | return -1; | ||
158 | } | ||
159 | if (len == 0) | ||
160 | break; | ||
161 | |||
162 | offset += len; | ||
163 | |||
164 | // finish reading the file | ||
165 | if( len < bufferSize ) | ||
166 | break; | ||
167 | |||
168 | bufferSize *= BUFFER_INC_FACTOR; | ||
169 | totalBufferSize += bufferSize; | ||
170 | unsigned char *tmp = realloc(*out, totalBufferSize ); | ||
171 | |||
172 | if( ! tmp ) { | ||
173 | CCLOG(@"cocos2d: ZipUtils: out of memory"); | ||
174 | free( *out ); | ||
175 | *out = NULL; | ||
176 | return -1; | ||
177 | } | ||
178 | |||
179 | *out = tmp; | ||
180 | } | ||
181 | |||
182 | if (gzclose(inFile) != Z_OK) | ||
183 | CCLOG(@"cocos2d: ZipUtils: gzclose failed"); | ||
184 | |||
185 | return offset; | ||
186 | } | ||
187 | |||
188 | int ccInflateCCZFile(const char *path, unsigned char **out) | ||
189 | { | ||
190 | NSCAssert( out, @"ccInflateCCZFile: invalid 'out' parameter"); | ||
191 | NSCAssert( &*out, @"ccInflateCCZFile: invalid 'out' parameter"); | ||
192 | |||
193 | // load file into memory | ||
194 | unsigned char *compressed = NULL; | ||
195 | NSInteger fileLen = ccLoadFileIntoMemory( path, &compressed ); | ||
196 | if( fileLen < 0 ) { | ||
197 | CCLOG(@"cocos2d: Error loading CCZ compressed file"); | ||
198 | } | ||
199 | |||
200 | struct CCZHeader *header = (struct CCZHeader*) compressed; | ||
201 | |||
202 | // verify header | ||
203 | if( header->sig[0] != 'C' || header->sig[1] != 'C' || header->sig[2] != 'Z' || header->sig[3] != '!' ) { | ||
204 | CCLOG(@"cocos2d: Invalid CCZ file"); | ||
205 | free(compressed); | ||
206 | return -1; | ||
207 | } | ||
208 | |||
209 | // verify header version | ||
210 | uint16_t version = CFSwapInt16BigToHost( header->version ); | ||
211 | if( version > 2 ) { | ||
212 | CCLOG(@"cocos2d: Unsupported CCZ header format"); | ||
213 | free(compressed); | ||
214 | return -1; | ||
215 | } | ||
216 | |||
217 | // verify compression format | ||
218 | if( CFSwapInt16BigToHost(header->compression_type) != CCZ_COMPRESSION_ZLIB ) { | ||
219 | CCLOG(@"cocos2d: CCZ Unsupported compression method"); | ||
220 | free(compressed); | ||
221 | return -1; | ||
222 | } | ||
223 | |||
224 | uint32_t len = CFSwapInt32BigToHost( header->len ); | ||
225 | |||
226 | *out = malloc( len ); | ||
227 | if(! *out ) | ||
228 | { | ||
229 | CCLOG(@"cocos2d: CCZ: Failed to allocate memory for texture"); | ||
230 | free(compressed); | ||
231 | return -1; | ||
232 | } | ||
233 | |||
234 | |||
235 | uLongf destlen = len; | ||
236 | uLongf source = (uLongf) compressed + sizeof(*header); | ||
237 | int ret = uncompress(*out, &destlen, (Bytef*)source, fileLen - sizeof(*header) ); | ||
238 | |||
239 | free( compressed ); | ||
240 | |||
241 | if( ret != Z_OK ) | ||
242 | { | ||
243 | CCLOG(@"cocos2d: CCZ: Failed to uncompress data"); | ||
244 | free( *out ); | ||
245 | *out = NULL; | ||
246 | return -1; | ||
247 | } | ||
248 | |||
249 | |||
250 | return len; | ||
251 | } | ||
diff --git a/libs/cocos2d/Support/base64.c b/libs/cocos2d/Support/base64.c new file mode 100755 index 0000000..9aa52a6 --- /dev/null +++ b/libs/cocos2d/Support/base64.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | public domain BASE64 code | ||
3 | |||
4 | modified for cocos2d-iphone: http://www.cocos2d-iphone.org | ||
5 | */ | ||
6 | |||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | |||
10 | #include "base64.h" | ||
11 | |||
12 | unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
13 | |||
14 | int _base64Decode( unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len ); | ||
15 | |||
16 | int _base64Decode( unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len ) | ||
17 | { | ||
18 | static char inalphabet[256], decoder[256]; | ||
19 | int i, bits, c, char_count, errors = 0; | ||
20 | unsigned int input_idx = 0; | ||
21 | unsigned int output_idx = 0; | ||
22 | |||
23 | for (i = (sizeof alphabet) - 1; i >= 0 ; i--) { | ||
24 | inalphabet[alphabet[i]] = 1; | ||
25 | decoder[alphabet[i]] = i; | ||
26 | } | ||
27 | |||
28 | char_count = 0; | ||
29 | bits = 0; | ||
30 | for( input_idx=0; input_idx < input_len ; input_idx++ ) { | ||
31 | c = input[ input_idx ]; | ||
32 | if (c == '=') | ||
33 | break; | ||
34 | if (c > 255 || ! inalphabet[c]) | ||
35 | continue; | ||
36 | bits += decoder[c]; | ||
37 | char_count++; | ||
38 | if (char_count == 4) { | ||
39 | output[ output_idx++ ] = (bits >> 16); | ||
40 | output[ output_idx++ ] = ((bits >> 8) & 0xff); | ||
41 | output[ output_idx++ ] = ( bits & 0xff); | ||
42 | bits = 0; | ||
43 | char_count = 0; | ||
44 | } else { | ||
45 | bits <<= 6; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | if( c == '=' ) { | ||
50 | switch (char_count) { | ||
51 | case 1: | ||
52 | fprintf(stderr, "base64Decode: encoding incomplete: at least 2 bits missing"); | ||
53 | errors++; | ||
54 | break; | ||
55 | case 2: | ||
56 | output[ output_idx++ ] = ( bits >> 10 ); | ||
57 | break; | ||
58 | case 3: | ||
59 | output[ output_idx++ ] = ( bits >> 16 ); | ||
60 | output[ output_idx++ ] = (( bits >> 8 ) & 0xff); | ||
61 | break; | ||
62 | } | ||
63 | } else if ( input_idx < input_len ) { | ||
64 | if (char_count) { | ||
65 | fprintf(stderr, "base64 encoding incomplete: at least %d bits truncated", | ||
66 | ((4 - char_count) * 6)); | ||
67 | errors++; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | *output_len = output_idx; | ||
72 | return errors; | ||
73 | } | ||
74 | |||
75 | int base64Decode(unsigned char *in, unsigned int inLength, unsigned char **out) | ||
76 | { | ||
77 | unsigned int outLength = 0; | ||
78 | |||
79 | //should be enough to store 6-bit buffers in 8-bit buffers | ||
80 | *out = malloc( inLength * 3.0f / 4.0f + 1 ); | ||
81 | if( *out ) { | ||
82 | int ret = _base64Decode(in, inLength, *out, &outLength); | ||
83 | |||
84 | if (ret > 0 ) | ||
85 | { | ||
86 | printf("Base64Utils: error decoding"); | ||
87 | free(*out); | ||
88 | *out = NULL; | ||
89 | outLength = 0; | ||
90 | } | ||
91 | } | ||
92 | return outLength; | ||
93 | } | ||
diff --git a/libs/cocos2d/Support/base64.h b/libs/cocos2d/Support/base64.h new file mode 100755 index 0000000..d30878e --- /dev/null +++ b/libs/cocos2d/Support/base64.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | public domain BASE64 code | ||
3 | |||
4 | modified for cocos2d-iphone: http://www.cocos2d-iphone.org | ||
5 | */ | ||
6 | |||
7 | #ifndef __CC_BASE64_DECODE_H | ||
8 | #define __CC_BASE64_DECODE_H | ||
9 | |||
10 | #ifdef __cplusplus | ||
11 | extern "C" { | ||
12 | #endif | ||
13 | |||
14 | |||
15 | /** @file | ||
16 | base64 helper functions | ||
17 | */ | ||
18 | |||
19 | /** | ||
20 | * Decodes a 64base encoded memory. The decoded memory is | ||
21 | * expected to be freed by the caller. | ||
22 | * | ||
23 | * @returns the length of the out buffer | ||
24 | * | ||
25 | @since v0.8.1 | ||
26 | */ | ||
27 | int base64Decode(unsigned char *in, unsigned int inLength, unsigned char **out); | ||
28 | |||
29 | #ifdef __cplusplus | ||
30 | } | ||
31 | #endif | ||
32 | |||
33 | #endif // __CC_BASE64_DECODE_H | ||
diff --git a/libs/cocos2d/Support/ccCArray.h b/libs/cocos2d/Support/ccCArray.h new file mode 100755 index 0000000..20d9633 --- /dev/null +++ b/libs/cocos2d/Support/ccCArray.h | |||
@@ -0,0 +1,447 @@ | |||
1 | /* Copyright (c) 2007 Scott Lembcke | ||
2 | * | ||
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | * of this software and associated documentation files (the "Software"), to deal | ||
5 | * in the Software without restriction, including without limitation the rights | ||
6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | * copies of the Software, and to permit persons to whom the Software is | ||
8 | * furnished to do so, subject to the following conditions: | ||
9 | * | ||
10 | * The above copyright notice and this permission notice shall be included in | ||
11 | * all copies or substantial portions of the Software. | ||
12 | * | ||
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
19 | * SOFTWARE. | ||
20 | */ | ||
21 | |||
22 | /** | ||
23 | @file | ||
24 | Based on Chipmunk cpArray. | ||
25 | ccArray is a faster alternative to NSMutableArray, it does pretty much the | ||
26 | same thing (stores NSObjects and retains/releases them appropriately). It's | ||
27 | faster because: | ||
28 | - it uses a plain C interface so it doesn't incur Objective-c messaging overhead | ||
29 | - it assumes you know what you're doing, so it doesn't spend time on safety checks | ||
30 | (index out of bounds, required capacity etc.) | ||
31 | - comparisons are done using pointer equality instead of isEqual | ||
32 | |||
33 | There are 2 kind of functions: | ||
34 | - ccArray functions that manipulates objective-c objects (retain and release are performanced) | ||
35 | - ccCArray functions that manipulates values like if they were standard C structures (no retain/release is performed) | ||
36 | */ | ||
37 | |||
38 | #ifndef CC_ARRAY_H | ||
39 | #define CC_ARRAY_H | ||
40 | |||
41 | #import <Foundation/Foundation.h> | ||
42 | |||
43 | #import <stdlib.h> | ||
44 | #import <string.h> | ||
45 | |||
46 | |||
47 | #pragma mark - | ||
48 | #pragma mark ccArray for Objects | ||
49 | |||
50 | // Easy integration | ||
51 | #define CCARRAYDATA_FOREACH(__array__, __object__) \ | ||
52 | __object__=__array__->arr[0]; for(NSUInteger i=0, num=__array__->num; i<num; i++, __object__=__array__->arr[i]) \ | ||
53 | |||
54 | |||
55 | typedef struct ccArray { | ||
56 | NSUInteger num, max; | ||
57 | id *arr; | ||
58 | } ccArray; | ||
59 | |||
60 | /** Allocates and initializes a new array with specified capacity */ | ||
61 | static inline ccArray* ccArrayNew(NSUInteger capacity) { | ||
62 | if (capacity == 0) | ||
63 | capacity = 1; | ||
64 | |||
65 | ccArray *arr = (ccArray*)malloc( sizeof(ccArray) ); | ||
66 | arr->num = 0; | ||
67 | arr->arr = (id*) malloc( capacity * sizeof(id) ); | ||
68 | arr->max = capacity; | ||
69 | |||
70 | return arr; | ||
71 | } | ||
72 | |||
73 | static inline void ccArrayRemoveAllObjects(ccArray *arr); | ||
74 | |||
75 | /** Frees array after removing all remaining objects. Silently ignores nil arr. */ | ||
76 | static inline void ccArrayFree(ccArray *arr) | ||
77 | { | ||
78 | if( arr == nil ) return; | ||
79 | |||
80 | ccArrayRemoveAllObjects(arr); | ||
81 | |||
82 | free(arr->arr); | ||
83 | free(arr); | ||
84 | } | ||
85 | |||
86 | /** Doubles array capacity */ | ||
87 | static inline void ccArrayDoubleCapacity(ccArray *arr) | ||
88 | { | ||
89 | arr->max *= 2; | ||
90 | id *newArr = (id *)realloc( arr->arr, arr->max * sizeof(id) ); | ||
91 | // will fail when there's not enough memory | ||
92 | NSCAssert(newArr != NULL, @"ccArrayDoubleCapacity failed. Not enough memory"); | ||
93 | arr->arr = newArr; | ||
94 | } | ||
95 | |||
96 | /** Increases array capacity such that max >= num + extra. */ | ||
97 | static inline void ccArrayEnsureExtraCapacity(ccArray *arr, NSUInteger extra) | ||
98 | { | ||
99 | while (arr->max < arr->num + extra) | ||
100 | ccArrayDoubleCapacity(arr); | ||
101 | } | ||
102 | |||
103 | /** shrinks the array so the memory footprint corresponds with the number of items */ | ||
104 | static inline void ccArrayShrink(ccArray *arr) | ||
105 | { | ||
106 | NSUInteger newSize; | ||
107 | |||
108 | //only resize when necessary | ||
109 | if (arr->max > arr->num && !(arr->num==0 && arr->max==1)) | ||
110 | { | ||
111 | if (arr->num!=0) | ||
112 | { | ||
113 | newSize=arr->num; | ||
114 | arr->max=arr->num; | ||
115 | } | ||
116 | else | ||
117 | {//minimum capacity of 1, with 0 elements the array would be free'd by realloc | ||
118 | newSize=1; | ||
119 | arr->max=1; | ||
120 | } | ||
121 | |||
122 | arr->arr = (id*) realloc(arr->arr,newSize * sizeof(id) ); | ||
123 | NSCAssert(arr->arr!=NULL,@"could not reallocate the memory"); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /** Returns index of first occurence of object, NSNotFound if object not found. */ | ||
128 | static inline NSUInteger ccArrayGetIndexOfObject(ccArray *arr, id object) | ||
129 | { | ||
130 | for( NSUInteger i = 0; i < arr->num; i++) | ||
131 | if( arr->arr[i] == object ) return i; | ||
132 | |||
133 | return NSNotFound; | ||
134 | } | ||
135 | |||
136 | /** Returns a Boolean value that indicates whether object is present in array. */ | ||
137 | static inline BOOL ccArrayContainsObject(ccArray *arr, id object) | ||
138 | { | ||
139 | return ccArrayGetIndexOfObject(arr, object) != NSNotFound; | ||
140 | } | ||
141 | |||
142 | /** Appends an object. Bahaviour undefined if array doesn't have enough capacity. */ | ||
143 | static inline void ccArrayAppendObject(ccArray *arr, id object) | ||
144 | { | ||
145 | arr->arr[arr->num] = [object retain]; | ||
146 | arr->num++; | ||
147 | } | ||
148 | |||
149 | /** Appends an object. Capacity of arr is increased if needed. */ | ||
150 | static inline void ccArrayAppendObjectWithResize(ccArray *arr, id object) | ||
151 | { | ||
152 | ccArrayEnsureExtraCapacity(arr, 1); | ||
153 | ccArrayAppendObject(arr, object); | ||
154 | } | ||
155 | |||
156 | /** Appends objects from plusArr to arr. Behaviour undefined if arr doesn't have | ||
157 | enough capacity. */ | ||
158 | static inline void ccArrayAppendArray(ccArray *arr, ccArray *plusArr) | ||
159 | { | ||
160 | for( NSUInteger i = 0; i < plusArr->num; i++) | ||
161 | ccArrayAppendObject(arr, plusArr->arr[i]); | ||
162 | } | ||
163 | |||
164 | /** Appends objects from plusArr to arr. Capacity of arr is increased if needed. */ | ||
165 | static inline void ccArrayAppendArrayWithResize(ccArray *arr, ccArray *plusArr) | ||
166 | { | ||
167 | ccArrayEnsureExtraCapacity(arr, plusArr->num); | ||
168 | ccArrayAppendArray(arr, plusArr); | ||
169 | } | ||
170 | |||
171 | /** Inserts an object at index */ | ||
172 | static inline void ccArrayInsertObjectAtIndex(ccArray *arr, id object, NSUInteger index) | ||
173 | { | ||
174 | NSCAssert(index<=arr->num, @"Invalid index. Out of bounds"); | ||
175 | |||
176 | ccArrayEnsureExtraCapacity(arr, 1); | ||
177 | |||
178 | NSUInteger remaining = arr->num - index; | ||
179 | if( remaining > 0) | ||
180 | memmove(&arr->arr[index+1], &arr->arr[index], sizeof(id) * remaining ); | ||
181 | |||
182 | arr->arr[index] = [object retain]; | ||
183 | arr->num++; | ||
184 | } | ||
185 | |||
186 | /** Swaps two objects */ | ||
187 | static inline void ccArraySwapObjectsAtIndexes(ccArray *arr, NSUInteger index1, NSUInteger index2) | ||
188 | { | ||
189 | NSCAssert(index1 < arr->num, @"(1) Invalid index. Out of bounds"); | ||
190 | NSCAssert(index2 < arr->num, @"(2) Invalid index. Out of bounds"); | ||
191 | |||
192 | id object1 = arr->arr[index1]; | ||
193 | |||
194 | arr->arr[index1] = arr->arr[index2]; | ||
195 | arr->arr[index2] = object1; | ||
196 | } | ||
197 | |||
198 | /** Removes all objects from arr */ | ||
199 | static inline void ccArrayRemoveAllObjects(ccArray *arr) | ||
200 | { | ||
201 | while( arr->num > 0 ) | ||
202 | [arr->arr[--arr->num] release]; | ||
203 | } | ||
204 | |||
205 | /** Removes object at specified index and pushes back all subsequent objects. | ||
206 | Behaviour undefined if index outside [0, num-1]. */ | ||
207 | static inline void ccArrayRemoveObjectAtIndex(ccArray *arr, NSUInteger index) | ||
208 | { | ||
209 | [arr->arr[index] release]; | ||
210 | arr->num--; | ||
211 | |||
212 | NSUInteger remaining = arr->num - index; | ||
213 | if(remaining>0) | ||
214 | memmove(&arr->arr[index], &arr->arr[index+1], remaining * sizeof(id)); | ||
215 | } | ||
216 | |||
217 | /** Removes object at specified index and fills the gap with the last object, | ||
218 | thereby avoiding the need to push back subsequent objects. | ||
219 | Behaviour undefined if index outside [0, num-1]. */ | ||
220 | static inline void ccArrayFastRemoveObjectAtIndex(ccArray *arr, NSUInteger index) | ||
221 | { | ||
222 | [arr->arr[index] release]; | ||
223 | NSUInteger last = --arr->num; | ||
224 | arr->arr[index] = arr->arr[last]; | ||
225 | } | ||
226 | |||
227 | static inline void ccArrayFastRemoveObject(ccArray *arr, id object) | ||
228 | { | ||
229 | NSUInteger index = ccArrayGetIndexOfObject(arr, object); | ||
230 | if (index != NSNotFound) | ||
231 | ccArrayFastRemoveObjectAtIndex(arr, index); | ||
232 | } | ||
233 | |||
234 | /** Searches for the first occurance of object and removes it. If object is not | ||
235 | found the function has no effect. */ | ||
236 | static inline void ccArrayRemoveObject(ccArray *arr, id object) | ||
237 | { | ||
238 | NSUInteger index = ccArrayGetIndexOfObject(arr, object); | ||
239 | if (index != NSNotFound) | ||
240 | ccArrayRemoveObjectAtIndex(arr, index); | ||
241 | } | ||
242 | |||
243 | /** Removes from arr all objects in minusArr. For each object in minusArr, the | ||
244 | first matching instance in arr will be removed. */ | ||
245 | static inline void ccArrayRemoveArray(ccArray *arr, ccArray *minusArr) | ||
246 | { | ||
247 | for( NSUInteger i = 0; i < minusArr->num; i++) | ||
248 | ccArrayRemoveObject(arr, minusArr->arr[i]); | ||
249 | } | ||
250 | |||
251 | /** Removes from arr all objects in minusArr. For each object in minusArr, all | ||
252 | matching instances in arr will be removed. */ | ||
253 | static inline void ccArrayFullRemoveArray(ccArray *arr, ccArray *minusArr) | ||
254 | { | ||
255 | NSUInteger back = 0; | ||
256 | |||
257 | for( NSUInteger i = 0; i < arr->num; i++) { | ||
258 | if( ccArrayContainsObject(minusArr, arr->arr[i]) ) { | ||
259 | [arr->arr[i] release]; | ||
260 | back++; | ||
261 | } else | ||
262 | arr->arr[i - back] = arr->arr[i]; | ||
263 | } | ||
264 | |||
265 | arr->num -= back; | ||
266 | } | ||
267 | |||
268 | /** Sends to each object in arr the message identified by given selector. */ | ||
269 | static inline void ccArrayMakeObjectsPerformSelector(ccArray *arr, SEL sel) | ||
270 | { | ||
271 | for( NSUInteger i = 0; i < arr->num; i++) | ||
272 | [arr->arr[i] performSelector:sel]; | ||
273 | } | ||
274 | |||
275 | static inline void ccArrayMakeObjectsPerformSelectorWithObject(ccArray *arr, SEL sel, id object) | ||
276 | { | ||
277 | for( NSUInteger i = 0; i < arr->num; i++) | ||
278 | [arr->arr[i] performSelector:sel withObject:object]; | ||
279 | } | ||
280 | |||
281 | |||
282 | #pragma mark - | ||
283 | #pragma mark ccCArray for Values (c structures) | ||
284 | |||
285 | typedef ccArray ccCArray; | ||
286 | |||
287 | static inline void ccCArrayRemoveAllValues(ccCArray *arr); | ||
288 | |||
289 | /** Allocates and initializes a new C array with specified capacity */ | ||
290 | static inline ccCArray* ccCArrayNew(NSUInteger capacity) { | ||
291 | if (capacity == 0) | ||
292 | capacity = 1; | ||
293 | |||
294 | ccCArray *arr = (ccCArray*)malloc( sizeof(ccCArray) ); | ||
295 | arr->num = 0; | ||
296 | arr->arr = (id*) malloc( capacity * sizeof(id) ); | ||
297 | arr->max = capacity; | ||
298 | |||
299 | return arr; | ||
300 | } | ||
301 | |||
302 | /** Frees C array after removing all remaining values. Silently ignores nil arr. */ | ||
303 | static inline void ccCArrayFree(ccCArray *arr) | ||
304 | { | ||
305 | if( arr == nil ) return; | ||
306 | |||
307 | ccCArrayRemoveAllValues(arr); | ||
308 | |||
309 | free(arr->arr); | ||
310 | free(arr); | ||
311 | } | ||
312 | |||
313 | /** Doubles C array capacity */ | ||
314 | static inline void ccCArrayDoubleCapacity(ccCArray *arr) | ||
315 | { | ||
316 | ccArrayDoubleCapacity(arr); | ||
317 | } | ||
318 | |||
319 | /** Increases array capacity such that max >= num + extra. */ | ||
320 | static inline void ccCArrayEnsureExtraCapacity(ccCArray *arr, NSUInteger extra) | ||
321 | { | ||
322 | ccArrayEnsureExtraCapacity(arr,extra); | ||
323 | } | ||
324 | |||
325 | /** Returns index of first occurence of value, NSNotFound if value not found. */ | ||
326 | static inline NSUInteger ccCArrayGetIndexOfValue(ccCArray *arr, void* value) | ||
327 | { | ||
328 | for( NSUInteger i = 0; i < arr->num; i++) | ||
329 | if( arr->arr[i] == value ) return i; | ||
330 | return NSNotFound; | ||
331 | } | ||
332 | |||
333 | /** Returns a Boolean value that indicates whether value is present in the C array. */ | ||
334 | static inline BOOL ccCArrayContainsValue(ccCArray *arr, void* value) | ||
335 | { | ||
336 | return ccCArrayGetIndexOfValue(arr, value) != NSNotFound; | ||
337 | } | ||
338 | |||
339 | /** Inserts a value at a certain position. Behaviour undefined if aray doesn't have enough capacity */ | ||
340 | static inline void ccCArrayInsertValueAtIndex( ccCArray *arr, void *value, NSUInteger index) | ||
341 | { | ||
342 | NSCAssert( index < arr->max, @"ccCArrayInsertValueAtIndex: invalid index"); | ||
343 | |||
344 | NSUInteger remaining = arr->num - index; | ||
345 | |||
346 | // last Value doesn't need to be moved | ||
347 | if( remaining > 0) { | ||
348 | // tex coordinates | ||
349 | memmove( &arr->arr[index+1],&arr->arr[index], sizeof(void*) * remaining ); | ||
350 | } | ||
351 | |||
352 | arr->num++; | ||
353 | arr->arr[index] = (id) value; | ||
354 | } | ||
355 | |||
356 | /** Appends an value. Bahaviour undefined if array doesn't have enough capacity. */ | ||
357 | static inline void ccCArrayAppendValue(ccCArray *arr, void* value) | ||
358 | { | ||
359 | arr->arr[arr->num] = (id) value; | ||
360 | arr->num++; | ||
361 | } | ||
362 | |||
363 | /** Appends an value. Capacity of arr is increased if needed. */ | ||
364 | static inline void ccCArrayAppendValueWithResize(ccCArray *arr, void* value) | ||
365 | { | ||
366 | ccCArrayEnsureExtraCapacity(arr, 1); | ||
367 | ccCArrayAppendValue(arr, value); | ||
368 | } | ||
369 | |||
370 | /** Appends values from plusArr to arr. Behaviour undefined if arr doesn't have | ||
371 | enough capacity. */ | ||
372 | static inline void ccCArrayAppendArray(ccCArray *arr, ccCArray *plusArr) | ||
373 | { | ||
374 | for( NSUInteger i = 0; i < plusArr->num; i++) | ||
375 | ccCArrayAppendValue(arr, plusArr->arr[i]); | ||
376 | } | ||
377 | |||
378 | /** Appends values from plusArr to arr. Capacity of arr is increased if needed. */ | ||
379 | static inline void ccCArrayAppendArrayWithResize(ccCArray *arr, ccCArray *plusArr) | ||
380 | { | ||
381 | ccCArrayEnsureExtraCapacity(arr, plusArr->num); | ||
382 | ccCArrayAppendArray(arr, plusArr); | ||
383 | } | ||
384 | |||
385 | /** Removes all values from arr */ | ||
386 | static inline void ccCArrayRemoveAllValues(ccCArray *arr) | ||
387 | { | ||
388 | arr->num = 0; | ||
389 | } | ||
390 | |||
391 | /** Removes value at specified index and pushes back all subsequent values. | ||
392 | Behaviour undefined if index outside [0, num-1]. | ||
393 | @since v0.99.4 | ||
394 | */ | ||
395 | static inline void ccCArrayRemoveValueAtIndex(ccCArray *arr, NSUInteger index) | ||
396 | { | ||
397 | for( NSUInteger last = --arr->num; index < last; index++) | ||
398 | arr->arr[index] = arr->arr[index + 1]; | ||
399 | } | ||
400 | |||
401 | /** Removes value at specified index and fills the gap with the last value, | ||
402 | thereby avoiding the need to push back subsequent values. | ||
403 | Behaviour undefined if index outside [0, num-1]. | ||
404 | @since v0.99.4 | ||
405 | */ | ||
406 | static inline void ccCArrayFastRemoveValueAtIndex(ccCArray *arr, NSUInteger index) | ||
407 | { | ||
408 | NSUInteger last = --arr->num; | ||
409 | arr->arr[index] = arr->arr[last]; | ||
410 | } | ||
411 | |||
412 | /** Searches for the first occurance of value and removes it. If value is not found the function has no effect. | ||
413 | @since v0.99.4 | ||
414 | */ | ||
415 | static inline void ccCArrayRemoveValue(ccCArray *arr, void* value) | ||
416 | { | ||
417 | NSUInteger index = ccCArrayGetIndexOfValue(arr, value); | ||
418 | if (index != NSNotFound) | ||
419 | ccCArrayRemoveValueAtIndex(arr, index); | ||
420 | } | ||
421 | |||
422 | /** Removes from arr all values in minusArr. For each Value in minusArr, the first matching instance in arr will be removed. | ||
423 | @since v0.99.4 | ||
424 | */ | ||
425 | static inline void ccCArrayRemoveArray(ccCArray *arr, ccCArray *minusArr) | ||
426 | { | ||
427 | for( NSUInteger i = 0; i < minusArr->num; i++) | ||
428 | ccCArrayRemoveValue(arr, minusArr->arr[i]); | ||
429 | } | ||
430 | |||
431 | /** Removes from arr all values in minusArr. For each value in minusArr, all matching instances in arr will be removed. | ||
432 | @since v0.99.4 | ||
433 | */ | ||
434 | static inline void ccCArrayFullRemoveArray(ccCArray *arr, ccCArray *minusArr) | ||
435 | { | ||
436 | NSUInteger back = 0; | ||
437 | |||
438 | for( NSUInteger i = 0; i < arr->num; i++) { | ||
439 | if( ccCArrayContainsValue(minusArr, arr->arr[i]) ) { | ||
440 | back++; | ||
441 | } else | ||
442 | arr->arr[i - back] = arr->arr[i]; | ||
443 | } | ||
444 | |||
445 | arr->num -= back; | ||
446 | } | ||
447 | #endif // CC_ARRAY_H | ||
diff --git a/libs/cocos2d/Support/ccUtils.c b/libs/cocos2d/Support/ccUtils.c new file mode 100755 index 0000000..39786ec --- /dev/null +++ b/libs/cocos2d/Support/ccUtils.c | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | ccNextPOT function is licensed under the same license that is used in CCTexture2D.m. | ||
8 | */ | ||
9 | #include "ccUtils.h" | ||
10 | |||
11 | unsigned long ccNextPOT(unsigned long x) | ||
12 | { | ||
13 | x = x - 1; | ||
14 | x = x | (x >> 1); | ||
15 | x = x | (x >> 2); | ||
16 | x = x | (x >> 4); | ||
17 | x = x | (x >> 8); | ||
18 | x = x | (x >>16); | ||
19 | return x + 1; | ||
20 | } \ No newline at end of file | ||
diff --git a/libs/cocos2d/Support/ccUtils.h b/libs/cocos2d/Support/ccUtils.h new file mode 100755 index 0000000..783fc54 --- /dev/null +++ b/libs/cocos2d/Support/ccUtils.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | */ | ||
5 | |||
6 | #ifndef __CC_UTILS_H | ||
7 | #define __CC_UTILS_H | ||
8 | |||
9 | /** @file ccUtils.h | ||
10 | Misc free functions | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | ccNextPOT function is licensed under the same license that is used in CCTexture2D.m. | ||
15 | */ | ||
16 | |||
17 | /** returns the Next Power of Two value. | ||
18 | |||
19 | Examples: | ||
20 | - If "value" is 15, it will return 16. | ||
21 | - If "value" is 16, it will return 16. | ||
22 | - If "value" is 17, it will return 32. | ||
23 | |||
24 | @since v0.99.5 | ||
25 | */ | ||
26 | |||
27 | unsigned long ccNextPOT( unsigned long value ); | ||
28 | |||
29 | #endif // ! __CC_UTILS_H | ||
diff --git a/libs/cocos2d/Support/uthash.h b/libs/cocos2d/Support/uthash.h new file mode 100755 index 0000000..a4bdc18 --- /dev/null +++ b/libs/cocos2d/Support/uthash.h | |||
@@ -0,0 +1,972 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net | ||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | * Redistributions of source code must retain the above copyright | ||
9 | notice, this list of conditions and the following disclaimer. | ||
10 | |||
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | */ | ||
23 | |||
24 | #ifndef UTHASH_H | ||
25 | #define UTHASH_H | ||
26 | |||
27 | #include <string.h> /* memcmp,strlen */ | ||
28 | #include <stddef.h> /* ptrdiff_t */ | ||
29 | |||
30 | /* These macros use decltype or the earlier __typeof GNU extension. | ||
31 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ | ||
32 | when compiling c++ source) this code uses whatever method is needed | ||
33 | or, for VS2008 where neither is available, uses casting workarounds. */ | ||
34 | #ifdef _MSC_VER /* MS compiler */ | ||
35 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ | ||
36 | #define DECLTYPE(x) (decltype(x)) | ||
37 | #else /* VS2008 or older (or VS2010 in C mode) */ | ||
38 | #define NO_DECLTYPE | ||
39 | #define DECLTYPE(x) | ||
40 | #endif | ||
41 | #else /* GNU, Sun and other compilers */ | ||
42 | #define DECLTYPE(x) (__typeof(x)) | ||
43 | #endif | ||
44 | |||
45 | #ifdef NO_DECLTYPE | ||
46 | #define DECLTYPE_ASSIGN(dst,src) \ | ||
47 | do { \ | ||
48 | char **_da_dst = (char**)(&(dst)); \ | ||
49 | *_da_dst = (char*)(src); \ | ||
50 | } while(0) | ||
51 | #else | ||
52 | #define DECLTYPE_ASSIGN(dst,src) \ | ||
53 | do { \ | ||
54 | (dst) = DECLTYPE(dst)(src); \ | ||
55 | } while(0) | ||
56 | #endif | ||
57 | |||
58 | /* a number of the hash function use uint32_t which isn't defined on win32 */ | ||
59 | #ifdef _MSC_VER | ||
60 | typedef unsigned int uint32_t; | ||
61 | #else | ||
62 | #include <inttypes.h> /* uint32_t */ | ||
63 | #endif | ||
64 | |||
65 | #define UTHASH_VERSION 1.9.3 | ||
66 | |||
67 | #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ | ||
68 | #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ | ||
69 | #define uthash_free(ptr,sz) free(ptr) /* free fcn */ | ||
70 | |||
71 | #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ | ||
72 | #define uthash_expand_fyi(tbl) /* can be defined to log expands */ | ||
73 | |||
74 | /* initial number of buckets */ | ||
75 | #define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ | ||
76 | #define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ | ||
77 | #define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ | ||
78 | |||
79 | /* calculate the element whose hash handle address is hhe */ | ||
80 | #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) | ||
81 | |||
82 | #define HASH_FIND(hh,head,keyptr,keylen,out) \ | ||
83 | do { \ | ||
84 | unsigned _hf_bkt,_hf_hashv; \ | ||
85 | out=NULL; \ | ||
86 | if (head) { \ | ||
87 | HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ | ||
88 | if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ | ||
89 | HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ | ||
90 | keyptr,keylen,out); \ | ||
91 | } \ | ||
92 | } \ | ||
93 | } while (0) | ||
94 | |||
95 | #ifdef HASH_BLOOM | ||
96 | #define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) | ||
97 | #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) | ||
98 | #define HASH_BLOOM_MAKE(tbl) \ | ||
99 | do { \ | ||
100 | (tbl)->bloom_nbits = HASH_BLOOM; \ | ||
101 | (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ | ||
102 | if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ | ||
103 | memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ | ||
104 | (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ | ||
105 | } while (0); | ||
106 | |||
107 | #define HASH_BLOOM_FREE(tbl) \ | ||
108 | do { \ | ||
109 | uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ | ||
110 | } while (0); | ||
111 | |||
112 | #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) | ||
113 | #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) | ||
114 | |||
115 | #define HASH_BLOOM_ADD(tbl,hashv) \ | ||
116 | HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) | ||
117 | |||
118 | #define HASH_BLOOM_TEST(tbl,hashv) \ | ||
119 | HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) | ||
120 | |||
121 | #else | ||
122 | #define HASH_BLOOM_MAKE(tbl) | ||
123 | #define HASH_BLOOM_FREE(tbl) | ||
124 | #define HASH_BLOOM_ADD(tbl,hashv) | ||
125 | #define HASH_BLOOM_TEST(tbl,hashv) (1) | ||
126 | #endif | ||
127 | |||
128 | #define HASH_MAKE_TABLE(hh,head) \ | ||
129 | do { \ | ||
130 | (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ | ||
131 | sizeof(UT_hash_table)); \ | ||
132 | if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ | ||
133 | memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ | ||
134 | (head)->hh.tbl->tail = &((head)->hh); \ | ||
135 | (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ | ||
136 | (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ | ||
137 | (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ | ||
138 | (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ | ||
139 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ | ||
140 | if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ | ||
141 | memset((head)->hh.tbl->buckets, 0, \ | ||
142 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ | ||
143 | HASH_BLOOM_MAKE((head)->hh.tbl); \ | ||
144 | (head)->hh.tbl->signature = HASH_SIGNATURE; \ | ||
145 | } while(0) | ||
146 | |||
147 | #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ | ||
148 | HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) | ||
149 | |||
150 | #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ | ||
151 | do { \ | ||
152 | unsigned _ha_bkt; \ | ||
153 | (add)->hh.next = NULL; \ | ||
154 | (add)->hh.key = (char*)keyptr; \ | ||
155 | (add)->hh.keylen = keylen_in; \ | ||
156 | if (!(head)) { \ | ||
157 | head = (add); \ | ||
158 | (head)->hh.prev = NULL; \ | ||
159 | HASH_MAKE_TABLE(hh,head); \ | ||
160 | } else { \ | ||
161 | (head)->hh.tbl->tail->next = (add); \ | ||
162 | (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ | ||
163 | (head)->hh.tbl->tail = &((add)->hh); \ | ||
164 | } \ | ||
165 | (head)->hh.tbl->num_items++; \ | ||
166 | (add)->hh.tbl = (head)->hh.tbl; \ | ||
167 | HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ | ||
168 | (add)->hh.hashv, _ha_bkt); \ | ||
169 | HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ | ||
170 | HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ | ||
171 | HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ | ||
172 | HASH_FSCK(hh,head); \ | ||
173 | } while(0) | ||
174 | |||
175 | #define HASH_TO_BKT( hashv, num_bkts, bkt ) \ | ||
176 | do { \ | ||
177 | bkt = ((hashv) & ((num_bkts) - 1)); \ | ||
178 | } while(0) | ||
179 | |||
180 | /* delete "delptr" from the hash table. | ||
181 | * "the usual" patch-up process for the app-order doubly-linked-list. | ||
182 | * The use of _hd_hh_del below deserves special explanation. | ||
183 | * These used to be expressed using (delptr) but that led to a bug | ||
184 | * if someone used the same symbol for the head and deletee, like | ||
185 | * HASH_DELETE(hh,users,users); | ||
186 | * We want that to work, but by changing the head (users) below | ||
187 | * we were forfeiting our ability to further refer to the deletee (users) | ||
188 | * in the patch-up process. Solution: use scratch space to | ||
189 | * copy the deletee pointer, then the latter references are via that | ||
190 | * scratch pointer rather than through the repointed (users) symbol. | ||
191 | */ | ||
192 | #define HASH_DELETE(hh,head,delptr) \ | ||
193 | do { \ | ||
194 | unsigned _hd_bkt; \ | ||
195 | struct UT_hash_handle *_hd_hh_del; \ | ||
196 | if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ | ||
197 | uthash_free((head)->hh.tbl->buckets, \ | ||
198 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ | ||
199 | HASH_BLOOM_FREE((head)->hh.tbl); \ | ||
200 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ | ||
201 | head = NULL; \ | ||
202 | } else { \ | ||
203 | _hd_hh_del = &((delptr)->hh); \ | ||
204 | if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ | ||
205 | (head)->hh.tbl->tail = \ | ||
206 | (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ | ||
207 | (head)->hh.tbl->hho); \ | ||
208 | } \ | ||
209 | if ((delptr)->hh.prev) { \ | ||
210 | ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ | ||
211 | (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ | ||
212 | } else { \ | ||
213 | DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ | ||
214 | } \ | ||
215 | if (_hd_hh_del->next) { \ | ||
216 | ((UT_hash_handle*)((char*)_hd_hh_del->next + \ | ||
217 | (head)->hh.tbl->hho))->prev = \ | ||
218 | _hd_hh_del->prev; \ | ||
219 | } \ | ||
220 | HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ | ||
221 | HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ | ||
222 | (head)->hh.tbl->num_items--; \ | ||
223 | } \ | ||
224 | HASH_FSCK(hh,head); \ | ||
225 | } while (0) | ||
226 | |||
227 | |||
228 | /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ | ||
229 | #define HASH_FIND_STR(head,findstr,out) \ | ||
230 | HASH_FIND(hh,head,findstr,strlen(findstr),out) | ||
231 | #define HASH_ADD_STR(head,strfield,add) \ | ||
232 | HASH_ADD(hh,head,strfield,strlen(add->strfield),add) | ||
233 | #define HASH_FIND_INT(head,findint,out) \ | ||
234 | HASH_FIND(hh,head,findint,sizeof(int),out) | ||
235 | #define HASH_ADD_INT(head,intfield,add) \ | ||
236 | HASH_ADD(hh,head,intfield,sizeof(int),add) | ||
237 | #define HASH_FIND_PTR(head,findptr,out) \ | ||
238 | HASH_FIND(hh,head,findptr,sizeof(void *),out) | ||
239 | #define HASH_ADD_PTR(head,ptrfield,add) \ | ||
240 | HASH_ADD(hh,head,ptrfield,sizeof(void *),add) | ||
241 | #define HASH_DEL(head,delptr) \ | ||
242 | HASH_DELETE(hh,head,delptr) | ||
243 | |||
244 | /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. | ||
245 | * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. | ||
246 | */ | ||
247 | #ifdef HASH_DEBUG | ||
248 | #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) | ||
249 | #define HASH_FSCK(hh,head) \ | ||
250 | do { \ | ||
251 | unsigned _bkt_i; \ | ||
252 | unsigned _count, _bkt_count; \ | ||
253 | char *_prev; \ | ||
254 | struct UT_hash_handle *_thh; \ | ||
255 | if (head) { \ | ||
256 | _count = 0; \ | ||
257 | for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ | ||
258 | _bkt_count = 0; \ | ||
259 | _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ | ||
260 | _prev = NULL; \ | ||
261 | while (_thh) { \ | ||
262 | if (_prev != (char*)(_thh->hh_prev)) { \ | ||
263 | HASH_OOPS("invalid hh_prev %p, actual %p\n", \ | ||
264 | _thh->hh_prev, _prev ); \ | ||
265 | } \ | ||
266 | _bkt_count++; \ | ||
267 | _prev = (char*)(_thh); \ | ||
268 | _thh = _thh->hh_next; \ | ||
269 | } \ | ||
270 | _count += _bkt_count; \ | ||
271 | if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ | ||
272 | HASH_OOPS("invalid bucket count %d, actual %d\n", \ | ||
273 | (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ | ||
274 | } \ | ||
275 | } \ | ||
276 | if (_count != (head)->hh.tbl->num_items) { \ | ||
277 | HASH_OOPS("invalid hh item count %d, actual %d\n", \ | ||
278 | (head)->hh.tbl->num_items, _count ); \ | ||
279 | } \ | ||
280 | /* traverse hh in app order; check next/prev integrity, count */ \ | ||
281 | _count = 0; \ | ||
282 | _prev = NULL; \ | ||
283 | _thh = &(head)->hh; \ | ||
284 | while (_thh) { \ | ||
285 | _count++; \ | ||
286 | if (_prev !=(char*)(_thh->prev)) { \ | ||
287 | HASH_OOPS("invalid prev %p, actual %p\n", \ | ||
288 | _thh->prev, _prev ); \ | ||
289 | } \ | ||
290 | _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ | ||
291 | _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ | ||
292 | (head)->hh.tbl->hho) : NULL ); \ | ||
293 | } \ | ||
294 | if (_count != (head)->hh.tbl->num_items) { \ | ||
295 | HASH_OOPS("invalid app item count %d, actual %d\n", \ | ||
296 | (head)->hh.tbl->num_items, _count ); \ | ||
297 | } \ | ||
298 | } \ | ||
299 | } while (0) | ||
300 | #else | ||
301 | #define HASH_FSCK(hh,head) | ||
302 | #endif | ||
303 | |||
304 | /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to | ||
305 | * the descriptor to which this macro is defined for tuning the hash function. | ||
306 | * The app can #include <unistd.h> to get the prototype for write(2). */ | ||
307 | #ifdef HASH_EMIT_KEYS | ||
308 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ | ||
309 | do { \ | ||
310 | unsigned _klen = fieldlen; \ | ||
311 | write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ | ||
312 | write(HASH_EMIT_KEYS, keyptr, fieldlen); \ | ||
313 | } while (0) | ||
314 | #else | ||
315 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) | ||
316 | #endif | ||
317 | |||
318 | /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ | ||
319 | #ifdef HASH_FUNCTION | ||
320 | #define HASH_FCN HASH_FUNCTION | ||
321 | #else | ||
322 | #define HASH_FCN HASH_JEN | ||
323 | #endif | ||
324 | |||
325 | /* The Bernstein hash function, used in Perl prior to v5.6 */ | ||
326 | #define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ | ||
327 | do { \ | ||
328 | unsigned _hb_keylen=keylen; \ | ||
329 | char *_hb_key=(char*)(key); \ | ||
330 | (hashv) = 0; \ | ||
331 | while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ | ||
332 | bkt = (hashv) & (num_bkts-1); \ | ||
333 | } while (0) | ||
334 | |||
335 | |||
336 | /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at | ||
337 | * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ | ||
338 | #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ | ||
339 | do { \ | ||
340 | unsigned _sx_i; \ | ||
341 | char *_hs_key=(char*)(key); \ | ||
342 | hashv = 0; \ | ||
343 | for(_sx_i=0; _sx_i < keylen; _sx_i++) \ | ||
344 | hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ | ||
345 | bkt = hashv & (num_bkts-1); \ | ||
346 | } while (0) | ||
347 | |||
348 | #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ | ||
349 | do { \ | ||
350 | unsigned _fn_i; \ | ||
351 | char *_hf_key=(char*)(key); \ | ||
352 | hashv = 2166136261UL; \ | ||
353 | for(_fn_i=0; _fn_i < keylen; _fn_i++) \ | ||
354 | hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ | ||
355 | bkt = hashv & (num_bkts-1); \ | ||
356 | } while(0); | ||
357 | |||
358 | #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ | ||
359 | do { \ | ||
360 | unsigned _ho_i; \ | ||
361 | char *_ho_key=(char*)(key); \ | ||
362 | hashv = 0; \ | ||
363 | for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ | ||
364 | hashv += _ho_key[_ho_i]; \ | ||
365 | hashv += (hashv << 10); \ | ||
366 | hashv ^= (hashv >> 6); \ | ||
367 | } \ | ||
368 | hashv += (hashv << 3); \ | ||
369 | hashv ^= (hashv >> 11); \ | ||
370 | hashv += (hashv << 15); \ | ||
371 | bkt = hashv & (num_bkts-1); \ | ||
372 | } while(0) | ||
373 | |||
374 | #define HASH_JEN_MIX(a,b,c) \ | ||
375 | do { \ | ||
376 | a -= b; a -= c; a ^= ( c >> 13 ); \ | ||
377 | b -= c; b -= a; b ^= ( a << 8 ); \ | ||
378 | c -= a; c -= b; c ^= ( b >> 13 ); \ | ||
379 | a -= b; a -= c; a ^= ( c >> 12 ); \ | ||
380 | b -= c; b -= a; b ^= ( a << 16 ); \ | ||
381 | c -= a; c -= b; c ^= ( b >> 5 ); \ | ||
382 | a -= b; a -= c; a ^= ( c >> 3 ); \ | ||
383 | b -= c; b -= a; b ^= ( a << 10 ); \ | ||
384 | c -= a; c -= b; c ^= ( b >> 15 ); \ | ||
385 | } while (0) | ||
386 | |||
387 | #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ | ||
388 | do { \ | ||
389 | unsigned _hj_i,_hj_j,_hj_k; \ | ||
390 | char *_hj_key=(char*)(key); \ | ||
391 | hashv = 0xfeedbeef; \ | ||
392 | _hj_i = _hj_j = 0x9e3779b9; \ | ||
393 | _hj_k = keylen; \ | ||
394 | while (_hj_k >= 12) { \ | ||
395 | _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ | ||
396 | + ( (unsigned)_hj_key[2] << 16 ) \ | ||
397 | + ( (unsigned)_hj_key[3] << 24 ) ); \ | ||
398 | _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ | ||
399 | + ( (unsigned)_hj_key[6] << 16 ) \ | ||
400 | + ( (unsigned)_hj_key[7] << 24 ) ); \ | ||
401 | hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ | ||
402 | + ( (unsigned)_hj_key[10] << 16 ) \ | ||
403 | + ( (unsigned)_hj_key[11] << 24 ) ); \ | ||
404 | \ | ||
405 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ | ||
406 | \ | ||
407 | _hj_key += 12; \ | ||
408 | _hj_k -= 12; \ | ||
409 | } \ | ||
410 | hashv += keylen; \ | ||
411 | switch ( _hj_k ) { \ | ||
412 | case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ | ||
413 | case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ | ||
414 | case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ | ||
415 | case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ | ||
416 | case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ | ||
417 | case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ | ||
418 | case 5: _hj_j += _hj_key[4]; \ | ||
419 | case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ | ||
420 | case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ | ||
421 | case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ | ||
422 | case 1: _hj_i += _hj_key[0]; \ | ||
423 | } \ | ||
424 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ | ||
425 | bkt = hashv & (num_bkts-1); \ | ||
426 | } while(0) | ||
427 | |||
428 | /* The Paul Hsieh hash function */ | ||
429 | #undef get16bits | ||
430 | #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ | ||
431 | || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) | ||
432 | #define get16bits(d) (*((const uint16_t *) (d))) | ||
433 | #endif | ||
434 | |||
435 | #if !defined (get16bits) | ||
436 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ | ||
437 | +(uint32_t)(((const uint8_t *)(d))[0]) ) | ||
438 | #endif | ||
439 | #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ | ||
440 | do { \ | ||
441 | char *_sfh_key=(char*)(key); \ | ||
442 | uint32_t _sfh_tmp, _sfh_len = keylen; \ | ||
443 | \ | ||
444 | int _sfh_rem = _sfh_len & 3; \ | ||
445 | _sfh_len >>= 2; \ | ||
446 | hashv = 0xcafebabe; \ | ||
447 | \ | ||
448 | /* Main loop */ \ | ||
449 | for (;_sfh_len > 0; _sfh_len--) { \ | ||
450 | hashv += get16bits (_sfh_key); \ | ||
451 | _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ | ||
452 | hashv = (hashv << 16) ^ _sfh_tmp; \ | ||
453 | _sfh_key += 2*sizeof (uint16_t); \ | ||
454 | hashv += hashv >> 11; \ | ||
455 | } \ | ||
456 | \ | ||
457 | /* Handle end cases */ \ | ||
458 | switch (_sfh_rem) { \ | ||
459 | case 3: hashv += get16bits (_sfh_key); \ | ||
460 | hashv ^= hashv << 16; \ | ||
461 | hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ | ||
462 | hashv += hashv >> 11; \ | ||
463 | break; \ | ||
464 | case 2: hashv += get16bits (_sfh_key); \ | ||
465 | hashv ^= hashv << 11; \ | ||
466 | hashv += hashv >> 17; \ | ||
467 | break; \ | ||
468 | case 1: hashv += *_sfh_key; \ | ||
469 | hashv ^= hashv << 10; \ | ||
470 | hashv += hashv >> 1; \ | ||
471 | } \ | ||
472 | \ | ||
473 | /* Force "avalanching" of final 127 bits */ \ | ||
474 | hashv ^= hashv << 3; \ | ||
475 | hashv += hashv >> 5; \ | ||
476 | hashv ^= hashv << 4; \ | ||
477 | hashv += hashv >> 17; \ | ||
478 | hashv ^= hashv << 25; \ | ||
479 | hashv += hashv >> 6; \ | ||
480 | bkt = hashv & (num_bkts-1); \ | ||
481 | } while(0); | ||
482 | |||
483 | #ifdef HASH_USING_NO_STRICT_ALIASING | ||
484 | /* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads. | ||
485 | * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. | ||
486 | * So MurmurHash comes in two versions, the faster unaligned one and the slower | ||
487 | * aligned one. We only use the faster one on CPU's where we know it's safe. | ||
488 | * | ||
489 | * Note the preprocessor built-in defines can be emitted using: | ||
490 | * | ||
491 | * gcc -m64 -dM -E - < /dev/null (on gcc) | ||
492 | * cc -## a.c (where a.c is a simple test file) (Sun Studio) | ||
493 | */ | ||
494 | #if (defined(__i386__) || defined(__x86_64__)) | ||
495 | #define HASH_MUR HASH_MUR_UNALIGNED | ||
496 | #else | ||
497 | #define HASH_MUR HASH_MUR_ALIGNED | ||
498 | #endif | ||
499 | |||
500 | /* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */ | ||
501 | #define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \ | ||
502 | do { \ | ||
503 | const unsigned int _mur_m = 0x5bd1e995; \ | ||
504 | const int _mur_r = 24; \ | ||
505 | hashv = 0xcafebabe ^ keylen; \ | ||
506 | char *_mur_key = (char *)(key); \ | ||
507 | uint32_t _mur_tmp, _mur_len = keylen; \ | ||
508 | \ | ||
509 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
510 | _mur_tmp = *(uint32_t *)_mur_key; \ | ||
511 | _mur_tmp *= _mur_m; \ | ||
512 | _mur_tmp ^= _mur_tmp >> _mur_r; \ | ||
513 | _mur_tmp *= _mur_m; \ | ||
514 | hashv *= _mur_m; \ | ||
515 | hashv ^= _mur_tmp; \ | ||
516 | _mur_key += 4; \ | ||
517 | } \ | ||
518 | \ | ||
519 | switch(_mur_len) \ | ||
520 | { \ | ||
521 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
522 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
523 | case 1: hashv ^= _mur_key[0]; \ | ||
524 | hashv *= _mur_m; \ | ||
525 | }; \ | ||
526 | \ | ||
527 | hashv ^= hashv >> 13; \ | ||
528 | hashv *= _mur_m; \ | ||
529 | hashv ^= hashv >> 15; \ | ||
530 | \ | ||
531 | bkt = hashv & (num_bkts-1); \ | ||
532 | } while(0) | ||
533 | |||
534 | /* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */ | ||
535 | #define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \ | ||
536 | do { \ | ||
537 | const unsigned int _mur_m = 0x5bd1e995; \ | ||
538 | const int _mur_r = 24; \ | ||
539 | hashv = 0xcafebabe ^ (keylen); \ | ||
540 | char *_mur_key = (char *)(key); \ | ||
541 | uint32_t _mur_len = keylen; \ | ||
542 | int _mur_align = (int)_mur_key & 3; \ | ||
543 | \ | ||
544 | if (_mur_align && (_mur_len >= 4)) { \ | ||
545 | unsigned _mur_t = 0, _mur_d = 0; \ | ||
546 | switch(_mur_align) { \ | ||
547 | case 1: _mur_t |= _mur_key[2] << 16; \ | ||
548 | case 2: _mur_t |= _mur_key[1] << 8; \ | ||
549 | case 3: _mur_t |= _mur_key[0]; \ | ||
550 | } \ | ||
551 | _mur_t <<= (8 * _mur_align); \ | ||
552 | _mur_key += 4-_mur_align; \ | ||
553 | _mur_len -= 4-_mur_align; \ | ||
554 | int _mur_sl = 8 * (4-_mur_align); \ | ||
555 | int _mur_sr = 8 * _mur_align; \ | ||
556 | \ | ||
557 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
558 | _mur_d = *(unsigned *)_mur_key; \ | ||
559 | _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
560 | unsigned _mur_k = _mur_t; \ | ||
561 | _mur_k *= _mur_m; \ | ||
562 | _mur_k ^= _mur_k >> _mur_r; \ | ||
563 | _mur_k *= _mur_m; \ | ||
564 | hashv *= _mur_m; \ | ||
565 | hashv ^= _mur_k; \ | ||
566 | _mur_t = _mur_d; \ | ||
567 | _mur_key += 4; \ | ||
568 | } \ | ||
569 | _mur_d = 0; \ | ||
570 | if(_mur_len >= _mur_align) { \ | ||
571 | switch(_mur_align) { \ | ||
572 | case 3: _mur_d |= _mur_key[2] << 16; \ | ||
573 | case 2: _mur_d |= _mur_key[1] << 8; \ | ||
574 | case 1: _mur_d |= _mur_key[0]; \ | ||
575 | } \ | ||
576 | unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
577 | _mur_k *= _mur_m; \ | ||
578 | _mur_k ^= _mur_k >> _mur_r; \ | ||
579 | _mur_k *= _mur_m; \ | ||
580 | hashv *= _mur_m; \ | ||
581 | hashv ^= _mur_k; \ | ||
582 | _mur_k += _mur_align; \ | ||
583 | _mur_len -= _mur_align; \ | ||
584 | \ | ||
585 | switch(_mur_len) \ | ||
586 | { \ | ||
587 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
588 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
589 | case 1: hashv ^= _mur_key[0]; \ | ||
590 | hashv *= _mur_m; \ | ||
591 | } \ | ||
592 | } else { \ | ||
593 | switch(_mur_len) \ | ||
594 | { \ | ||
595 | case 3: _mur_d ^= _mur_key[2] << 16; \ | ||
596 | case 2: _mur_d ^= _mur_key[1] << 8; \ | ||
597 | case 1: _mur_d ^= _mur_key[0]; \ | ||
598 | case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
599 | hashv *= _mur_m; \ | ||
600 | } \ | ||
601 | } \ | ||
602 | \ | ||
603 | hashv ^= hashv >> 13; \ | ||
604 | hashv *= _mur_m; \ | ||
605 | hashv ^= hashv >> 15; \ | ||
606 | } else { \ | ||
607 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
608 | unsigned _mur_k = *(unsigned*)_mur_key; \ | ||
609 | _mur_k *= _mur_m; \ | ||
610 | _mur_k ^= _mur_k >> _mur_r; \ | ||
611 | _mur_k *= _mur_m; \ | ||
612 | hashv *= _mur_m; \ | ||
613 | hashv ^= _mur_k; \ | ||
614 | _mur_key += 4; \ | ||
615 | } \ | ||
616 | switch(_mur_len) \ | ||
617 | { \ | ||
618 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
619 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
620 | case 1: hashv ^= _mur_key[0]; \ | ||
621 | hashv *= _mur_m; \ | ||
622 | } \ | ||
623 | \ | ||
624 | hashv ^= hashv >> 13; \ | ||
625 | hashv *= _mur_m; \ | ||
626 | hashv ^= hashv >> 15; \ | ||
627 | } \ | ||
628 | bkt = hashv & (num_bkts-1); \ | ||
629 | } while(0) | ||
630 | #endif /* HASH_USING_NO_STRICT_ALIASING */ | ||
631 | |||
632 | /* key comparison function; return 0 if keys equal */ | ||
633 | #define HASH_KEYCMP(a,b,len) memcmp(a,b,len) | ||
634 | |||
635 | /* iterate over items in a known bucket to find desired item */ | ||
636 | #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ | ||
637 | do { \ | ||
638 | if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ | ||
639 | else out=NULL; \ | ||
640 | while (out) { \ | ||
641 | if (out->hh.keylen == keylen_in) { \ | ||
642 | if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ | ||
643 | } \ | ||
644 | if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ | ||
645 | else out = NULL; \ | ||
646 | } \ | ||
647 | } while(0) | ||
648 | |||
649 | /* add an item to a bucket */ | ||
650 | #define HASH_ADD_TO_BKT(head,addhh) \ | ||
651 | do { \ | ||
652 | head.count++; \ | ||
653 | (addhh)->hh_next = head.hh_head; \ | ||
654 | (addhh)->hh_prev = NULL; \ | ||
655 | if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ | ||
656 | (head).hh_head=addhh; \ | ||
657 | if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ | ||
658 | && (addhh)->tbl->noexpand != 1) { \ | ||
659 | HASH_EXPAND_BUCKETS((addhh)->tbl); \ | ||
660 | } \ | ||
661 | } while(0) | ||
662 | |||
663 | /* remove an item from a given bucket */ | ||
664 | #define HASH_DEL_IN_BKT(hh,head,hh_del) \ | ||
665 | (head).count--; \ | ||
666 | if ((head).hh_head == hh_del) { \ | ||
667 | (head).hh_head = hh_del->hh_next; \ | ||
668 | } \ | ||
669 | if (hh_del->hh_prev) { \ | ||
670 | hh_del->hh_prev->hh_next = hh_del->hh_next; \ | ||
671 | } \ | ||
672 | if (hh_del->hh_next) { \ | ||
673 | hh_del->hh_next->hh_prev = hh_del->hh_prev; \ | ||
674 | } | ||
675 | |||
676 | /* Bucket expansion has the effect of doubling the number of buckets | ||
677 | * and redistributing the items into the new buckets. Ideally the | ||
678 | * items will distribute more or less evenly into the new buckets | ||
679 | * (the extent to which this is true is a measure of the quality of | ||
680 | * the hash function as it applies to the key domain). | ||
681 | * | ||
682 | * With the items distributed into more buckets, the chain length | ||
683 | * (item count) in each bucket is reduced. Thus by expanding buckets | ||
684 | * the hash keeps a bound on the chain length. This bounded chain | ||
685 | * length is the essence of how a hash provides constant time lookup. | ||
686 | * | ||
687 | * The calculation of tbl->ideal_chain_maxlen below deserves some | ||
688 | * explanation. First, keep in mind that we're calculating the ideal | ||
689 | * maximum chain length based on the *new* (doubled) bucket count. | ||
690 | * In fractions this is just n/b (n=number of items,b=new num buckets). | ||
691 | * Since the ideal chain length is an integer, we want to calculate | ||
692 | * ceil(n/b). We don't depend on floating point arithmetic in this | ||
693 | * hash, so to calculate ceil(n/b) with integers we could write | ||
694 | * | ||
695 | * ceil(n/b) = (n/b) + ((n%b)?1:0) | ||
696 | * | ||
697 | * and in fact a previous version of this hash did just that. | ||
698 | * But now we have improved things a bit by recognizing that b is | ||
699 | * always a power of two. We keep its base 2 log handy (call it lb), | ||
700 | * so now we can write this with a bit shift and logical AND: | ||
701 | * | ||
702 | * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) | ||
703 | * | ||
704 | */ | ||
705 | #define HASH_EXPAND_BUCKETS(tbl) \ | ||
706 | do { \ | ||
707 | unsigned _he_bkt; \ | ||
708 | unsigned _he_bkt_i; \ | ||
709 | struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ | ||
710 | UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ | ||
711 | _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ | ||
712 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ | ||
713 | if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ | ||
714 | memset(_he_new_buckets, 0, \ | ||
715 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ | ||
716 | tbl->ideal_chain_maxlen = \ | ||
717 | (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ | ||
718 | ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ | ||
719 | tbl->nonideal_items = 0; \ | ||
720 | for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ | ||
721 | { \ | ||
722 | _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ | ||
723 | while (_he_thh) { \ | ||
724 | _he_hh_nxt = _he_thh->hh_next; \ | ||
725 | HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ | ||
726 | _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ | ||
727 | if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ | ||
728 | tbl->nonideal_items++; \ | ||
729 | _he_newbkt->expand_mult = _he_newbkt->count / \ | ||
730 | tbl->ideal_chain_maxlen; \ | ||
731 | } \ | ||
732 | _he_thh->hh_prev = NULL; \ | ||
733 | _he_thh->hh_next = _he_newbkt->hh_head; \ | ||
734 | if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ | ||
735 | _he_thh; \ | ||
736 | _he_newbkt->hh_head = _he_thh; \ | ||
737 | _he_thh = _he_hh_nxt; \ | ||
738 | } \ | ||
739 | } \ | ||
740 | uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ | ||
741 | tbl->num_buckets *= 2; \ | ||
742 | tbl->log2_num_buckets++; \ | ||
743 | tbl->buckets = _he_new_buckets; \ | ||
744 | tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ | ||
745 | (tbl->ineff_expands+1) : 0; \ | ||
746 | if (tbl->ineff_expands > 1) { \ | ||
747 | tbl->noexpand=1; \ | ||
748 | uthash_noexpand_fyi(tbl); \ | ||
749 | } \ | ||
750 | uthash_expand_fyi(tbl); \ | ||
751 | } while(0) | ||
752 | |||
753 | |||
754 | /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ | ||
755 | /* Note that HASH_SORT assumes the hash handle name to be hh. | ||
756 | * HASH_SRT was added to allow the hash handle name to be passed in. */ | ||
757 | #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) | ||
758 | #define HASH_SRT(hh,head,cmpfcn) \ | ||
759 | do { \ | ||
760 | unsigned _hs_i; \ | ||
761 | unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ | ||
762 | struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ | ||
763 | if (head) { \ | ||
764 | _hs_insize = 1; \ | ||
765 | _hs_looping = 1; \ | ||
766 | _hs_list = &((head)->hh); \ | ||
767 | while (_hs_looping) { \ | ||
768 | _hs_p = _hs_list; \ | ||
769 | _hs_list = NULL; \ | ||
770 | _hs_tail = NULL; \ | ||
771 | _hs_nmerges = 0; \ | ||
772 | while (_hs_p) { \ | ||
773 | _hs_nmerges++; \ | ||
774 | _hs_q = _hs_p; \ | ||
775 | _hs_psize = 0; \ | ||
776 | for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ | ||
777 | _hs_psize++; \ | ||
778 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
779 | ((void*)((char*)(_hs_q->next) + \ | ||
780 | (head)->hh.tbl->hho)) : NULL); \ | ||
781 | if (! (_hs_q) ) break; \ | ||
782 | } \ | ||
783 | _hs_qsize = _hs_insize; \ | ||
784 | while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ | ||
785 | if (_hs_psize == 0) { \ | ||
786 | _hs_e = _hs_q; \ | ||
787 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
788 | ((void*)((char*)(_hs_q->next) + \ | ||
789 | (head)->hh.tbl->hho)) : NULL); \ | ||
790 | _hs_qsize--; \ | ||
791 | } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ | ||
792 | _hs_e = _hs_p; \ | ||
793 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ | ||
794 | ((void*)((char*)(_hs_p->next) + \ | ||
795 | (head)->hh.tbl->hho)) : NULL); \ | ||
796 | _hs_psize--; \ | ||
797 | } else if (( \ | ||
798 | cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ | ||
799 | DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ | ||
800 | ) <= 0) { \ | ||
801 | _hs_e = _hs_p; \ | ||
802 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ | ||
803 | ((void*)((char*)(_hs_p->next) + \ | ||
804 | (head)->hh.tbl->hho)) : NULL); \ | ||
805 | _hs_psize--; \ | ||
806 | } else { \ | ||
807 | _hs_e = _hs_q; \ | ||
808 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
809 | ((void*)((char*)(_hs_q->next) + \ | ||
810 | (head)->hh.tbl->hho)) : NULL); \ | ||
811 | _hs_qsize--; \ | ||
812 | } \ | ||
813 | if ( _hs_tail ) { \ | ||
814 | _hs_tail->next = ((_hs_e) ? \ | ||
815 | ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ | ||
816 | } else { \ | ||
817 | _hs_list = _hs_e; \ | ||
818 | } \ | ||
819 | _hs_e->prev = ((_hs_tail) ? \ | ||
820 | ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ | ||
821 | _hs_tail = _hs_e; \ | ||
822 | } \ | ||
823 | _hs_p = _hs_q; \ | ||
824 | } \ | ||
825 | _hs_tail->next = NULL; \ | ||
826 | if ( _hs_nmerges <= 1 ) { \ | ||
827 | _hs_looping=0; \ | ||
828 | (head)->hh.tbl->tail = _hs_tail; \ | ||
829 | DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ | ||
830 | } \ | ||
831 | _hs_insize *= 2; \ | ||
832 | } \ | ||
833 | HASH_FSCK(hh,head); \ | ||
834 | } \ | ||
835 | } while (0) | ||
836 | |||
837 | /* This function selects items from one hash into another hash. | ||
838 | * The end result is that the selected items have dual presence | ||
839 | * in both hashes. There is no copy of the items made; rather | ||
840 | * they are added into the new hash through a secondary hash | ||
841 | * hash handle that must be present in the structure. */ | ||
842 | #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ | ||
843 | do { \ | ||
844 | unsigned _src_bkt, _dst_bkt; \ | ||
845 | void *_last_elt=NULL, *_elt; \ | ||
846 | UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ | ||
847 | ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ | ||
848 | if (src) { \ | ||
849 | for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ | ||
850 | for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ | ||
851 | _src_hh; \ | ||
852 | _src_hh = _src_hh->hh_next) { \ | ||
853 | _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ | ||
854 | if (cond(_elt)) { \ | ||
855 | _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ | ||
856 | _dst_hh->key = _src_hh->key; \ | ||
857 | _dst_hh->keylen = _src_hh->keylen; \ | ||
858 | _dst_hh->hashv = _src_hh->hashv; \ | ||
859 | _dst_hh->prev = _last_elt; \ | ||
860 | _dst_hh->next = NULL; \ | ||
861 | if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ | ||
862 | if (!dst) { \ | ||
863 | DECLTYPE_ASSIGN(dst,_elt); \ | ||
864 | HASH_MAKE_TABLE(hh_dst,dst); \ | ||
865 | } else { \ | ||
866 | _dst_hh->tbl = (dst)->hh_dst.tbl; \ | ||
867 | } \ | ||
868 | HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ | ||
869 | HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ | ||
870 | (dst)->hh_dst.tbl->num_items++; \ | ||
871 | _last_elt = _elt; \ | ||
872 | _last_elt_hh = _dst_hh; \ | ||
873 | } \ | ||
874 | } \ | ||
875 | } \ | ||
876 | } \ | ||
877 | HASH_FSCK(hh_dst,dst); \ | ||
878 | } while (0) | ||
879 | |||
880 | #define HASH_CLEAR(hh,head) \ | ||
881 | do { \ | ||
882 | if (head) { \ | ||
883 | uthash_free((head)->hh.tbl->buckets, \ | ||
884 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ | ||
885 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ | ||
886 | (head)=NULL; \ | ||
887 | } \ | ||
888 | } while(0) | ||
889 | |||
890 | #ifdef NO_DECLTYPE | ||
891 | #define HASH_ITER(hh,head,el,tmp) \ | ||
892 | for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ | ||
893 | el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) | ||
894 | #else | ||
895 | #define HASH_ITER(hh,head,el,tmp) \ | ||
896 | for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ | ||
897 | el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) | ||
898 | #endif | ||
899 | |||
900 | /* obtain a count of items in the hash */ | ||
901 | #define HASH_COUNT(head) HASH_CNT(hh,head) | ||
902 | #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) | ||
903 | |||
904 | typedef struct UT_hash_bucket { | ||
905 | struct UT_hash_handle *hh_head; | ||
906 | unsigned count; | ||
907 | |||
908 | /* expand_mult is normally set to 0. In this situation, the max chain length | ||
909 | * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If | ||
910 | * the bucket's chain exceeds this length, bucket expansion is triggered). | ||
911 | * However, setting expand_mult to a non-zero value delays bucket expansion | ||
912 | * (that would be triggered by additions to this particular bucket) | ||
913 | * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. | ||
914 | * (The multiplier is simply expand_mult+1). The whole idea of this | ||
915 | * multiplier is to reduce bucket expansions, since they are expensive, in | ||
916 | * situations where we know that a particular bucket tends to be overused. | ||
917 | * It is better to let its chain length grow to a longer yet-still-bounded | ||
918 | * value, than to do an O(n) bucket expansion too often. | ||
919 | */ | ||
920 | unsigned expand_mult; | ||
921 | |||
922 | } UT_hash_bucket; | ||
923 | |||
924 | /* random signature used only to find hash tables in external analysis */ | ||
925 | #define HASH_SIGNATURE 0xa0111fe1 | ||
926 | #define HASH_BLOOM_SIGNATURE 0xb12220f2 | ||
927 | |||
928 | typedef struct UT_hash_table { | ||
929 | UT_hash_bucket *buckets; | ||
930 | unsigned num_buckets, log2_num_buckets; | ||
931 | unsigned num_items; | ||
932 | struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ | ||
933 | ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ | ||
934 | |||
935 | /* in an ideal situation (all buckets used equally), no bucket would have | ||
936 | * more than ceil(#items/#buckets) items. that's the ideal chain length. */ | ||
937 | unsigned ideal_chain_maxlen; | ||
938 | |||
939 | /* nonideal_items is the number of items in the hash whose chain position | ||
940 | * exceeds the ideal chain maxlen. these items pay the penalty for an uneven | ||
941 | * hash distribution; reaching them in a chain traversal takes >ideal steps */ | ||
942 | unsigned nonideal_items; | ||
943 | |||
944 | /* ineffective expands occur when a bucket doubling was performed, but | ||
945 | * afterward, more than half the items in the hash had nonideal chain | ||
946 | * positions. If this happens on two consecutive expansions we inhibit any | ||
947 | * further expansion, as it's not helping; this happens when the hash | ||
948 | * function isn't a good fit for the key domain. When expansion is inhibited | ||
949 | * the hash will still work, albeit no longer in constant time. */ | ||
950 | unsigned ineff_expands, noexpand; | ||
951 | |||
952 | uint32_t signature; /* used only to find hash tables in external analysis */ | ||
953 | #ifdef HASH_BLOOM | ||
954 | uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ | ||
955 | uint8_t *bloom_bv; | ||
956 | char bloom_nbits; | ||
957 | #endif | ||
958 | |||
959 | } UT_hash_table; | ||
960 | |||
961 | typedef struct UT_hash_handle { | ||
962 | struct UT_hash_table *tbl; | ||
963 | void *prev; /* prev element in app order */ | ||
964 | void *next; /* next element in app order */ | ||
965 | struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ | ||
966 | struct UT_hash_handle *hh_next; /* next hh in bucket order */ | ||
967 | void *key; /* ptr to enclosing struct's key */ | ||
968 | unsigned keylen; /* enclosing struct's key len */ | ||
969 | unsigned hashv; /* result of hash-fcn(key) */ | ||
970 | } UT_hash_handle; | ||
971 | |||
972 | #endif /* UTHASH_H */ | ||
diff --git a/libs/cocos2d/Support/utlist.h b/libs/cocos2d/Support/utlist.h new file mode 100755 index 0000000..34c725b --- /dev/null +++ b/libs/cocos2d/Support/utlist.h | |||
@@ -0,0 +1,490 @@ | |||
1 | /* | ||
2 | Copyright (c) 2007-2010, Troy D. Hanson http://uthash.sourceforge.net | ||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | * Redistributions of source code must retain the above copyright | ||
9 | notice, this list of conditions and the following disclaimer. | ||
10 | |||
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | */ | ||
23 | |||
24 | #ifndef UTLIST_H | ||
25 | #define UTLIST_H | ||
26 | |||
27 | #define UTLIST_VERSION 1.9.1 | ||
28 | |||
29 | /* | ||
30 | * This file contains macros to manipulate singly and doubly-linked lists. | ||
31 | * | ||
32 | * 1. LL_ macros: singly-linked lists. | ||
33 | * 2. DL_ macros: doubly-linked lists. | ||
34 | * 3. CDL_ macros: circular doubly-linked lists. | ||
35 | * | ||
36 | * To use singly-linked lists, your structure must have a "next" pointer. | ||
37 | * To use doubly-linked lists, your structure must "prev" and "next" pointers. | ||
38 | * Either way, the pointer to the head of the list must be initialized to NULL. | ||
39 | * | ||
40 | * ----------------.EXAMPLE ------------------------- | ||
41 | * struct item { | ||
42 | * int id; | ||
43 | * struct item *prev, *next; | ||
44 | * } | ||
45 | * | ||
46 | * struct item *list = NULL: | ||
47 | * | ||
48 | * int main() { | ||
49 | * struct item *item; | ||
50 | * ... allocate and populate item ... | ||
51 | * DL_APPEND(list, item); | ||
52 | * } | ||
53 | * -------------------------------------------------- | ||
54 | * | ||
55 | * For doubly-linked lists, the append and delete macros are O(1) | ||
56 | * For singly-linked lists, append and delete are O(n) but prepend is O(1) | ||
57 | * The sort macro is O(n log(n)) for all types of single/double/circular lists. | ||
58 | */ | ||
59 | |||
60 | /* These macros use decltype or the earlier __typeof GNU extension. | ||
61 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ | ||
62 | when compiling c++ code), this code uses whatever method is needed | ||
63 | or, for VS2008 where neither is available, uses casting workarounds. */ | ||
64 | #ifdef _MSC_VER /* MS compiler */ | ||
65 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ | ||
66 | #define LDECLTYPE(x) decltype(x) | ||
67 | #else /* VS2008 or older (or VS2010 in C mode) */ | ||
68 | #define NO_DECLTYPE | ||
69 | #define LDECLTYPE(x) char* | ||
70 | #endif | ||
71 | #else /* GNU, Sun and other compilers */ | ||
72 | #define LDECLTYPE(x) __typeof(x) | ||
73 | #endif | ||
74 | |||
75 | /* for VS2008 we use some workarounds to get around the lack of decltype, | ||
76 | * namely, we always reassign our tmp variable to the list head if we need | ||
77 | * to dereference its prev/next pointers, and save/restore the real head.*/ | ||
78 | #ifdef NO_DECLTYPE | ||
79 | #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } | ||
80 | #define _NEXT(elt,list) ((char*)((list)->next)) | ||
81 | #define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } | ||
82 | #define _PREV(elt,list) ((char*)((list)->prev)) | ||
83 | #define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } | ||
84 | #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } | ||
85 | #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } | ||
86 | #else | ||
87 | #define _SV(elt,list) | ||
88 | #define _NEXT(elt,list) ((elt)->next) | ||
89 | #define _NEXTASGN(elt,list,to) ((elt)->next)=(to) | ||
90 | #define _PREV(elt,list) ((elt)->prev) | ||
91 | #define _PREVASGN(elt,list,to) ((elt)->prev)=(to) | ||
92 | #define _RS(list) | ||
93 | #define _CASTASGN(a,b) (a)=(b) | ||
94 | #endif | ||
95 | |||
96 | /****************************************************************************** | ||
97 | * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * | ||
98 | * Unwieldy variable names used here to avoid shadowing passed-in variables. * | ||
99 | *****************************************************************************/ | ||
100 | #define LL_SORT(list, cmp) \ | ||
101 | do { \ | ||
102 | LDECLTYPE(list) _ls_p; \ | ||
103 | LDECLTYPE(list) _ls_q; \ | ||
104 | LDECLTYPE(list) _ls_e; \ | ||
105 | LDECLTYPE(list) _ls_tail; \ | ||
106 | LDECLTYPE(list) _ls_oldhead; \ | ||
107 | LDECLTYPE(list) _tmp; \ | ||
108 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
109 | if (list) { \ | ||
110 | _ls_insize = 1; \ | ||
111 | _ls_looping = 1; \ | ||
112 | while (_ls_looping) { \ | ||
113 | _CASTASGN(_ls_p,list); \ | ||
114 | _CASTASGN(_ls_oldhead,list); \ | ||
115 | list = NULL; \ | ||
116 | _ls_tail = NULL; \ | ||
117 | _ls_nmerges = 0; \ | ||
118 | while (_ls_p) { \ | ||
119 | _ls_nmerges++; \ | ||
120 | _ls_q = _ls_p; \ | ||
121 | _ls_psize = 0; \ | ||
122 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
123 | _ls_psize++; \ | ||
124 | _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ | ||
125 | if (!_ls_q) break; \ | ||
126 | } \ | ||
127 | _ls_qsize = _ls_insize; \ | ||
128 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
129 | if (_ls_psize == 0) { \ | ||
130 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
131 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
132 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
133 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
134 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
135 | } else { \ | ||
136 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
137 | } \ | ||
138 | if (_ls_tail) { \ | ||
139 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
140 | } else { \ | ||
141 | _CASTASGN(list,_ls_e); \ | ||
142 | } \ | ||
143 | _ls_tail = _ls_e; \ | ||
144 | } \ | ||
145 | _ls_p = _ls_q; \ | ||
146 | } \ | ||
147 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ | ||
148 | if (_ls_nmerges <= 1) { \ | ||
149 | _ls_looping=0; \ | ||
150 | } \ | ||
151 | _ls_insize *= 2; \ | ||
152 | } \ | ||
153 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
154 | } while (0) | ||
155 | |||
156 | #define DL_SORT(list, cmp) \ | ||
157 | do { \ | ||
158 | LDECLTYPE(list) _ls_p; \ | ||
159 | LDECLTYPE(list) _ls_q; \ | ||
160 | LDECLTYPE(list) _ls_e; \ | ||
161 | LDECLTYPE(list) _ls_tail; \ | ||
162 | LDECLTYPE(list) _ls_oldhead; \ | ||
163 | LDECLTYPE(list) _tmp; \ | ||
164 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
165 | if (list) { \ | ||
166 | _ls_insize = 1; \ | ||
167 | _ls_looping = 1; \ | ||
168 | while (_ls_looping) { \ | ||
169 | _CASTASGN(_ls_p,list); \ | ||
170 | _CASTASGN(_ls_oldhead,list); \ | ||
171 | list = NULL; \ | ||
172 | _ls_tail = NULL; \ | ||
173 | _ls_nmerges = 0; \ | ||
174 | while (_ls_p) { \ | ||
175 | _ls_nmerges++; \ | ||
176 | _ls_q = _ls_p; \ | ||
177 | _ls_psize = 0; \ | ||
178 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
179 | _ls_psize++; \ | ||
180 | _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ | ||
181 | if (!_ls_q) break; \ | ||
182 | } \ | ||
183 | _ls_qsize = _ls_insize; \ | ||
184 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
185 | if (_ls_psize == 0) { \ | ||
186 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
187 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
188 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
189 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
190 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
191 | } else { \ | ||
192 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
193 | } \ | ||
194 | if (_ls_tail) { \ | ||
195 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
196 | } else { \ | ||
197 | _CASTASGN(list,_ls_e); \ | ||
198 | } \ | ||
199 | _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ | ||
200 | _ls_tail = _ls_e; \ | ||
201 | } \ | ||
202 | _ls_p = _ls_q; \ | ||
203 | } \ | ||
204 | _CASTASGN(list->prev, _ls_tail); \ | ||
205 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ | ||
206 | if (_ls_nmerges <= 1) { \ | ||
207 | _ls_looping=0; \ | ||
208 | } \ | ||
209 | _ls_insize *= 2; \ | ||
210 | } \ | ||
211 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
212 | } while (0) | ||
213 | |||
214 | #define CDL_SORT(list, cmp) \ | ||
215 | do { \ | ||
216 | LDECLTYPE(list) _ls_p; \ | ||
217 | LDECLTYPE(list) _ls_q; \ | ||
218 | LDECLTYPE(list) _ls_e; \ | ||
219 | LDECLTYPE(list) _ls_tail; \ | ||
220 | LDECLTYPE(list) _ls_oldhead; \ | ||
221 | LDECLTYPE(list) _tmp; \ | ||
222 | LDECLTYPE(list) _tmp2; \ | ||
223 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
224 | if (list) { \ | ||
225 | _ls_insize = 1; \ | ||
226 | _ls_looping = 1; \ | ||
227 | while (_ls_looping) { \ | ||
228 | _CASTASGN(_ls_p,list); \ | ||
229 | _CASTASGN(_ls_oldhead,list); \ | ||
230 | list = NULL; \ | ||
231 | _ls_tail = NULL; \ | ||
232 | _ls_nmerges = 0; \ | ||
233 | while (_ls_p) { \ | ||
234 | _ls_nmerges++; \ | ||
235 | _ls_q = _ls_p; \ | ||
236 | _ls_psize = 0; \ | ||
237 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
238 | _ls_psize++; \ | ||
239 | _SV(_ls_q,list); \ | ||
240 | if (_NEXT(_ls_q,list) == _ls_oldhead) { \ | ||
241 | _ls_q = NULL; \ | ||
242 | } else { \ | ||
243 | _ls_q = _NEXT(_ls_q,list); \ | ||
244 | } \ | ||
245 | _RS(list); \ | ||
246 | if (!_ls_q) break; \ | ||
247 | } \ | ||
248 | _ls_qsize = _ls_insize; \ | ||
249 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
250 | if (_ls_psize == 0) { \ | ||
251 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
252 | if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ | ||
253 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
254 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
255 | if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ | ||
256 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
257 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
258 | if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ | ||
259 | } else { \ | ||
260 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
261 | if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ | ||
262 | } \ | ||
263 | if (_ls_tail) { \ | ||
264 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
265 | } else { \ | ||
266 | _CASTASGN(list,_ls_e); \ | ||
267 | } \ | ||
268 | _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ | ||
269 | _ls_tail = _ls_e; \ | ||
270 | } \ | ||
271 | _ls_p = _ls_q; \ | ||
272 | } \ | ||
273 | _CASTASGN(list->prev,_ls_tail); \ | ||
274 | _CASTASGN(_tmp2,list); \ | ||
275 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list); \ | ||
276 | if (_ls_nmerges <= 1) { \ | ||
277 | _ls_looping=0; \ | ||
278 | } \ | ||
279 | _ls_insize *= 2; \ | ||
280 | } \ | ||
281 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
282 | } while (0) | ||
283 | |||
284 | /****************************************************************************** | ||
285 | * singly linked list macros (non-circular) * | ||
286 | *****************************************************************************/ | ||
287 | #define LL_PREPEND(head,add) \ | ||
288 | do { \ | ||
289 | (add)->next = head; \ | ||
290 | head = add; \ | ||
291 | } while (0) | ||
292 | |||
293 | #define LL_APPEND(head,add) \ | ||
294 | do { \ | ||
295 | LDECLTYPE(head) _tmp; \ | ||
296 | (add)->next=NULL; \ | ||
297 | if (head) { \ | ||
298 | _tmp = head; \ | ||
299 | while (_tmp->next) { _tmp = _tmp->next; } \ | ||
300 | _tmp->next=(add); \ | ||
301 | } else { \ | ||
302 | (head)=(add); \ | ||
303 | } \ | ||
304 | } while (0) | ||
305 | |||
306 | #define LL_DELETE(head,del) \ | ||
307 | do { \ | ||
308 | LDECLTYPE(head) _tmp; \ | ||
309 | if ((head) == (del)) { \ | ||
310 | (head)=(head)->next; \ | ||
311 | } else { \ | ||
312 | _tmp = head; \ | ||
313 | while (_tmp->next && (_tmp->next != (del))) { \ | ||
314 | _tmp = _tmp->next; \ | ||
315 | } \ | ||
316 | if (_tmp->next) { \ | ||
317 | _tmp->next = ((del)->next); \ | ||
318 | } \ | ||
319 | } \ | ||
320 | } while (0) | ||
321 | |||
322 | /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ | ||
323 | #define LL_APPEND_VS2008(head,add) \ | ||
324 | do { \ | ||
325 | if (head) { \ | ||
326 | (add)->next = head; /* use add->next as a temp variable */ \ | ||
327 | while ((add)->next->next) { (add)->next = (add)->next->next; } \ | ||
328 | (add)->next->next=(add); \ | ||
329 | } else { \ | ||
330 | (head)=(add); \ | ||
331 | } \ | ||
332 | (add)->next=NULL; \ | ||
333 | } while (0) | ||
334 | |||
335 | #define LL_DELETE_VS2008(head,del) \ | ||
336 | do { \ | ||
337 | if ((head) == (del)) { \ | ||
338 | (head)=(head)->next; \ | ||
339 | } else { \ | ||
340 | char *_tmp = (char*)(head); \ | ||
341 | while (head->next && (head->next != (del))) { \ | ||
342 | head = head->next; \ | ||
343 | } \ | ||
344 | if (head->next) { \ | ||
345 | head->next = ((del)->next); \ | ||
346 | } \ | ||
347 | { \ | ||
348 | char **_head_alias = (char**)&(head); \ | ||
349 | *_head_alias = _tmp; \ | ||
350 | } \ | ||
351 | } \ | ||
352 | } while (0) | ||
353 | #ifdef NO_DECLTYPE | ||
354 | #undef LL_APPEND | ||
355 | #define LL_APPEND LL_APPEND_VS2008 | ||
356 | #undef LL_DELETE | ||
357 | #define LL_DELETE LL_DELETE_VS2008 | ||
358 | #endif | ||
359 | /* end VS2008 replacements */ | ||
360 | |||
361 | #define LL_FOREACH(head,el) \ | ||
362 | for(el=head;el;el=el->next) | ||
363 | |||
364 | #define LL_FOREACH_SAFE(head,el,tmp) \ | ||
365 | for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) | ||
366 | |||
367 | #define LL_SEARCH_SCALAR(head,out,field,val) \ | ||
368 | do { \ | ||
369 | LL_FOREACH(head,out) { \ | ||
370 | if ((out)->field == (val)) break; \ | ||
371 | } \ | ||
372 | } while(0) | ||
373 | |||
374 | #define LL_SEARCH(head,out,elt,cmp) \ | ||
375 | do { \ | ||
376 | LL_FOREACH(head,out) { \ | ||
377 | if ((cmp(out,elt))==0) break; \ | ||
378 | } \ | ||
379 | } while(0) | ||
380 | |||
381 | /****************************************************************************** | ||
382 | * doubly linked list macros (non-circular) * | ||
383 | *****************************************************************************/ | ||
384 | #define DL_PREPEND(head,add) \ | ||
385 | do { \ | ||
386 | (add)->next = head; \ | ||
387 | if (head) { \ | ||
388 | (add)->prev = (head)->prev; \ | ||
389 | (head)->prev = (add); \ | ||
390 | } else { \ | ||
391 | (add)->prev = (add); \ | ||
392 | } \ | ||
393 | (head) = (add); \ | ||
394 | } while (0) | ||
395 | |||
396 | #define DL_APPEND(head,add) \ | ||
397 | do { \ | ||
398 | if (head) { \ | ||
399 | (add)->prev = (head)->prev; \ | ||
400 | (head)->prev->next = (add); \ | ||
401 | (head)->prev = (add); \ | ||
402 | (add)->next = NULL; \ | ||
403 | } else { \ | ||
404 | (head)=(add); \ | ||
405 | (head)->prev = (head); \ | ||
406 | (head)->next = NULL; \ | ||
407 | } \ | ||
408 | } while (0); | ||
409 | |||
410 | #define DL_DELETE(head,del) \ | ||
411 | do { \ | ||
412 | if ((del)->prev == (del)) { \ | ||
413 | (head)=NULL; \ | ||
414 | } else if ((del)==(head)) { \ | ||
415 | (del)->next->prev = (del)->prev; \ | ||
416 | (head) = (del)->next; \ | ||
417 | } else { \ | ||
418 | (del)->prev->next = (del)->next; \ | ||
419 | if ((del)->next) { \ | ||
420 | (del)->next->prev = (del)->prev; \ | ||
421 | } else { \ | ||
422 | (head)->prev = (del)->prev; \ | ||
423 | } \ | ||
424 | } \ | ||
425 | } while (0); | ||
426 | |||
427 | |||
428 | #define DL_FOREACH(head,el) \ | ||
429 | for(el=head;el;el=el->next) | ||
430 | |||
431 | /* this version is safe for deleting the elements during iteration */ | ||
432 | #define DL_FOREACH_SAFE(head,el,tmp) \ | ||
433 | for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) | ||
434 | |||
435 | /* these are identical to their singly-linked list counterparts */ | ||
436 | #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR | ||
437 | #define DL_SEARCH LL_SEARCH | ||
438 | |||
439 | /****************************************************************************** | ||
440 | * circular doubly linked list macros * | ||
441 | *****************************************************************************/ | ||
442 | #define CDL_PREPEND(head,add) \ | ||
443 | do { \ | ||
444 | if (head) { \ | ||
445 | (add)->prev = (head)->prev; \ | ||
446 | (add)->next = (head); \ | ||
447 | (head)->prev = (add); \ | ||
448 | (add)->prev->next = (add); \ | ||
449 | } else { \ | ||
450 | (add)->prev = (add); \ | ||
451 | (add)->next = (add); \ | ||
452 | } \ | ||
453 | (head)=(add); \ | ||
454 | } while (0) | ||
455 | |||
456 | #define CDL_DELETE(head,del) \ | ||
457 | do { \ | ||
458 | if ( ((head)==(del)) && ((head)->next == (head))) { \ | ||
459 | (head) = 0L; \ | ||
460 | } else { \ | ||
461 | (del)->next->prev = (del)->prev; \ | ||
462 | (del)->prev->next = (del)->next; \ | ||
463 | if ((del) == (head)) (head)=(del)->next; \ | ||
464 | } \ | ||
465 | } while (0); | ||
466 | |||
467 | #define CDL_FOREACH(head,el) \ | ||
468 | for(el=head;el;el=(el->next==head ? 0L : el->next)) | ||
469 | |||
470 | #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ | ||
471 | for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ | ||
472 | (el) && ((tmp2)=(el)->next, 1); \ | ||
473 | ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) | ||
474 | |||
475 | #define CDL_SEARCH_SCALAR(head,out,field,val) \ | ||
476 | do { \ | ||
477 | CDL_FOREACH(head,out) { \ | ||
478 | if ((out)->field == (val)) break; \ | ||
479 | } \ | ||
480 | } while(0) | ||
481 | |||
482 | #define CDL_SEARCH(head,out,elt,cmp) \ | ||
483 | do { \ | ||
484 | CDL_FOREACH(head,out) { \ | ||
485 | if ((cmp(out,elt))==0) break; \ | ||
486 | } \ | ||
487 | } while(0) | ||
488 | |||
489 | #endif /* UTLIST_H */ | ||
490 | |||