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
|
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
|
-
+
-
+
|
#import "OFStream.h"
#import "OFString.h"
#import "OFOutOfRangeException.h"
static OFString *
stringFromBuffer(const unsigned char *buffer, size_t length,
of_string_encoding_t encoding)
OFStringEncoding encoding)
{
for (size_t i = 0; i < length; i++)
if (buffer[i] == '\0')
length = i;
return [OFString stringWithCString: (const char *)buffer
encoding: encoding
length: length];
}
static void
stringToBuffer(unsigned char *buffer, OFString *string, size_t length,
of_string_encoding_t encoding)
OFStringEncoding encoding)
{
size_t cStringLength = [string cStringLengthWithEncoding: encoding];
if (cStringLength > length)
@throw [OFOutOfRangeException exception];
memcpy(buffer, [string cStringWithEncoding: encoding], cStringLength);
|
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
|
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
|
-
+
-
+
-
+
-
+
|
return 0;
if (buffer[0] == 0x80) {
for (size_t i = 1; i < length; i++)
value = (value << 8) | buffer[i];
} else
value = [stringFromBuffer(buffer, length,
OF_STRING_ENCODING_ASCII) unsignedLongLongValueWithBase: 8];
OFStringEncodingASCII) unsignedLongLongValueWithBase: 8];
if (value > max)
@throw [OFOutOfRangeException exception];
return value;
}
@implementation OFTarArchiveEntry
+ (instancetype)entryWithFileName: (OFString *)fileName
{
return [[[self alloc] initWithFileName: fileName] autorelease];
}
- (instancetype)init
{
OF_INVALID_INIT_METHOD
}
- (instancetype)of_initWithHeader: (unsigned char [512])header
encoding: (of_string_encoding_t)encoding
encoding: (OFStringEncoding)encoding
{
self = [super init];
@try {
void *pool = objc_autoreleasePoolPush();
OFString *targetFileName;
_fileName = [stringFromBuffer(header, 100, encoding) copy];
_mode = (unsigned long)octalValueFromBuffer(
header + 100, 8, ULONG_MAX);
_UID = (unsigned long)octalValueFromBuffer(
header + 108, 8, ULONG_MAX);
_GID = (unsigned long)octalValueFromBuffer(
header + 116, 8, ULONG_MAX);
_size = (unsigned long long)octalValueFromBuffer(
header + 124, 12, ULLONG_MAX);
_modificationDate = [[OFDate alloc]
initWithTimeIntervalSince1970:
(of_time_interval_t)octalValueFromBuffer(
(OFTimeInterval)octalValueFromBuffer(
header + 136, 12, ULLONG_MAX)];
_type = header[156];
targetFileName = stringFromBuffer(header + 157, 100, encoding);
if (targetFileName.length > 0)
_targetFileName = [targetFileName copy];
if (_type == '\0')
_type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE;
_type = OFTarArchiveEntryTypeFile;
if (memcmp(header + 257, "ustar\0" "00", 8) == 0) {
OFString *prefix;
_owner = [stringFromBuffer(header + 265, 32, encoding)
copy];
_group = [stringFromBuffer(header + 297, 32, encoding)
|
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
|
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
|
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
|
objc_autoreleasePoolPop(pool);
return [ret autorelease];
}
- (void)of_writeToStream: (OFStream *)stream
encoding: (of_string_encoding_t)encoding
encoding: (OFStringEncoding)encoding
{
unsigned char buffer[512];
unsigned long long modificationDate;
uint16_t checksum = 0;
stringToBuffer(buffer, _fileName, 100, encoding);
stringToBuffer(buffer + 100,
[OFString stringWithFormat: @"%06" PRIo16 " ", _mode], 8,
OF_STRING_ENCODING_ASCII);
OFStringEncodingASCII);
stringToBuffer(buffer + 108,
[OFString stringWithFormat: @"%06" PRIo16 " ", _UID], 8,
OF_STRING_ENCODING_ASCII);
OFStringEncodingASCII);
stringToBuffer(buffer + 116,
[OFString stringWithFormat: @"%06" PRIo16 " ", _GID], 8,
OF_STRING_ENCODING_ASCII);
OFStringEncodingASCII);
stringToBuffer(buffer + 124,
[OFString stringWithFormat: @"%011" PRIo64 " ", _size], 12,
OF_STRING_ENCODING_ASCII);
OFStringEncodingASCII);
modificationDate = _modificationDate.timeIntervalSince1970;
stringToBuffer(buffer + 136,
[OFString stringWithFormat: @"%011llo", modificationDate],
12, OF_STRING_ENCODING_ASCII);
12, OFStringEncodingASCII);
/*
* During checksumming, the checksum field is expected to be set to 8
* spaces.
*/
memset(buffer + 148, ' ', 8);
buffer[156] = _type;
stringToBuffer(buffer + 157, _targetFileName, 100, encoding);
/* ustar */
memcpy(buffer + 257, "ustar\0" "00", 8);
stringToBuffer(buffer + 265, _owner, 32, encoding);
stringToBuffer(buffer + 297, _group, 32, encoding);
stringToBuffer(buffer + 329,
[OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMajor], 8,
OF_STRING_ENCODING_ASCII);
OFStringEncodingASCII);
stringToBuffer(buffer + 337,
[OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMinor], 8,
OF_STRING_ENCODING_ASCII);
OFStringEncodingASCII);
memset(buffer + 345, '\0', 155 + 12);
/* Fill in the checksum */
for (size_t i = 0; i < 500; i++)
checksum += buffer[i];
stringToBuffer(buffer + 148,
[OFString stringWithFormat: @"%06" PRIo16, checksum], 7,
OF_STRING_ENCODING_ASCII);
OFStringEncodingASCII);
[stream writeBuffer: buffer
[stream writeBuffer: buffer length: sizeof(buffer)];
length: sizeof(buffer)];
}
@end
|