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