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