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