-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDataLibraryCreator.m
More file actions
282 lines (248 loc) · 8 KB
/
DataLibraryCreator.m
File metadata and controls
282 lines (248 loc) · 8 KB
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//
// Created by Karsten Kusche on 27.09.10.
// Copyright 2010 Briksoftware.com. All rights reserved.
//
/*
The main work is done in:
- (void)convertFrom: (NSString*)source to:(NSString*)target
the idea is to compile an dummy Assembler file into an object file, link that into a static library
the static library will have a placeholder inside which consists of 0x33s.
The placeholder is replaced by the contents of the <source> file and the resulting file is stored in <target>
There are two globals defined in the Assembler file:
"name" and "name_size", where "name" is what you pass to the tool in the -n switch
In your c project you can then link to the static library and declare the data via "extern char* name;" and "extern long name_size;"
*/
#import "DataLibraryCreator.h"
#import "DDCliUtil.h"
#import "DDGetoptLongParser.h"
static unsigned char spaceByte = 0x33;
@implementation DataLibraryCreator
- (NSString*)tempFolder
{
static NSString *tempDirectoryPath = nil;
if (tempDirectoryPath == nil)
{
NSString *tempDirectoryTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"DataCreator.XXXXXX"];
const char *tempDirectoryTemplateCString = [tempDirectoryTemplate fileSystemRepresentation];
char *tempDirectoryNameCString = (char *)malloc(strlen(tempDirectoryTemplateCString) + 1);
strcpy(tempDirectoryNameCString, tempDirectoryTemplateCString);
char *result = mkdtemp(tempDirectoryNameCString);
if (!result)
{
return nil;
}
tempDirectoryPath = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempDirectoryNameCString
length:strlen(result)];
free(tempDirectoryNameCString);
// NSLog(@"temps at: %@",tempDirectoryPath);
}
return tempDirectoryPath;
}
- (void)showError:(NSString*)errorMessage
{
ddfprintf(stderr, @"error: %@\n\
\n\
parameter: \n\
-n name -- symbol name -- will create a <name> and <name_size> variable\n\
-s file -- source file\n\
[-o file] -- out file -- defaults to stdout\n\
[-a arch] -- architecture -- defaults to current arch\n",errorMessage);
[[NSFileManager defaultManager] removeItemAtPath:[self tempFolder] error:nil];
exit(EXIT_FAILURE);
}
- (NSString*)pathForFile:(NSString*) path withExtention:(NSString*)extention
{
// NSString* folder = [path stringByDeletingLastPathComponent];
NSString* file = [[path lastPathComponent] stringByDeletingPathExtension];
return [[[self tempFolder] stringByAppendingPathComponent:file]stringByAppendingPathExtension:extention];
}
- (NSString*)createAsFile: (NSString*)path forSize:(NSUInteger)size
{
NSString* asFile = [self pathForFile:path withExtention:@"s"];
NSString* sizeString = [[NSNumber numberWithUnsignedInteger:size] stringValue];
NSString* contents = [NSString stringWithFormat:@".section __DATA,__data\n\
_%@_holder: \n\
.space %@,%i\n\
.globl _%@\n\
_%@:\n\
.quad _%@_holder\n\
.long 0xfeedface\n\
.globl _%@_size\n\
_%@_size:\n\
.long %@\n",symbolName,sizeString,spaceByte,symbolName,symbolName,symbolName,symbolName,symbolName,sizeString];
if ([contents writeToFile:asFile atomically:YES encoding:NSUTF8StringEncoding error:nil])
{
return asFile;
}
return nil;
}
- (BOOL)executeScript:(NSString*)script
{
const char* command;
command = [script UTF8String];
return system(command) != -1;
}
- (NSString*)assembleFile:(NSString*)asFile
{
NSString* archString = @"";
if (arch)
{
archString = [NSString stringWithFormat:@"-arch %@",arch];
}
NSString* oFile = [self pathForFile:asFile withExtention:@"o"];
NSString* script = [NSString stringWithFormat:@"as %@ %@ -o %@",archString,asFile,oFile];
if ([self executeScript:script])
{
return oFile;
}
return nil;
}
- (NSString*)linkFile:(NSString*)oFile
{
NSString* aFile = [self pathForFile:oFile withExtention:@"a"];
if ([self executeScript:[NSString stringWithFormat:@"libtool %@ -o %@",oFile, aFile]])
{
return aFile;
}
return nil;
}
- (void)copy:(long) numBytes bytesFrom: (FILE*)fromFile to: (FILE*)toFile
{
char smallBuffer = '\0';
int smallBytes = numBytes % sizeof(long);
long bigBuffer = 0;
long bigBytes = (numBytes - smallBytes) / sizeof(long);
long i;
for (i = 0; feof(fromFile) == NO && i < smallBytes; i++)
{
fread(&smallBuffer, 1, 1, fromFile);
fwrite(&smallBuffer, 1, 1, toFile);
}
for (i = 0; feof(fromFile) == NO && i < bigBytes; i++)
{
long numRead = fread(&bigBuffer,1,sizeof(long),fromFile);
fwrite(&bigBuffer,1,numRead,toFile);
}
}
- (BOOL)patchFile:(NSString*)aFileName withContentsFrom:(NSString*)sourceFile to:(NSString*)target
{
FILE* aFile = fopen([aFileName fileSystemRepresentation],"r");
FILE* dataFile = fopen([sourceFile fileSystemRepresentation],"r");
FILE* targetFile = fopen([target fileSystemRepresentation],"w");
// get dataFile's size
fseek(dataFile, 0, SEEK_END);
long dataFileSize = ftell(dataFile);
rewind(dataFile);
// find the placeholder in aFile.
long size = 0;
long start = 0;
while (feof(aFile) == NO && size != dataFileSize)
{
unsigned char byte = '\0';
// search until the start of the placeholder
while (feof(aFile) == NO && byte != spaceByte)
{
fread(&byte, sizeof(byte), 1, aFile);
}
start = ftell(aFile) - 1;
// search until the end of the placeholder
while (feof(aFile) == NO && byte == spaceByte)
{
fread(&byte, sizeof(byte), 1, aFile);
}
size = (ftell(aFile) - 1) - start;
}
if (feof(aFile) == YES)
{
[self showError:@"can't find placeholder in file"];
return NO;
}
rewind(aFile);
[self copy: start bytesFrom: aFile to: targetFile];
[self copy: size bytesFrom: dataFile to: targetFile];
fseek(aFile, size, SEEK_CUR);
[self copy: LONG_MAX bytesFrom: aFile to: targetFile];
fclose(aFile);
fclose(dataFile);
fclose(targetFile);
return YES;
}
- (void)convertFrom: (NSString*)source to:(NSString*)target
{
NSDictionary* fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:source error:nil];
NSUInteger fileSize = [[fileAttributes objectForKey:NSFileSize] unsignedIntegerValue];
if (!fileSize) {[self showError:@"invalid input"]; return;}
NSString* asFile = [self createAsFile:target forSize:fileSize];
if (!asFile) {[self showError:@"can't create .s file"]; return;}
NSString* oFile = [self assembleFile: asFile];
if (!oFile) { [self showError: @"can't create .o file"]; return;}
NSString* aFile = [self linkFile: oFile];
if (!aFile) { [self showError: @"can't create .a file"]; return;}
BOOL couldReplaceContents = [self patchFile: aFile withContentsFrom:source to:target];
if (!couldReplaceContents) {[self showError:@"can't replace contents"]; return;}
}
- (int)application:(DDCliApplication *)app
runWithArguments:(NSArray *)arguments
{
NSString* sourceFile = nil;
NSString* output = @"/dev/stdout";
if (symbolName == nil)
{
[self showError:@"no symbol name provided"];
}
if (inFile) {
sourceFile = [inFile stringByExpandingTildeInPath];
}
else
{
[self showError:@"no imput file provided"];
}
if (arch == nil) {
SInt32 gestaltValue;
Gestalt(gestaltSysArchitecture, &gestaltValue);
if (gestaltValue == gestaltPowerPC)
{
arch = @"ppc";
}
else
{
if (sizeof(NSInteger) == sizeof(int))
{
arch = @"i386";
}
else
{
arch = @"x86_64";
}
}
}
if (outFile)
{
output = [outFile stringByExpandingTildeInPath];
}
[self convertFrom: sourceFile to: output];
return EXIT_SUCCESS;
}
- (void)application:(DDCliApplication *)app
willParseOptions:(DDGetoptLongParser *)optionsParser
{
outFile = nil;
inFile = nil;
arch = nil;
DDGetoptOption optionTable[] =
{
// Long Short Argument options
{@"inFile", 's', DDGetoptRequiredArgument},
{@"outFile", 'o', DDGetoptRequiredArgument},
{@"symbolName", 'n', DDGetoptRequiredArgument},
{@"verbose", 'v', DDGetoptNoArgument},
{@"arch", 'a', DDGetoptRequiredArgument},
{nil, 0, 0}
};
[optionsParser addOptionsFromTable:optionTable];
}
@end
int main(int argc, char* argv[])
{
return DDCliAppRunWithDefaultClass();
}