xref: /haiku/src/apps/expander/ExpanderRules.cpp (revision 4a3268e14fff4dd5a456d824b48ce6503368e4c1)
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_SYSTEM_NONPACKAGED_DATA_DIRECTORY,
122 		B_SYSTEM_DATA_DIRECTORY
123 	};
124 
125 	for (size_t i = 0; i < sizeof(kDirectories) / sizeof(kDirectories[0]);
126 		i++) {
127 		BDirectory directory;
128 		if (find_directory(kDirectories[i], &path) != B_OK
129 			|| path.Append(kRulesDirectoryPath) != B_OK
130 			|| directory.SetTo(path.Path()) != B_OK) {
131 			continue;
132 		}
133 
134 		entry_ref entry;
135 		while (directory.GetNextRef(&entry) == B_OK) {
136 			BPath filePath;
137 			if (filePath.SetTo(path.Path(), entry.name) == B_OK)
138 				_LoadRulesFile(filePath.Path());
139 		}
140 	}
141 }
142 
143 
144 void
145 ExpanderRules::_LoadRulesFile(const char* path)
146 {
147 	FILE* file = fopen(path, "r");
148 	if (file == NULL)
149 		return;
150 
151 	char buffer[1024];
152 	BString strings[4];
153 	while (fgets(buffer, 1024 - 1, file) != NULL) {
154 		int32 i = 0, j = 0;
155 		int32 firstQuote = -1;
156 		while (buffer[i] != '#' && buffer[i] != '\n' && j < 4) {
157 			if ((j == 0 || j > 1) && buffer[i] == '"') {
158 				if (firstQuote >= 0) {
159 					strings[j++].SetTo(&buffer[firstQuote+1],
160 						i - firstQuote - 1);
161 					firstQuote = -1;
162 				} else
163 					firstQuote = i;
164 			} else if (j == 1 && (buffer[i] == ' ' || buffer[i] == '\t')) {
165 				if (firstQuote >= 0) {
166 					if (firstQuote + 1 != i) {
167 						strings[j++].SetTo(&buffer[firstQuote+1],
168 							i - firstQuote - 1);
169 						firstQuote = -1;
170 					} else
171 						firstQuote = i;
172 				} else
173 					firstQuote = i;
174 			}
175 			i++;
176 		}
177 		if (j == 4)
178 			_AddRule(strings[0], strings[1], strings[2], strings[3]);
179 	}
180 
181 	fclose(file);
182 }
183 
184 
185 bool
186 ExpanderRules::_AddRule(const char* mimetype, const BString& filenameExtension,
187 	const BString& listingCmd, const BString& expandCmd)
188 {
189 	ExpanderRule* rule = new(std::nothrow) ExpanderRule(mimetype,
190 		filenameExtension, listingCmd, expandCmd);
191 	if (rule == NULL || !fList.AddItem(rule)) {
192 		delete rule;
193 		return false;
194 	}
195 
196 	return true;
197 }
198 
199 
200 // #pragma mark - RuleRefFilter
201 
202 
203 RuleRefFilter::RuleRefFilter(ExpanderRules& rules)
204 	: BRefFilter(),
205 	fRules(rules)
206 {
207 }
208 
209 
210 bool
211 RuleRefFilter::Filter(const entry_ref* ref, BNode* node, struct stat_beos* st,
212 	const char* filetype)
213 {
214 	if (node->IsDirectory() || node->IsSymLink())
215 		return true;
216 
217 	BString fileName(ref->name);
218 	return fRules.MatchingRule(fileName, filetype) != NULL;
219 }
220