PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/core/sdk-objc/GMResourceFork.m

http://macfuse.googlecode.com/
Objective C | 305 lines | 202 code | 38 blank | 65 comment | 11 complexity | fb951f2e7ad1d06435b727a9a82dc15f MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-2.0
  1. // ================================================================
  2. // Copyright (c) 2007, Google Inc.
  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
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // ================================================================
  31. //
  32. // GMResourceFork.m
  33. // MacFUSE
  34. //
  35. // Created by ted on 12/29/07.
  36. //
  37. // See the following URL for documentation on resource fork format:
  38. // http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html
  39. //
  40. #import "GMResourceFork.h"
  41. // The format for a resource fork is as follows ('+' means one-or-more):
  42. //
  43. // ResourceForkHeader
  44. // {ResourceDataItem, <data_for_resource>}+
  45. // ResourceMapHeader
  46. // ResourceTypeListHeader
  47. // ResourceTypeListItem+
  48. // ResourceReferenceListItem+
  49. // {ResourceNameListItem, <name_for_resource>}+
  50. //
  51. typedef struct {
  52. UInt32 resourceDataOffset; // Offset from beginning to resource data.
  53. UInt32 resourceMapOffset; // Offset from beginning to resource map.
  54. UInt32 resourceDataLength; // Length of entire data segment in bytes.
  55. UInt32 resourceMapLength; // Length of resource map in bytes.
  56. } __attribute__((packed)) ResourceForkHeader;
  57. typedef struct {
  58. UInt32 dataLength; // Length of data that follows.
  59. // Followed by: variable length byte[] of data.
  60. } __attribute__((packed)) ResourceDataItem;
  61. typedef struct {
  62. // The next three fields should be zero'd out. It looks like they are reserved
  63. // for in-memory use by an entity loading the resource fork.
  64. char reservedForResourceForkHeader[sizeof(ResourceForkHeader)];
  65. UInt32 reservedForHandle;
  66. UInt16 reservedForFileReferenceNumber;
  67. SInt16 resourceForkAttributes; // ResFileAttributes attribs of resource fork.
  68. UInt16 typeListOffset; // Offset from beginning of map to resource type list.
  69. UInt16 nameListOffset; // Offset from beginning of map to resource name list.
  70. } __attribute__((packed)) ResourceMapHeader;
  71. typedef struct {
  72. UInt16 numTypesMinusOne; // Number of types in the map minus 1.
  73. } __attribute__((packed)) ResourceTypeListHeader;
  74. typedef struct {
  75. ResType type; // FourCharCode resource type, i.e. 'icns'
  76. UInt16 numMinusOne; // Number of resources of this type in map minus 1.
  77. UInt16 referenceListOffset; // Offset from beginning of resource type list to
  78. // the reference list for this type.
  79. } __attribute__((packed)) ResourceTypeListItem;
  80. typedef struct {
  81. SInt16 resid; // ResID type; resource ID
  82. SInt16 nameListOffset; // Offset from beginning of resource name list to
  83. // resource name for this resource. A value of -1 is
  84. // used when the resource does not have a name.
  85. UInt8 attributes; // ResAttributes?: resource attributes.
  86. UInt8 resourceDataOffset1; // These three bytes are the offset from beginning
  87. UInt8 resourceDataOffset2; // of resource data to data for this resource.
  88. UInt8 resourceDataOffset3;
  89. UInt32 reservedForHandleToResource; // Reserved, zero out.
  90. } __attribute__((packed)) ResourceReferenceListItem;
  91. typedef struct {
  92. UInt8 nameLength; // Length of name in bytes.
  93. // Followed by: variable length char[] for resource name.
  94. } __attribute__((packed)) ResourceNameListItem;
  95. @implementation GMResource
  96. + (GMResource *)resourceWithType:(ResType)resType
  97. resID:(ResID)resID
  98. name:(NSString *)name // May be nil
  99. data:(NSData *)data {
  100. return [[[GMResource alloc]
  101. initWithType:resType resID:resID name:name data:data] autorelease];
  102. }
  103. - (id)init {
  104. return [self initWithType:0 resID:0 name:nil data:nil];
  105. }
  106. - (id)initWithType:(ResType)resType
  107. resID:(ResID)resID
  108. name:(NSString *)name
  109. data:(NSData *)data {
  110. if ((self = [super init])) {
  111. if (data == nil) {
  112. [self release];
  113. return nil;
  114. }
  115. resType_ = resType;
  116. resID_ = resID;
  117. name_ = [name retain];
  118. data_ = [data retain];
  119. }
  120. return self;
  121. }
  122. - (void)dealloc {
  123. [name_ release];
  124. [data_ release];
  125. [super dealloc];
  126. }
  127. - (ResID)resID {
  128. return resID_;
  129. }
  130. - (ResType)resType {
  131. return resType_;
  132. }
  133. - (NSString *)name {
  134. return name_;
  135. }
  136. - (NSData *)data {
  137. return data_;
  138. }
  139. @end
  140. @implementation GMResourceFork
  141. + (GMResourceFork *)resourceFork {
  142. return [[[GMResourceFork alloc] init] autorelease];
  143. }
  144. - (id)init {
  145. if ((self = [super init])) {
  146. resourcesByType_ = [[NSMutableDictionary alloc] init];
  147. }
  148. return self;
  149. }
  150. - (void)dealloc {
  151. [resourcesByType_ release];
  152. [super dealloc];
  153. }
  154. // Add a new resource.
  155. - (void)addResourceWithType:(ResType)resType
  156. resID:(ResID)resID
  157. name:(NSString *)name
  158. data:(NSData *)data {
  159. GMResource* resource = [GMResource resourceWithType:resType
  160. resID:resID
  161. name:name
  162. data:data];
  163. [self addResource:resource];
  164. }
  165. - (void)addResource:(GMResource *)resource {
  166. ResType type = [resource resType];
  167. NSNumber* key = [NSNumber numberWithLong:type];
  168. NSMutableArray* resources = [resourcesByType_ objectForKey:key];
  169. if (resources == nil) {
  170. resources = [NSMutableArray array];
  171. [resourcesByType_ setObject:resources forKey:key];
  172. }
  173. [resources addObject:resource];
  174. }
  175. // Constructs the raw data for the resource fork containing all added resources.
  176. - (NSData *)data {
  177. NSMutableData* resourceData = [NSMutableData data];
  178. NSMutableData* typeListData = [NSMutableData data];
  179. NSMutableData* referenceListData = [NSMutableData data];
  180. NSMutableData* nameListData = [NSMutableData data];
  181. NSArray* keys = [resourcesByType_ allKeys];
  182. int refListStartOffset = sizeof(ResourceTypeListHeader) +
  183. ([keys count] * sizeof(ResourceTypeListItem));
  184. // For each resource type.
  185. for ( int i = 0; i < [keys count]; ++i ) {
  186. NSArray* resources = [resourcesByType_ objectForKey:[keys objectAtIndex:i]];
  187. // -- Append the ResourceTypeListItem to typeListData --
  188. ResourceTypeListItem typeItem;
  189. memset(&typeItem, 0, sizeof(typeItem));
  190. UInt16 refListOffset = refListStartOffset + [referenceListData length];
  191. ResType type = [[resources lastObject] resType];
  192. typeItem.type = htonl(type);
  193. typeItem.numMinusOne = htons([resources count] - 1);
  194. typeItem.referenceListOffset = htons(refListOffset);
  195. [typeListData appendBytes:&typeItem length:sizeof(typeItem)];
  196. // For each resource of that type.
  197. for ( int j = 0; j < [resources count]; ++j ) {
  198. GMResource* resource = [resources objectAtIndex:j];
  199. NSString* name = [resource name];
  200. // -- Append the ResourceReferenceListItem to referenceListData --
  201. ResourceReferenceListItem referenceItem;
  202. memset(&referenceItem, 0, sizeof(referenceItem));
  203. UInt32 dataOffset = [resourceData length];
  204. referenceItem.resid = htons([resource resID]);
  205. referenceItem.nameListOffset =
  206. htons((name == nil) ? (SInt16)(-1) : [nameListData length]);
  207. referenceItem.attributes = 0; // TODO: Support attributes?
  208. referenceItem.resourceDataOffset1 = (dataOffset & 0x00FF0000) >> 16;
  209. referenceItem.resourceDataOffset2 = (dataOffset & 0x0000FF00) >> 8;
  210. referenceItem.resourceDataOffset3 = (dataOffset & 0x000000FF);
  211. [referenceListData appendBytes:&referenceItem length:sizeof(referenceItem)];
  212. // -- Append the ResourceNameListItem and name data nameListData --
  213. if ([resource name] != nil) {
  214. ResourceNameListItem nameItem;
  215. memset(&nameItem, 0, sizeof(nameItem));
  216. NSString* name = [resource name];
  217. int nameLen = [name lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  218. nameItem.nameLength = nameLen;
  219. [nameListData appendBytes:&nameItem length:sizeof(nameItem)];
  220. [nameListData appendBytes:[name UTF8String] length:nameLen];
  221. }
  222. // -- Append the ResourceDataItem and resource data to resourceData --
  223. ResourceDataItem dataItem;
  224. memset(&dataItem, 0, sizeof(dataItem));
  225. dataItem.dataLength = htonl([[resource data] length]);
  226. [resourceData appendBytes:&dataItem length:sizeof(dataItem)];
  227. [resourceData appendData:[resource data]];
  228. }
  229. }
  230. ResourceForkHeader forkHeader;
  231. memset(&forkHeader, 0, sizeof(forkHeader));
  232. ResourceMapHeader mapHeader;
  233. memset(&mapHeader, 0, sizeof(mapHeader));
  234. ResourceTypeListHeader typeListHeader;
  235. memset(&typeListHeader, 0, sizeof(typeListHeader));
  236. // It looks like OS X prefers the resource data to start at offset 256 bytes.
  237. UInt32 dataOffset = sizeof(forkHeader) > 256 ? sizeof(forkHeader) : 256;
  238. UInt32 dataLen = [resourceData length];
  239. UInt32 mapOffset = dataOffset + dataLen;
  240. UInt32 mapLen = sizeof(ResourceMapHeader) +
  241. sizeof(ResourceTypeListHeader) +
  242. [typeListData length] +
  243. [referenceListData length] +
  244. [nameListData length];
  245. forkHeader.resourceDataOffset = htonl(dataOffset);
  246. forkHeader.resourceMapOffset = htonl(mapOffset);
  247. forkHeader.resourceDataLength = htonl(dataLen);
  248. forkHeader.resourceMapLength = htonl(mapLen);
  249. mapHeader.resourceForkAttributes = htons(0); // TODO: Support attributes?
  250. mapHeader.typeListOffset = htons(sizeof(mapHeader));
  251. mapHeader.nameListOffset = htons(sizeof(mapHeader) +
  252. sizeof(ResourceTypeListHeader) +
  253. [typeListData length] +
  254. [referenceListData length]);
  255. typeListHeader.numTypesMinusOne = htons([resourcesByType_ count] - 1);
  256. NSMutableData* data = [NSMutableData data];
  257. [data appendBytes:&forkHeader length:sizeof(forkHeader)];
  258. [data setLength:dataOffset];
  259. [data appendData:resourceData];
  260. [data appendBytes:&mapHeader length:sizeof(mapHeader)];
  261. [data appendBytes:&typeListHeader length:sizeof(typeListHeader)];
  262. [data appendData:typeListData];
  263. [data appendData:referenceListData];
  264. [data appendData:nameListData];
  265. return data;
  266. }
  267. @end