xref: /haiku/src/apps/expander/ExpanderRules.cpp (revision 579f1dbca962a2a03df54f69fdc6e9423f91f20e)
1 /*
2  * Copyright 2004-2006, Jérôme Duval. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "ExpanderRules.h"
8 
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 
13 #include <FindDirectory.h>
14 #include <NodeInfo.h>
15 #include <Path.h>
16 
17 #include <compat/sys/stat.h>
18 
19 #include "ExpanderSettings.h"
20 
21 
22 static const char* const kRulesDirectoryPath = "expander/rules";
23 static const char* const kUserRulesFileName = "rules";
24 
25 
26 // #pragma mark - ExpanderRule
27 
28 
29 ExpanderRule::ExpanderRule(const char* mimetype,
30 	const BString& filenameExtension, const BString& listingCmd,
31 	const BString& expandCmd)
32 	:
33 	fMimeType(mimetype),
34 	fFilenameExtension(filenameExtension),
35 	fListingCmd(listingCmd),
36 	fExpandCmd(expandCmd)
37 {
38 }
39 
40 
41 // #pragma mark - ExpanderRules
42 
43 
44 ExpanderRules::ExpanderRules()
45 {
46 	// Load the rules files first, then add the built-in rules. This way the
47 	// built-ins can be overridden, if the files contain matching rules.
48 	_LoadRulesFiles();
49 
50 	_AddRule("", ".tar.gz", "tar -ztvf %s", "tar -zxf %s");
51 	_AddRule("", ".tar.bz2", "tar -jtvf %s", "tar -jxf %s");
52 	_AddRule("", ".tar.Z", "tar -Ztvf %s", "tar -Zxf %s");
53 	_AddRule("", ".tgz", "tar -ztvf %s", "tar -zxf %s");
54 	_AddRule("application/x-tar", ".tar", "tar -tvf %s", "tar -xf %s");
55 	_AddRule("application/x-gzip", ".gz", "echo %s | sed 's/.gz$//g'",
56 		"gunzip -c %s > `echo %s | sed 's/.gz$//g'`");
57 	_AddRule("application/x-bzip2", ".bz2", "echo %s | sed 's/.bz2$//g'",
58 		"bunzip2 -k %s");
59 	_AddRule("application/zip", ".zip", "unzip -l %s", "unzip -o %s");
60 	_AddRule("application/x-zip-compressed", ".zip", "unzip -l %s",
61 		"unzip -o %s");
62 	_AddRule("application/x-rar", ".rar", "unrar v %s", "unrar x -y %s");
63 	_AddRule("application/x-vnd.haiku-package", ".hpkg", "package list %s",
64 		"package extract %s");
65 }
66 
67 
68 ExpanderRules::~ExpanderRules()
69 {
70 	void* item;
71 	while ((item = fList.RemoveItem((int32)0)))
72 		delete (ExpanderRule*)item;
73 }
74 
75 
76 ExpanderRule*
77 ExpanderRules::MatchingRule(BString& fileName, const char* filetype)
78 {
79 	int32 count = fList.CountItems();
80 	int32 length = fileName.Length();
81 	for (int32 i = 0; i < count; i++) {
82 		ExpanderRule* rule = (ExpanderRule*)fList.ItemAt(i);
83 		if (rule->MimeType().IsValid() && rule->MimeType() == filetype)
84 			return rule;
85 		int32 extPosition = fileName.FindLast(rule->FilenameExtension());
86 		if (extPosition != -1
87 			&& extPosition == (length - rule->FilenameExtension().Length()))
88 			return rule;
89 	}
90 	return NULL;
91 }
92 
93 
94 ExpanderRule*
95 ExpanderRules::MatchingRule(const entry_ref* ref)
96 {
97 	BEntry entry(ref, true);
98 	BNode node(&entry);
99 	BNodeInfo nodeInfo(&node);
100 	char type[B_MIME_TYPE_LENGTH];
101 	nodeInfo.GetType(type);
102 	BString fileName(ref->name);
103 	return MatchingRule(fileName, type);
104 }
105 
106 
107 void
108 ExpanderRules::_LoadRulesFiles()
109 {
110 	// load the user editable rules first
111 	BPath path;
112 	if (ExpanderSettings::GetSettingsDirectoryPath(path) == B_OK
113 		&& path.Append(kUserRulesFileName) == B_OK) {
114 		_LoadRulesFile(path.Path());
115 	}
116 
117 	// load the rules files from the data directories
118 	const directory_which kDirectories[] = {
119 		B_USER_NONPACKAGED_DATA_DIRECTORY,
120 		B_USER_DATA_DIRECTORY,
121 		B_COMMON_NONPACKAGED_DATA_DIRECTORY,
122 		B_COMMON_DATA_DIRECTORY,
123 		B_SYSTEM_DATA_DIRECTORY
124 	};
125 
126 	for (size_t i = 0; i < sizeof(kDirectories) / sizeof(kDirectories[0]);
127 		i++) {
128 		BDirectory directory;
129 		if (find_directory(kDirectories[i], &path) != B_OK
130 			|| path.Append(kRulesDirectoryPath) != B_OK
131 			|| directory.SetTo(path.Path()) != B_OK) {
132 			continue;
133 		}
134 
135 		entry_ref entry;
136 		while (directory.GetNextRef(&entry) == B_OK) {
137 			BPath filePath;
138 			if (filePath.SetTo(path.Path(), entry.name) == B_OK)
139 				_LoadRulesFile(filePath.Path());
140 		}
141 	}
142 }
143 
144 
145 void
146 ExpanderRules::_LoadRulesFile(const char* path)
147 {
148 	FILE* file = fopen(path, "r");
149 	if (file == NULL)
150 		return;
151 
152 	char buffer[1024];
153 	BString strings[4];
154 	while (fgets(buffer, 1024 - 1, file) != NULL) {
155 		int32 i = 0, j = 0;
156 		int32 firstQuote = -1;
157 		while (buffer[i] != '#' && buffer[i] != '\n' && j < 4) {
158 			if ((j == 0 || j > 1) && buffer[i] == '"') {
159 				if (firstQuote >= 0) {
160 					strings[j++].SetTo(&buffer[firstQuote+1],
161 						i - firstQuote - 1);
162 					firstQuote = -1;
163 				} else
164 					firstQuote = i;
165 			} else if (j == 1 && (buffer[i] == ' ' || buffer[i] == '\t')) {
166 				if (firstQuote >= 0) {
167 					if (firstQuote + 1 != i) {
168 						strings[j++].SetTo(&buffer[firstQuote+1],
169 							i - firstQuote - 1);
170 						firstQuote = -1;
171 					} else
172 						firstQuote = i;
173 				} else
174 					firstQuote = i;
175 			}
176 			i++;
177 		}
178 		if (j == 4)
179 			_AddRule(strings[0], strings[1], strings[2], strings[3]);
180 	}
181 
182 	fclose(file);
183 }
184 
185 
186 bool
187 ExpanderRules::_AddRule(const char* mimetype, const BString& filenameExtension,
188 	const BString& listingCmd, const BString& expandCmd)
189 {
190 	ExpanderRule* rule = new(std::nothrow) ExpanderRule(mimetype,
191 		filenameExtension, listingCmd, expandCmd);
192 	if (rule == NULL || !fList.AddItem(rule)) {
193 		delete rule;
194 		return false;
195 	}
196 
197 	return true;
198 }
199 
200 
201 // #pragma mark - RuleRefFilter
202 
203 
204 RuleRefFilter::RuleRefFilter(ExpanderRules& rules)
205 	: BRefFilter(),
206 	fRules(rules)
207 {
208 }
209 
210 
211 bool
212 RuleRefFilter::Filter(const entry_ref* ref, BNode* node, struct stat_beos* st,
213 	const char* filetype)
214 {
215 	if (node->IsDirectory() || node->IsSymLink())
216 		return true;
217 
218 	BString fileName(ref->name);
219 	return fRules.MatchingRule(fileName, filetype) != NULL;
220 }
221