[go: up one dir, main page]

File: XADResourceFork.m

package info (click to toggle)
unar 1.10.8%2Bds1-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,212 kB
  • sloc: ansic: 50,891; objc: 47,233; makefile: 77; sh: 34
file content (185 lines) | stat: -rw-r--r-- 6,071 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
 * XADResourceFork.m
 *
 * Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 */
#import "XADResourceFork.h"
#import "CSMemoryHandle.h"

#define ResourceMapHeader 22 // 16+4+2 bytes reserved for in-memory structures.
#define ResourceMapEntryHeader 2 // 2-byte type count actually part of type list.
#define ResourceMapEntrySize 8 // 4+2+2 bytes per type list entry.

@implementation XADResourceFork

+(XADResourceFork *)resourceForkWithHandle:(CSHandle *)handle
{
	if(!handle) return nil;
	XADResourceFork *fork=[[self new] autorelease];
	[fork parseFromHandle:handle];
	return fork;
}

+(XADResourceFork *)resourceForkWithHandle:(CSHandle *)handle error:(XADError *)errorptr
{
	@try { return [self resourceForkWithHandle:handle]; }
	@catch(id exception) { if(errorptr) *errorptr=[XADException parseException:exception]; }
	return nil;
}

-(id)init
{
	if((self=[super init]))
	{
		resources=nil;
	}
	return self;
}

-(void)dealloc
{
	[resources release];
	[super dealloc];
}

-(void)parseFromHandle:(CSHandle *)handle
{
	off_t pos=[handle offsetInFile];

	off_t dataoffset=[handle readUInt32BE];
	off_t mapoffset=[handle readUInt32BE];
	off_t datalength=[handle readUInt32BE];
	off_t maplength=[handle readUInt32BE];

	CSHandle *datahandle=[handle nonCopiedSubHandleFrom:pos+dataoffset length:datalength];
	NSMutableDictionary *dataobjects=[self _parseResourceDataFromHandle:datahandle];

	// Load the map into memory so that traversing its data structures
	// doesn't cause countless seeks in compressed or encrypted input streams
	[handle seekToFileOffset:pos+mapoffset];
	NSData *mapdata=[handle readDataOfLength:(int)maplength];
	CSHandle *maphandle=[CSMemoryHandle memoryHandleForReadingData:mapdata];

	[resources release];
	resources=[[self _parseMapFromHandle:maphandle withDataObjects:dataobjects] retain];
}

-(NSData *)resourceDataForType:(uint32_t)type identifier:(int)identifier
{
	NSNumber *typekey=[NSNumber numberWithUnsignedInt:type];
	NSNumber *identifierkey=[NSNumber numberWithInt:identifier];
	NSDictionary *resourcesoftype=[resources objectForKey:typekey];
	NSDictionary *resource=[resourcesoftype objectForKey:identifierkey];
	return [resource objectForKey:@"Data"];
}

-(NSMutableDictionary *)_parseResourceDataFromHandle:(CSHandle *)handle
{
	NSMutableDictionary *dict=[NSMutableDictionary dictionary];
	while(![handle atEndOfFile])
	{
		NSNumber *key=[NSNumber numberWithUnsignedLongLong:[handle offsetInFile]];
		uint32_t length=[handle readUInt32BE];
		NSData *data=[handle readDataOfLength:length];
		[dict setObject:data forKey:key];
	}
	return dict;
}

-(NSDictionary *)_parseMapFromHandle:(CSHandle *)handle withDataObjects:(NSMutableDictionary *)dataobjects
{
	[handle skipBytes:ResourceMapHeader];
	/*int forkattributes=*/[handle readUInt16BE];
	int typelistoffset=[handle readInt16BE];
	int namelistoffset=[handle readInt16BE];
	
	int typecount=[handle readInt16BE]+1;
	NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithCapacity:typecount];
	for(int i=0;i<typecount;i++)
	{
		[handle seekToFileOffset:typelistoffset+i*ResourceMapEntrySize+ResourceMapEntryHeader];
		uint32_t type=[handle readID];
		int count=[handle readInt16BE]+1;
		int offset=[handle readInt16BE];

		[handle seekToFileOffset:typelistoffset+offset];
		NSDictionary *references=[self _parseReferencesFromHandle:handle count:count];

		[dict setObject:references forKey:[NSNumber numberWithUnsignedInt:type]];
	}

	NSEnumerator *typeenumerator=[dict keyEnumerator];
	NSNumber *type;
	while(type=[typeenumerator nextObject])
	{
		NSDictionary *resourcesoftype=[dict objectForKey:type];
		NSEnumerator *identifierenumerator=[resourcesoftype keyEnumerator];
		NSNumber *identifier;
		while(identifier=[identifierenumerator nextObject])
		{
			NSMutableDictionary *resource=[resourcesoftype objectForKey:identifier];
			[resource setObject:type forKey:@"Type"];

			// Resolve the name (if any).
			NSNumber *nameoffset=[resource objectForKey:@"NameOffset"];
			if(nameoffset)
			{
				// untested
				[handle seekToFileOffset:namelistoffset+[nameoffset intValue]];
				int length=[handle readUInt8];
				NSData *namedata=[handle readDataOfLength:length];
				[resource setObject:namedata forKey:@"NameData"];
			}

			// Resolve the data.
			NSNumber *dataoffset=[resource objectForKey:@"DataOffset"];
			NSData *data=[dataobjects objectForKey:dataoffset];
			[resource setObject:data forKey:@"Data"];
		}
	}
	
	return dict;
}

-(NSDictionary *)_parseReferencesFromHandle:(CSHandle *)handle count:(int)count
{
	NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithCapacity:count];
	for(int i=0;i<count;i++)
	{
		int identifier=[handle readInt16BE];
		int nameoffset=[handle readInt16BE];
		uint32_t attrsandoffset=[handle readUInt32BE];
		int attrs=(attrsandoffset>>24)&0xff;
		off_t offset=attrsandoffset&0xffffff;
		/*reserved=*/[handle readUInt32BE];

		NSNumber *key=[NSNumber numberWithInt:identifier];
		NSMutableDictionary *resource=[NSMutableDictionary dictionaryWithObjectsAndKeys:
			key,@"ID",
			[NSNumber numberWithInt:attrs],@"Attributes",
			[NSNumber numberWithUnsignedLongLong:offset],@"DataOffset",
		nil];

		if(nameoffset!=-1) [resource setObject:[NSNumber numberWithInt:nameoffset] forKey:@"NameOffset"];

		[dict setObject:resource forKey:key];
	}
	return dict;
}

@end