1/*
2
3  RarArchive.m
4  Zipper
5
6  Copyright (C) 2012 Free Software Foundation, Inc
7
8  Authors:
9
10  This application is free software; you can redistribute it and/or modify it
11  under the terms of the GNU General Public License as published by the Free
12  Software Foundation; either version 2 of the License, or (at your option)
13  any later version.
14
15  This program is distributed in the hope that it will be useful, but
16  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  or FITNESS FOR A PARTICULAR PURPOSE.
18  See the GNU General Public License for more details
19
20 */
21
22#import <Foundation/Foundation.h>
23#import "RarArchive.h"
24#import "FileInfo.h"
25#import "NSString+Custom.h"
26#import "Preferences.h"
27#import "NSArray+Custom.h"
28#import "common.h"
29
30static NSData *_magicBytes;
31
32@interface RarArchive (PrivateAPI)
33- (NSData *)dataByRunningRar;
34@end
35
36@implementation RarArchive : Archive
37
38/**
39 * register our supported file extensions with our superclass.
40 */
41+ (void)initialize
42{
43	// rar files start with 'R a r !'
44	char rarBytes[] = { 'R', 'a', 'r', '!' };
45	_magicBytes = [[NSData dataWithBytes:rarBytes length:4] retain];
46
47	[self registerFileExtension:@"rar" forArchiveClass:self];
48}
49
50+ (NSString *)unarchiveExecutable
51{
52	return [Preferences rarExecutable];
53}
54
55/**
56 * rar archives <em>do</em> contain info about compression ratio.
57 */
58+ (BOOL)hasRatio;
59{
60	return YES;
61}
62
63+ (ArchiveType)archiveType
64{
65	return RAR;
66}
67
68+ (NSData *)magicBytes
69{
70	return _magicBytes;
71}
72
73//------------------------------------------------------------------------------
74// expanding the archive
75//------------------------------------------------------------------------------
76- (int)expandFiles:(NSArray *)files withPathInfo:(BOOL)usePathInfo toPath:(NSString *)path
77{
78	FileInfo *fileInfo;
79	NSMutableArray *args;
80
81	args = [NSMutableArray array];
82	if (usePathInfo)
83	{
84		[args addObject:@"x"];
85	}
86	else
87	{
88		[args addObject:@"e"];
89	}
90
91	// protect against archives and files starting with -
92	[args addObject:@"--"];
93
94	[args addObject:[self path]];
95
96	if (files != nil)
97	{
98		NSEnumerator *cursor = [files objectEnumerator];
99		while ((fileInfo = [cursor nextObject]) != nil)
100		{
101			[args addObject:[fileInfo fullPath]];
102		}
103	}
104
105	// destination dir
106	[args addObject:path];
107	return [self runUnarchiverWithArguments:args];
108}
109
110- (NSArray *)listContents
111{
112	NSUInteger lineCount, i;
113	NSString *path = nil;
114
115    NSMutableArray *results = [NSMutableArray array];
116    NSData *data = [self dataByRunningRar];
117    NSString *string = [[[NSString alloc] initWithData:data
118		encoding:NSASCIIStringEncoding] autorelease];
119    NSArray *lines = [string componentsSeparatedByString:@"\n"];
120
121    // take out first 9 lines (header) and last 3 lines (footer)
122    lines = [lines subarrayWithRange:NSMakeRange(8, [lines count] - 8)];
123    lines = [lines subarrayWithRange:NSMakeRange(0, [lines count] - 4)];
124
125	lineCount = [lines count];
126	for (i = 0; i < lineCount; i++)
127	{
128        NSString *line = nil;
129
130		line = [lines objectAtIndex:i];
131		if ((i % 2) == 0)
132		{
133			path = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
134		}
135		else
136		{
137			NSArray *components;
138			NSString *date, *ratio;
139	        int length;
140			NSCalendarDate *calendarDate;
141			FileInfo *info;
142
143			components = [[line componentsSeparatedByString:@" "] arrayByRemovingEmptyStrings];
144			// continue only for non-directory entries
145			if ([[components objectAtIndex:5] hasPrefix:@"d"] == NO)
146			{
147				length = [[components objectAtIndex:0] intValue];
148				ratio = [components objectAtIndex:2];
149
150				date = [components objectAtIndex:3];
151				date = [NSString stringWithFormat:@"%@ %@", date, [components objectAtIndex:4]];
152        		calendarDate = [NSCalendarDate dateWithString:date
153					calendarFormat:@"%d-%m-%y %H:%M"];
154
155				info = [FileInfo newWithPath:path date:calendarDate
156					size:[NSNumber numberWithInt:length] ratio:ratio];
157	        	[results addObject:info];
158			}
159		}
160	}
161    return results;
162}
163
164//------------------------------------------------------------------------------
165// private API
166//------------------------------------------------------------------------------
167- (NSData *)dataByRunningRar
168{
169	// Args for rar:
170	// v	view contents of archive
171	// -c-	suppress archive comment
172
173	NSArray *args = [NSArray arrayWithObjects:@"v", @"-c-", @"--", [self path], nil];
174	return [self dataByRunningUnachiverWithArguments:args];
175}
176
177@end
178