xref: /haiku/src/apps/expander/ExpanderRules.cpp (revision 22440f4105cafc95cc1d49f9bc65bb395c527d86)
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& listingCommand,
31 	const BString& expandCommand)
32 	:
33 	fMimeType(mimeType),
34 	fFilenameExtension(filenameExtension),
35 	fListingCmd(listingCommand),
36 	fExpandCmd(expandCommand)
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 
86 		int32 extensionPosition = fileName.FindLast(rule->FilenameExtension());
87 		if (extensionPosition != -1 && extensionPosition
88 				== (length - rule->FilenameExtension().Length())) {
89 			return rule;
90 		}
91 	}
92 
93 	return NULL;
94 }
95 
96 
97 ExpanderRule*
98 ExpanderRules::MatchingRule(const entry_ref* ref)
99 {
100 	BEntry entry(ref, true);
101 	BNode node(&entry);
102 	BNodeInfo nodeInfo(&node);
103 	char type[B_MIME_TYPE_LENGTH];
104 	nodeInfo.GetType(type);
105 	BString fileName(ref->name);
106 
107 	return MatchingRule(fileName, type);
108 }
109 
110 
111 void
112 ExpanderRules::_LoadRulesFiles()
113 {
114 	// load the user editable rules first
115 	BPath path;
116 	if (ExpanderSettings::GetSettingsDirectoryPath(path) == B_OK
117 		&& path.Append(kUserRulesFileName) == B_OK) {
118 		_LoadRulesFile(path.Path());
119 	}
120 
121 	// load the rules files from the data directories
122 	const directory_which kDirectories[] = {
123 		B_USER_NONPACKAGED_DATA_DIRECTORY,
124 		B_USER_DATA_DIRECTORY,
125 		B_SYSTEM_NONPACKAGED_DATA_DIRECTORY,
126 		B_SYSTEM_DATA_DIRECTORY
127 	};
128 
129 	for (size_t i = 0; i < sizeof(kDirectories) / sizeof(kDirectories[0]);
130 			i++) {
131 		BDirectory directory;
132 		if (find_directory(kDirectories[i], &path) != B_OK
133 			|| path.Append(kRulesDirectoryPath) != B_OK
134 			|| directory.SetTo(path.Path()) != B_OK) {
135 			continue;
136 		}
137 
138 		entry_ref entry;
139 		while (directory.GetNextRef(&entry) == B_OK) {
140 			BPath filePath;
141 			if (filePath.SetTo(path.Path(), entry.name) == B_OK)
142 				_LoadRulesFile(filePath.Path());
143 		}
144 	}
145 }
146 
147 
148 void
149 ExpanderRules::_LoadRulesFile(const char* path)
150 {
151 	FILE* file = fopen(path, "r");
152 	if (file == NULL)
153 		return;
154 
155 	char buffer[1024];
156 	BString strings[4];
157 	while (fgets(buffer, 1024 - 1, file) != NULL) {
158 		int32 i = 0, j = 0;
159 		int32 firstQuote = -1;
160 		while (buffer[i] != '#' && buffer[i] != '\n' && j < 4) {
161 			if ((j == 0 || j > 1) && buffer[i] == '"') {
162 				if (firstQuote >= 0) {
163 					strings[j++].SetTo(&buffer[firstQuote+1],
164 						i - firstQuote - 1);
165 					firstQuote = -1;
166 				} else
167 					firstQuote = i;
168 			} else if (j == 1 && (buffer[i] == ' ' || buffer[i] == '\t')) {
169 				if (firstQuote >= 0) {
170 					if (firstQuote + 1 != i) {
171 						strings[j++].SetTo(&buffer[firstQuote+1],
172 							i - firstQuote - 1);
173 						firstQuote = -1;
174 					} else
175 						firstQuote = i;
176 				} else
177 					firstQuote = i;
178 			}
179 			i++;
180 		}
181 
182 		if (j == 4)
183 			_AddRule(strings[0], strings[1], strings[2], strings[3]);
184 	}
185 
186 	fclose(file);
187 }
188 
189 
190 bool
191 ExpanderRules::_AddRule(const char* mimeType, const BString& filenameExtension,
192 	const BString& listingCommand, const BString& expandCommand)
193 {
194 	ExpanderRule* rule = new(std::nothrow) ExpanderRule(mimeType,
195 		filenameExtension, listingCommand, expandCommand);
196 	if (rule == NULL)
197 		return false;
198 
199 	if (!fList.AddItem(rule)) {
200 		delete rule;
201 		return false;
202 	}
203 
204 	return true;
205 }
206 
207 
208 // #pragma mark - RuleRefFilter
209 
210 
211 RuleRefFilter::RuleRefFilter(ExpanderRules& rules)
212 	:
213 	BRefFilter(),
214 	fRules(rules)
215 {
216 }
217 
218 
219 bool
220 RuleRefFilter::Filter(const entry_ref* ref, BNode* node, struct stat_beos* stat,
221 	const char* filetype)
222 {
223 	if (node->IsDirectory() || node->IsSymLink())
224 		return true;
225 
226 	BString fileName(ref->name);
227 	return fRules.MatchingRule(fileName, filetype) != NULL;
228 }
229