haiku/src/apps/expander/ExpanderRules.cpp

229 lines
5.3 KiB
C++

/*
* Copyright 2004-2006, Jérôme Duval. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "ExpanderRules.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <FindDirectory.h>
#include <NodeInfo.h>
#include <Path.h>
#include <compat/sys/stat.h>
#include "ExpanderSettings.h"
static const char* const kRulesDirectoryPath = "expander/rules";
static const char* const kUserRulesFileName = "rules";
// #pragma mark - ExpanderRule
ExpanderRule::ExpanderRule(const char* mimeType,
const BString& filenameExtension, const BString& listingCommand,
const BString& expandCommand)
:
fMimeType(mimeType),
fFilenameExtension(filenameExtension),
fListingCmd(listingCommand),
fExpandCmd(expandCommand)
{
}
// #pragma mark - ExpanderRules
ExpanderRules::ExpanderRules()
{
// Load the rules files first, then add the built-in rules. This way the
// built-ins can be overridden, if the files contain matching rules.
_LoadRulesFiles();
_AddRule("", ".tar.gz", "tar -ztvf %s", "tar -zxf %s");
_AddRule("", ".tar.bz2", "tar -jtvf %s", "tar -jxf %s");
_AddRule("", ".tar.Z", "tar -Ztvf %s", "tar -Zxf %s");
_AddRule("", ".tgz", "tar -ztvf %s", "tar -zxf %s");
_AddRule("application/x-tar", ".tar", "tar -tvf %s", "tar -xf %s");
_AddRule("application/x-gzip", ".gz", "echo %s | sed 's/.gz$//g'",
"gunzip -c %s > `echo %s | sed 's/.gz$//g'`");
_AddRule("application/x-bzip2", ".bz2", "echo %s | sed 's/.bz2$//g'",
"bunzip2 -k %s");
_AddRule("application/zip", ".zip", "unzip -l %s", "unzip -o %s");
_AddRule("application/x-zip-compressed", ".zip", "unzip -l %s",
"unzip -o %s");
_AddRule("application/x-rar", ".rar", "unrar v %s", "unrar x -y %s");
_AddRule("application/x-vnd.haiku-package", ".hpkg", "package list %s",
"package extract %s");
}
ExpanderRules::~ExpanderRules()
{
void* item;
while ((item = fList.RemoveItem((int32)0)))
delete (ExpanderRule*)item;
}
ExpanderRule*
ExpanderRules::MatchingRule(BString& fileName, const char* filetype)
{
int32 count = fList.CountItems();
int32 length = fileName.Length();
for (int32 i = 0; i < count; i++) {
ExpanderRule* rule = (ExpanderRule*)fList.ItemAt(i);
if (rule->MimeType().IsValid() && rule->MimeType() == filetype)
return rule;
int32 extensionPosition = fileName.FindLast(rule->FilenameExtension());
if (extensionPosition != -1 && extensionPosition
== (length - rule->FilenameExtension().Length())) {
return rule;
}
}
return NULL;
}
ExpanderRule*
ExpanderRules::MatchingRule(const entry_ref* ref)
{
BEntry entry(ref, true);
BNode node(&entry);
BNodeInfo nodeInfo(&node);
char type[B_MIME_TYPE_LENGTH];
nodeInfo.GetType(type);
BString fileName(ref->name);
return MatchingRule(fileName, type);
}
void
ExpanderRules::_LoadRulesFiles()
{
// load the user editable rules first
BPath path;
if (ExpanderSettings::GetSettingsDirectoryPath(path) == B_OK
&& path.Append(kUserRulesFileName) == B_OK) {
_LoadRulesFile(path.Path());
}
// load the rules files from the data directories
const directory_which kDirectories[] = {
B_USER_NONPACKAGED_DATA_DIRECTORY,
B_USER_DATA_DIRECTORY,
B_SYSTEM_NONPACKAGED_DATA_DIRECTORY,
B_SYSTEM_DATA_DIRECTORY
};
for (size_t i = 0; i < sizeof(kDirectories) / sizeof(kDirectories[0]);
i++) {
BDirectory directory;
if (find_directory(kDirectories[i], &path) != B_OK
|| path.Append(kRulesDirectoryPath) != B_OK
|| directory.SetTo(path.Path()) != B_OK) {
continue;
}
entry_ref entry;
while (directory.GetNextRef(&entry) == B_OK) {
BPath filePath;
if (filePath.SetTo(path.Path(), entry.name) == B_OK)
_LoadRulesFile(filePath.Path());
}
}
}
void
ExpanderRules::_LoadRulesFile(const char* path)
{
FILE* file = fopen(path, "r");
if (file == NULL)
return;
char buffer[1024];
BString strings[4];
while (fgets(buffer, 1024 - 1, file) != NULL) {
int32 i = 0, j = 0;
int32 firstQuote = -1;
while (buffer[i] != '#' && buffer[i] != '\n' && j < 4) {
if ((j == 0 || j > 1) && buffer[i] == '"') {
if (firstQuote >= 0) {
strings[j++].SetTo(&buffer[firstQuote+1],
i - firstQuote - 1);
firstQuote = -1;
} else
firstQuote = i;
} else if (j == 1 && (buffer[i] == ' ' || buffer[i] == '\t')) {
if (firstQuote >= 0) {
if (firstQuote + 1 != i) {
strings[j++].SetTo(&buffer[firstQuote+1],
i - firstQuote - 1);
firstQuote = -1;
} else
firstQuote = i;
} else
firstQuote = i;
}
i++;
}
if (j == 4)
_AddRule(strings[0], strings[1], strings[2], strings[3]);
}
fclose(file);
}
bool
ExpanderRules::_AddRule(const char* mimeType, const BString& filenameExtension,
const BString& listingCommand, const BString& expandCommand)
{
ExpanderRule* rule = new(std::nothrow) ExpanderRule(mimeType,
filenameExtension, listingCommand, expandCommand);
if (rule == NULL)
return false;
if (!fList.AddItem(rule)) {
delete rule;
return false;
}
return true;
}
// #pragma mark - RuleRefFilter
RuleRefFilter::RuleRefFilter(ExpanderRules& rules)
:
BRefFilter(),
fRules(rules)
{
}
bool
RuleRefFilter::Filter(const entry_ref* ref, BNode* node, struct stat_beos* stat,
const char* filetype)
{
if (node->IsDirectory() || node->IsSymLink())
return true;
BString fileName(ref->name);
return fRules.MatchingRule(fileName, filetype) != NULL;
}