/core/sdk-objc/GMResourceFork.m
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
- // ================================================================
- // Copyright (c) 2007, Google Inc.
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- // ================================================================
- //
- // GMResourceFork.m
- // MacFUSE
- //
- // Created by ted on 12/29/07.
- //
- // See the following URL for documentation on resource fork format:
- // http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html
- //
- #import "GMResourceFork.h"
- // The format for a resource fork is as follows ('+' means one-or-more):
- //
- // ResourceForkHeader
- // {ResourceDataItem, <data_for_resource>}+
- // ResourceMapHeader
- // ResourceTypeListHeader
- // ResourceTypeListItem+
- // ResourceReferenceListItem+
- // {ResourceNameListItem, <name_for_resource>}+
- //
- typedef struct {
- UInt32 resourceDataOffset; // Offset from beginning to resource data.
- UInt32 resourceMapOffset; // Offset from beginning to resource map.
- UInt32 resourceDataLength; // Length of entire data segment in bytes.
- UInt32 resourceMapLength; // Length of resource map in bytes.
- } __attribute__((packed)) ResourceForkHeader;
- typedef struct {
- UInt32 dataLength; // Length of data that follows.
- // Followed by: variable length byte[] of data.
- } __attribute__((packed)) ResourceDataItem;
- typedef struct {
- // The next three fields should be zero'd out. It looks like they are reserved
- // for in-memory use by an entity loading the resource fork.
- char reservedForResourceForkHeader[sizeof(ResourceForkHeader)];
- UInt32 reservedForHandle;
- UInt16 reservedForFileReferenceNumber;
-
- SInt16 resourceForkAttributes; // ResFileAttributes attribs of resource fork.
- UInt16 typeListOffset; // Offset from beginning of map to resource type list.
- UInt16 nameListOffset; // Offset from beginning of map to resource name list.
- } __attribute__((packed)) ResourceMapHeader;
- typedef struct {
- UInt16 numTypesMinusOne; // Number of types in the map minus 1.
- } __attribute__((packed)) ResourceTypeListHeader;
- typedef struct {
- ResType type; // FourCharCode resource type, i.e. 'icns'
- UInt16 numMinusOne; // Number of resources of this type in map minus 1.
- UInt16 referenceListOffset; // Offset from beginning of resource type list to
- // the reference list for this type.
- } __attribute__((packed)) ResourceTypeListItem;
- typedef struct {
- SInt16 resid; // ResID type; resource ID
- SInt16 nameListOffset; // Offset from beginning of resource name list to
- // resource name for this resource. A value of -1 is
- // used when the resource does not have a name.
- UInt8 attributes; // ResAttributes?: resource attributes.
- UInt8 resourceDataOffset1; // These three bytes are the offset from beginning
- UInt8 resourceDataOffset2; // of resource data to data for this resource.
- UInt8 resourceDataOffset3;
- UInt32 reservedForHandleToResource; // Reserved, zero out.
- } __attribute__((packed)) ResourceReferenceListItem;
- typedef struct {
- UInt8 nameLength; // Length of name in bytes.
- // Followed by: variable length char[] for resource name.
- } __attribute__((packed)) ResourceNameListItem;
- @implementation GMResource
- + (GMResource *)resourceWithType:(ResType)resType
- resID:(ResID)resID
- name:(NSString *)name // May be nil
- data:(NSData *)data {
- return [[[GMResource alloc]
- initWithType:resType resID:resID name:name data:data] autorelease];
- }
- - (id)init {
- return [self initWithType:0 resID:0 name:nil data:nil];
- }
- - (id)initWithType:(ResType)resType
- resID:(ResID)resID
- name:(NSString *)name
- data:(NSData *)data {
- if ((self = [super init])) {
- if (data == nil) {
- [self release];
- return nil;
- }
- resType_ = resType;
- resID_ = resID;
- name_ = [name retain];
- data_ = [data retain];
- }
- return self;
- }
- - (void)dealloc {
- [name_ release];
- [data_ release];
- [super dealloc];
- }
- - (ResID)resID {
- return resID_;
- }
- - (ResType)resType {
- return resType_;
- }
- - (NSString *)name {
- return name_;
- }
- - (NSData *)data {
- return data_;
- }
- @end
- @implementation GMResourceFork
- + (GMResourceFork *)resourceFork {
- return [[[GMResourceFork alloc] init] autorelease];
- }
- - (id)init {
- if ((self = [super init])) {
- resourcesByType_ = [[NSMutableDictionary alloc] init];
- }
- return self;
- }
- - (void)dealloc {
- [resourcesByType_ release];
- [super dealloc];
- }
- // Add a new resource.
- - (void)addResourceWithType:(ResType)resType
- resID:(ResID)resID
- name:(NSString *)name
- data:(NSData *)data {
- GMResource* resource = [GMResource resourceWithType:resType
- resID:resID
- name:name
- data:data];
- [self addResource:resource];
- }
- - (void)addResource:(GMResource *)resource {
- ResType type = [resource resType];
- NSNumber* key = [NSNumber numberWithLong:type];
- NSMutableArray* resources = [resourcesByType_ objectForKey:key];
- if (resources == nil) {
- resources = [NSMutableArray array];
- [resourcesByType_ setObject:resources forKey:key];
- }
- [resources addObject:resource];
- }
- // Constructs the raw data for the resource fork containing all added resources.
- - (NSData *)data {
- NSMutableData* resourceData = [NSMutableData data];
- NSMutableData* typeListData = [NSMutableData data];
- NSMutableData* referenceListData = [NSMutableData data];
- NSMutableData* nameListData = [NSMutableData data];
- NSArray* keys = [resourcesByType_ allKeys];
- int refListStartOffset = sizeof(ResourceTypeListHeader) +
- ([keys count] * sizeof(ResourceTypeListItem));
- // For each resource type.
- for ( int i = 0; i < [keys count]; ++i ) {
- NSArray* resources = [resourcesByType_ objectForKey:[keys objectAtIndex:i]];
- // -- Append the ResourceTypeListItem to typeListData --
- ResourceTypeListItem typeItem;
- memset(&typeItem, 0, sizeof(typeItem));
- UInt16 refListOffset = refListStartOffset + [referenceListData length];
- ResType type = [[resources lastObject] resType];
- typeItem.type = htonl(type);
- typeItem.numMinusOne = htons([resources count] - 1);
- typeItem.referenceListOffset = htons(refListOffset);
- [typeListData appendBytes:&typeItem length:sizeof(typeItem)];
-
- // For each resource of that type.
- for ( int j = 0; j < [resources count]; ++j ) {
- GMResource* resource = [resources objectAtIndex:j];
- NSString* name = [resource name];
-
- // -- Append the ResourceReferenceListItem to referenceListData --
- ResourceReferenceListItem referenceItem;
- memset(&referenceItem, 0, sizeof(referenceItem));
- UInt32 dataOffset = [resourceData length];
- referenceItem.resid = htons([resource resID]);
- referenceItem.nameListOffset =
- htons((name == nil) ? (SInt16)(-1) : [nameListData length]);
- referenceItem.attributes = 0; // TODO: Support attributes?
- referenceItem.resourceDataOffset1 = (dataOffset & 0x00FF0000) >> 16;
- referenceItem.resourceDataOffset2 = (dataOffset & 0x0000FF00) >> 8;
- referenceItem.resourceDataOffset3 = (dataOffset & 0x000000FF);
- [referenceListData appendBytes:&referenceItem length:sizeof(referenceItem)];
- // -- Append the ResourceNameListItem and name data nameListData --
- if ([resource name] != nil) {
- ResourceNameListItem nameItem;
- memset(&nameItem, 0, sizeof(nameItem));
- NSString* name = [resource name];
- int nameLen = [name lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
- nameItem.nameLength = nameLen;
- [nameListData appendBytes:&nameItem length:sizeof(nameItem)];
- [nameListData appendBytes:[name UTF8String] length:nameLen];
- }
- // -- Append the ResourceDataItem and resource data to resourceData --
- ResourceDataItem dataItem;
- memset(&dataItem, 0, sizeof(dataItem));
- dataItem.dataLength = htonl([[resource data] length]);
- [resourceData appendBytes:&dataItem length:sizeof(dataItem)];
- [resourceData appendData:[resource data]];
- }
- }
- ResourceForkHeader forkHeader;
- memset(&forkHeader, 0, sizeof(forkHeader));
- ResourceMapHeader mapHeader;
- memset(&mapHeader, 0, sizeof(mapHeader));
- ResourceTypeListHeader typeListHeader;
- memset(&typeListHeader, 0, sizeof(typeListHeader));
-
- // It looks like OS X prefers the resource data to start at offset 256 bytes.
- UInt32 dataOffset = sizeof(forkHeader) > 256 ? sizeof(forkHeader) : 256;
- UInt32 dataLen = [resourceData length];
- UInt32 mapOffset = dataOffset + dataLen;
- UInt32 mapLen = sizeof(ResourceMapHeader) +
- sizeof(ResourceTypeListHeader) +
- [typeListData length] +
- [referenceListData length] +
- [nameListData length];
- forkHeader.resourceDataOffset = htonl(dataOffset);
- forkHeader.resourceMapOffset = htonl(mapOffset);
- forkHeader.resourceDataLength = htonl(dataLen);
- forkHeader.resourceMapLength = htonl(mapLen);
-
- mapHeader.resourceForkAttributes = htons(0); // TODO: Support attributes?
- mapHeader.typeListOffset = htons(sizeof(mapHeader));
- mapHeader.nameListOffset = htons(sizeof(mapHeader) +
- sizeof(ResourceTypeListHeader) +
- [typeListData length] +
- [referenceListData length]);
-
- typeListHeader.numTypesMinusOne = htons([resourcesByType_ count] - 1);
- NSMutableData* data = [NSMutableData data];
- [data appendBytes:&forkHeader length:sizeof(forkHeader)];
- [data setLength:dataOffset];
- [data appendData:resourceData];
- [data appendBytes:&mapHeader length:sizeof(mapHeader)];
- [data appendBytes:&typeListHeader length:sizeof(typeListHeader)];
- [data appendData:typeListData];
- [data appendData:referenceListData];
- [data appendData:nameListData];
-
- return data;
- }
- @end