+ Added file-extension based mime type guessing

+ Added sniffer rule based mime type guessing
+ Added get_device_icon()
+ Added complete (synchronous, asynchronous; recursive,
  non-recursive; forcing, non-forcing; you name it we got it :-)
  update_mime_info() implementation.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1152 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Tyler Dauwalder 2002-09-24 05:36:03 +00:00
parent 743e936ee7
commit 1bd963b6c2
12 changed files with 891 additions and 101 deletions

View File

@ -145,10 +145,10 @@ public:
/* calls to ask the sniffer to identify the MIME type of a file or data in
memory */
static status_t GuessMimeType(const entry_ref *file, BMimeType *result);
static status_t GuessMimeType(const entry_ref *file, BMimeType *type);
static status_t GuessMimeType(const void *buffer, int32 length,
BMimeType *result);
static status_t GuessMimeType(const char *filename, BMimeType *result);
BMimeType *type);
static status_t GuessMimeType(const char *filename, BMimeType *type);
static status_t StartWatching(BMessenger target);
static status_t StopWatching(BMessenger target);
@ -201,6 +201,9 @@ private:
// status_t CloseFile() const;
status_t GetSupportedTypes(BMessage *types);
status_t SetSupportedTypes(const BMessage *types, bool fullSync = true);
static status_t GetAssociatedTypes(const char *extension, BMessage *types);
// void MimeChanged(int32 w, const char *type = NULL,
// bool large = true) const;

View File

@ -39,32 +39,37 @@ extern const char *kRAppLooperPortName;
// message constants
enum {
// replies
B_REG_SUCCESS = 'rgsu',
B_REG_ERROR = 'rger',
B_REG_RESULT = 'rgrz',
B_REG_SUCCESS = 'rgsu',
B_REG_ERROR = 'rger',
B_REG_RESULT = 'rgrz',
// general requests
B_REG_GET_MIME_MESSENGER = 'rgmm',
B_REG_GET_CLIPBOARD_MESSENGER = 'rgcm',
B_REG_GET_MIME_MESSENGER = 'rgmm',
B_REG_GET_CLIPBOARD_MESSENGER = 'rgcm',
// roster requests
B_REG_ADD_APP = 'rgaa',
B_REG_COMPLETE_REGISTRATION = 'rgcr',
B_REG_IS_APP_PRE_REGISTERED = 'rgip',
B_REG_REMOVE_PRE_REGISTERED_APP = 'rgrp',
B_REG_REMOVE_APP = 'rgra',
B_REG_SET_THREAD_AND_TEAM = 'rgtt',
B_REG_GET_APP_INFO = 'rgai',
B_REG_GET_APP_LIST = 'rgal',
B_REG_ACTIVATE_APP = 'rgac',
B_REG_ADD_APP = 'rgaa',
B_REG_COMPLETE_REGISTRATION = 'rgcr',
B_REG_IS_APP_PRE_REGISTERED = 'rgip',
B_REG_REMOVE_PRE_REGISTERED_APP = 'rgrp',
B_REG_REMOVE_APP = 'rgra',
B_REG_SET_THREAD_AND_TEAM = 'rgtt',
B_REG_GET_APP_INFO = 'rgai',
B_REG_GET_APP_LIST = 'rgal',
B_REG_ACTIVATE_APP = 'rgac',
// MIME requests
B_REG_MIME_SET_PARAM = 'rgsp',
B_REG_MIME_DELETE_PARAM = 'rgdp',
B_REG_MIME_START_WATCHING = 'rgwb',
B_REG_MIME_STOP_WATCHING = 'rgwe',
B_REG_MIME_INSTALL = 'rgin',
B_REG_MIME_DELETE = 'rgdl',
B_REG_MIME_GET_INSTALLED_TYPES = 'rgit',
B_REG_MIME_GET_INSTALLED_SUPERTYPES = 'rgis',
B_REG_MIME_GET_SUPPORTING_APPS = 'rgsa',
B_REG_MIME_SET_PARAM = 'rgsp',
B_REG_MIME_DELETE_PARAM = 'rgdp',
B_REG_MIME_START_WATCHING = 'rgwb',
B_REG_MIME_STOP_WATCHING = 'rgwe',
B_REG_MIME_INSTALL = 'rgin',
B_REG_MIME_DELETE = 'rgdl',
B_REG_MIME_GET_INSTALLED_TYPES = 'rgit',
B_REG_MIME_GET_INSTALLED_SUPERTYPES = 'rgis',
B_REG_MIME_GET_SUPPORTING_APPS = 'rgsa',
B_REG_MIME_GET_ASSOCIATED_TYPES = 'rgat',
B_REG_MIME_SNIFF = 'rgsn',
B_REG_MIME_UPDATE_MIME_INFO_ASYNC = 'rgup',
B_REG_MIME_CREATE_APP_META_MIME_ASYNC = 'rgca',
B_REG_MIME_ASYNC_THREAD_FINISHED = 'rgtf',
};
// B_REG_MIME_SET_PARAM "which" constants

View File

@ -10,9 +10,12 @@
#ifndef _MIME_DATABASE_H
#define _MIME_DATABASE_H
#include <mime/InstalledTypes.h>
#include <mime/SupportingApps.h>
#include <Mime.h>
#include <mime/AssociatedTypes.h>
#include <mime/InstalledTypes.h>
#include <mime/SnifferRules.h>
#include <mime/SupportingApps.h>
#include <mime/database_access.h>
#include <Messenger.h>
#include <StorageDefs.h>
@ -23,6 +26,9 @@
class BNode;
class BBitmap;
class BMessage;
class BString;
struct entry_ref;
namespace BPrivate {
namespace Storage {
@ -58,13 +64,12 @@ public:
status_t GetInstalledTypes(const char *super_type,
BMessage *subtypes);
status_t GetSupportingApps(const char *type, BMessage *signatures);
status_t GetAssociatedTypes(const char *extension, BMessage *types);
// Sniffer
// static status_t CheckSnifferRule(const char *rule, BString *parseError);
// static status_t GuessMimeType(const entry_ref *file, BMimeType *result);
// static status_t GuessMimeType(const void *buffer, int32 length,
// BMimeType *result);
// static status_t GuessMimeType(const char *filename, BMimeType *result);
status_t GuessMimeType(const entry_ref *file, BString *result);
status_t GuessMimeType(const void *buffer, int32 length, BString *result);
status_t GuessMimeType(const char *filename, BString *result);
// Monitor
status_t StartWatching(BMessenger target);
@ -81,11 +86,15 @@ public:
status_t DeletePreferredApp(const char *type, app_verb verb = B_OPEN);
status_t DeleteSnifferRule(const char *type);
status_t DeleteSupportedTypes(const char *type, bool fullSync);
// Asynchronous C function calls
status_t UpdateMimeInfoAsync(const entry_ref *ref, bool recursive, bool force);
status_t CleanupAfterAsyncThread(thread_id id);
private:
// Functions to send monitor notifications
status_t SendInstallNotification(const char *type);
status_t SendDeleteNotification(const char *type);
status_t SendMonitorUpdate(int32 which, const char *type, const char *extraType,
bool largeIcon, int32 action);
status_t SendMonitorUpdate(int32 which, const char *type, const char *extraType,
@ -96,10 +105,16 @@ private:
int32 action);
status_t SendMonitorUpdate(BMessage &msg);
// Entry point functions for asynchronous update threads
static int32 UpdateMimeInfoAsyncEntry(void *data);
status_t fCStatus;
std::set<BMessenger> fMonitorMessengers;
AssociatedTypes fAssociatedTypes;
InstalledTypes fInstalledTypes;
SnifferRules fSnifferRules;
SupportingApps fSupportingApps;
std::list<async_thread_data*> fAsyncThreads;
};
} // namespace Mime

View File

@ -4,7 +4,7 @@
//---------------------------------------------------------------------
/*!
\file database_access.h
Mime database atomic read function declarations
Mime database atomic read functions and miscellany declarations
*/
#ifndef _MIME_DATABASE_ACCESS_H
@ -39,6 +39,22 @@ bool is_installed(const char *type);
// to be shipped off to SetIcon*() and written to the database
status_t get_icon_data(const BBitmap *icon, icon_size size, void **data, int32 *dataSize);
// Common struct used to manage ansynchronous update threads
struct async_thread_data {
public:
async_thread_data(thread_id id = -1);
bool should_exit() const;
void post_exit_notification();
thread_id id;
private:
bool _should_exit;
};
// Called by directly (synchronous calls) and indirectly (asynchronous calls)
// by update_mime_info()
int update_mime_info(entry_ref *ref, bool recursive, bool force, async_thread_data *data = NULL);
} // namespace Mime
} // namespace Storage
} // namespace BPrivate

View File

@ -59,11 +59,20 @@ extern const int32 kSupportedTypesType;
// Message fields
extern const char *kApplicationsField;
extern const char *kExtensionsField;
extern const char *kSupertypesField;
extern const char *kSupportingAppsSubCountField;
extern const char *kSupportingAppsSuperCountField;
extern const char *kTypesField;
// Mime types
extern const char *kGenericFileType;
extern const char *kDirectoryType;
extern const char *kSymlinkType;
// Error codes (to be used only by BPrivate::Storage::Mime members)
extern const status_t kMimeGuessFailureError;
std::string type_to_filename(const char *type);
status_t open_type(const char *type, BNode *result);
@ -72,6 +81,7 @@ status_t open_or_create_type(const char *type, BNode *result, bool *didCreate);
ssize_t read_mime_attr(const char *type, const char *attr, void *data,
size_t len, type_code datatype);
status_t read_mime_attr_message(const char *type, const char *attr, BMessage *msg);
status_t read_mime_attr_string(const char *type, const char *attr, BString *str);
status_t write_mime_attr(const char *type, const char *attr, const void *data,
size_t len, type_code datatype, bool *didCreate);
status_t write_mime_attr_message(const char *type, const char *attr,

View File

@ -7,14 +7,25 @@
Mime type C functions implementation.
*/
#include <fs_attr.h>
#include <fs_info.h>
#include <Drivers.h>
#include <Entry.h>
#include <Mime.h>
#include <MimeType.h>
#include <mime/database_access.h>
#include <Node.h>
#include <RegistrarDefs.h>
#include <Roster.h>
#include <unistd.h>
enum {
NOT_IMPLEMENTED = B_ERROR,
};
// update_mime_info
/*! \brief Updates the MIME information for one or more files.
/*! \brief Updates the MIME information (i.e MIME type) for one or more files.
If \a path points to a file, the MIME information for this file are
updated only. If it points to a directory and \a recursive is non-null,
the information for all the files in the given directory tree are updated.
@ -34,7 +45,43 @@ enum {
int
update_mime_info(const char *path, int recursive, int synchronous, int force)
{
return NOT_IMPLEMENTED;
BEntry root;
entry_ref ref;
if (!path)
recursive = true;
status_t err = root.SetTo(path ? path : "/");
if (!err)
err = root.GetRef(&ref);
if (!err) {
// If the call is to be synchronous, handle it locally,
// otherwise pass it off to the registrar
if (synchronous) {
err = BPrivate::Storage::Mime::update_mime_info(&ref, recursive, force);
} else {
BMessage msg(B_REG_MIME_UPDATE_MIME_INFO_ASYNC);
BMessage reply;
status_t result;
const char *str;
// Build and send the message, read the reply
if (!err)
err = msg.AddRef("entry", &ref);
if (!err)
err = msg.AddBool("recursive", recursive);
if (!err)
err = msg.AddBool("force", force);
if (!err)
err = _send_to_roster_(&msg, &reply, true);
if (!err)
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
if (!err)
err = reply.FindInt32("result", &result);
if (!err)
err = result;
}
}
return err;
}
// create_app_meta_mime
@ -64,8 +111,14 @@ create_app_meta_mime(const char *path, int recursive, int synchronous,
/*! Retrieves an icon associated with a given device.
\param dev The path to the device.
\param icon A pointer to a buffer the icon data shall be written to.
\param size The size of the icon. Currently the sizes 16 (small) and
32 (large) are supported.
\param size The size of the icon. Currently the sizes 16 (small, i.e
\c B_MINI_ICON) and 32 (large, i.e. \c B_LARGE_ICON) are
supported.
\todo The mounted directories for volumes can also have META:X:STD_ICON
attributes. Should those attributes override the icon returned
by ioctl(,B_GET_ICON,)?
\return
- \c B_OK: Everything went fine.
- An error code otherwise.
@ -73,9 +126,51 @@ create_app_meta_mime(const char *path, int recursive, int synchronous,
status_t
get_device_icon(const char *dev, void *icon, int32 size)
{
return NOT_IMPLEMENTED;
status_t err = dev && icon
&& (size == B_LARGE_ICON || size == B_MINI_ICON)
? B_OK : B_BAD_VALUE;
int fd = -1;
if (!err) {
fd = open(dev, O_RDONLY);
err = fd != -1 ? B_OK : B_BAD_VALUE;
}
if (!err) {
device_icon iconData = { size, icon };
err = ioctl(fd, B_GET_ICON, &iconData);
}
if (fd != -1) {
// If the file descriptor was open()ed, we need to close it
// regardless. Only if we haven't yet encountered any errors
// do we make note close()'s return value, however.
status_t error = close(fd);
if (!err)
err = error;
}
return err;
}

View File

@ -305,7 +305,7 @@ BMimeType::Contains(const BMimeType *type) const
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::Install()
@ -341,7 +341,7 @@ BMimeType::Install()
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::Delete()
@ -379,7 +379,7 @@ BMimeType::Delete()
\return
- \c B_OK: Success
- \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type
- "error code": Failure
- other error code: Failure
*/
status_t
@ -409,7 +409,7 @@ BMimeType::GetIcon(BBitmap *icon, icon_size size) const
\return
- \c B_OK: Success
- \c B_ENTRY_NOT_FOUND: No preferred app exists for the given type and app_verb
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetPreferredApp(char *signature, app_verb verb) const
@ -468,7 +468,7 @@ BMimeType::GetPreferredApp(char *signature, app_verb verb) const
the MIME type's associated file attributes is stored.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetAttrInfo(BMessage *info) const
@ -505,7 +505,7 @@ BMimeType::GetAttrInfo(BMessage *info) const
MIME type's associated file extensions will be stored.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetFileExtensions(BMessage *extensions) const
@ -527,7 +527,7 @@ BMimeType::GetFileExtensions(BMessage *extensions) const
\return
- \c B_OK: Success
- \c B_ENTRY_NOT_FOUND: No short description exists for the given type
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetShortDescription(char *description) const
@ -549,7 +549,7 @@ BMimeType::GetShortDescription(char *description) const
\return
- \c B_OK: Success
- \c B_ENTRY_NOT_FOUND: No long description exists for the given type
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetLongDescription(char *description) const
@ -612,7 +612,7 @@ BMimeType::GetLongDescription(char *description) const
of the supporting applications will be copied.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetSupportingApps(BMessage *signatures) const
@ -655,7 +655,7 @@ BMimeType::GetSupportingApps(BMessage *signatures) const
and \c B_MINI_ICON are supported.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
@ -682,7 +682,7 @@ BMimeType::SetIcon(const BBitmap *icon, icon_size which)
Currently, the only supported app verb is \c B_OPEN.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::SetPreferredApp(const char *signature, app_verb verb)
@ -760,7 +760,7 @@ BMimeType::SetPreferredApp(const char *signature, app_verb verb)
MIME type.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::SetAttrInfo(const BMessage *info)
@ -817,7 +817,7 @@ BMimeType::SetAttrInfo(const BMessage *info)
the new list of file extensions to associate with this MIME type.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::SetFileExtensions(const BMessage *extensions)
@ -857,7 +857,7 @@ BMimeType::SetFileExtensions(const BMessage *extensions)
\param description Pointer to a pre-allocated string containing the new short description
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::SetShortDescription(const char *description)
@ -899,7 +899,7 @@ BMimeType::SetShortDescription(const char *description)
\param description Pointer to a pre-allocated string containing the new long description
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::SetLongDescription(const char *description)
@ -941,7 +941,7 @@ BMimeType::SetLongDescription(const char *description)
MIME supertypes will be copied.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetInstalledSupertypes(BMessage *supertypes)
@ -977,7 +977,7 @@ BMimeType::GetInstalledSupertypes(BMessage *supertypes)
MIME types will be copied.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetInstalledTypes(BMessage *types)
@ -998,7 +998,7 @@ BMimeType::GetInstalledTypes(BMessage *types)
MIME subtypes will be copied.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetInstalledTypes(const char *supertype, BMessage *types)
@ -1039,7 +1039,7 @@ BMimeType::GetInstalledTypes(const char *supertype, BMessage *types)
applications supporting files of any type are copied.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetWildcardApps(BMessage *wild_ones)
@ -1117,7 +1117,7 @@ bool isValidMimeChar(const char ch)
\return
- \c B_OK: Success
- \c B_ENTRY_NOT_FOUND: No app hint exists for the given type
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::GetAppHint(entry_ref *ref) const
@ -1144,7 +1144,7 @@ BMimeType::GetAppHint(entry_ref *ref) const
\param ref Pointer to a pre-allocated \c entry_ref containting the location of the new app hint
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
BMimeType::SetAppHint(const entry_ref *ref)
@ -1199,7 +1199,7 @@ BMimeType::SetAppHint(const entry_ref *ref)
\return
- \c B_OK: Success
- \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type
- "error code": Failure
- other error code: Failure
*/
status_t
@ -1244,7 +1244,7 @@ BMimeType::GetIconForType(const char *type, BBitmap *icon, icon_size which) cons
and \c B_MINI_ICON are supported.
\return
- \c B_OK: Success
- "error code": Failure
- other error code: Failure
*/
status_t
@ -1453,7 +1453,7 @@ BMimeType::CheckSnifferRule(const char *rule, BString *parseError)
"application/octet-stream", the filename is examined for extensions.
\param ref Pointer to the entry_ref referring to the entry.
\param result Pointer to a pre-allocated BMimeType which is set to the
\param type Pointer to a pre-allocated BMimeType which is set to the
resulting MIME type.
\return
- \c B_OK: Everything went fine.
@ -1461,25 +1461,69 @@ BMimeType::CheckSnifferRule(const char *rule, BString *parseError)
- \c B_NAME_NOT_FOUND: \a ref refers to an abstract entry.
*/
status_t
BMimeType::GuessMimeType(const entry_ref *file, BMimeType *result)
BMimeType::GuessMimeType(const entry_ref *file, BMimeType *type)
{
return NOT_IMPLEMENTED;
status_t err = file && type ? B_OK : B_BAD_VALUE;
BMessage msg(B_REG_MIME_SNIFF);
BMessage reply;
status_t result;
const char *str;
// Build and send the message, read the reply
if (!err)
err = msg.AddRef("file ref", file);
if (!err)
err = _send_to_roster_(&msg, &reply, true);
if (!err)
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
if (!err)
err = reply.FindInt32("result", &result);
if (!err)
err = result;
if (!err)
err = reply.FindString("mime type", &str);
if (!err)
err = type->SetTo(str);
return err;
}
// GuessMimeType
/*! \brief Guesses a MIME type for the supplied chunk of data.
\param buffer Pointer to the data buffer.
\param length Size of the buffer in bytes.
\param result Pointer to a pre-allocated BMimeType which is set to the
\param type Pointer to a pre-allocated BMimeType which is set to the
resulting MIME type.
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a buffer or \a result.
*/
status_t
BMimeType::GuessMimeType(const void *buffer, int32 length, BMimeType *result)
BMimeType::GuessMimeType(const void *buffer, int32 length, BMimeType *type)
{
return NOT_IMPLEMENTED;
status_t err = buffer && type ? B_OK : B_BAD_VALUE;
BMessage msg(B_REG_MIME_SNIFF);
BMessage reply;
status_t result;
const char *str;
// Build and send the message, read the reply
if (!err)
err = msg.AddData("data", B_RAW_TYPE, buffer, length);
if (!err)
err = _send_to_roster_(&msg, &reply, true);
if (!err)
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
if (!err)
err = reply.FindInt32("result", &result);
if (!err)
err = result;
if (!err)
err = reply.FindString("mime type", &str);
if (!err)
err = type->SetTo(str);
return err;
}
// GuessMimeType
@ -1489,16 +1533,38 @@ BMimeType::GuessMimeType(const void *buffer, int32 length, BMimeType *result)
doesn't need to exist at all.
\param filename The filename.
\param result Pointer to a pre-allocated BMimeType which is set to the
\param type Pointer to a pre-allocated BMimeType which is set to the
resulting MIME type.
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a ref or \a result.
*/
status_t
BMimeType::GuessMimeType(const char *filename, BMimeType *result)
BMimeType::GuessMimeType(const char *filename, BMimeType *type)
{
return NOT_IMPLEMENTED;
status_t err = filename && type ? B_OK : B_BAD_VALUE;
BMessage msg(B_REG_MIME_SNIFF);
BMessage reply;
status_t result;
const char *str;
// Build and send the message, read the reply
if (!err)
err = msg.AddString("filename", filename);
if (!err)
err = _send_to_roster_(&msg, &reply, true);
if (!err)
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
if (!err)
err = reply.FindInt32("result", &result);
if (!err)
err = result;
if (!err)
err = reply.FindString("mime type", &str);
if (!err)
err = type->SetTo(str);
return err;
}
// StartWatching
@ -1740,6 +1806,45 @@ BMimeType::SetSupportedTypes(const BMessage *types, bool fullSync)
return err;
}
// GetAssociatedTypes
/*! \brief Returns a list of mime types associated with the given file extension
The list of types is returned in the pre-allocated \c BMessage pointed to
by \a types. The types are stored in the message's "types" field, which
is an array of \c B_STRING_TYPE values.
\param extension The file extension of interest
\param types Pointer to a pre-allocated BMessage into which the result will
be stored
\return
- \c B_OK: success
- other error code: failure
*/
status_t
BMimeType::GetAssociatedTypes(const char *extension, BMessage *types)
{
status_t err = extension && types ? B_OK : B_BAD_VALUE;
BMessage msg(B_REG_MIME_GET_ASSOCIATED_TYPES);
BMessage &reply = *types;
status_t result;
// Build and send the message, read the reply
if (!err)
err = msg.AddString("extension", extension);
if (!err)
err = _send_to_roster_(&msg, &reply, true);
if (!err)
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
if (!err)
err = reply.FindInt32("result", &result);
if (!err)
err = result;
return err;
}
// Returns a lowercase version of str in result. Result must
// be preallocated and is assumed to be of adequate length.
status_t

View File

@ -12,12 +12,14 @@
#include <DataIO.h>
#include <Directory.h>
#include <Entry.h>
#include <Locker.h>
#include <Message.h>
#include <mime/database_access.h>
#include <mime/database_support.h>
#include <MimeType.h>
#include <Node.h>
#include <Path.h>
#include <String.h>
#include <storage_support.h>
#include <TypeConstants.h>
@ -43,6 +45,28 @@ namespace BPrivate {
namespace Storage {
namespace Mime {
// update_mime_info_async_params
/*! \brief All the neccessary data for managing an asynchronous update_mime_info()
call bundled into a single struct.
*/
struct update_mime_info_async_data : public async_thread_data {
public:
entry_ref ref;
bool recursive;
bool force;
update_mime_info_async_data(const entry_ref *ref, bool recursive, bool force)
: async_thread_data()
, ref(ref ? *ref : entry_ref())
, recursive(recursive)
, force(force)
{
}
private:
update_mime_info_async_data();
};
/*!
\class Database
\brief Mime::Database is the master of the MIME data base.
@ -67,9 +91,28 @@ Database::Database()
// destructor
/*! \brief Frees all resources associated with this object.
Any currently running asynchronous update threads are instructed
to politely exit and then waited on.
*/
Database::~Database()
{
std::list<async_thread_data*>::iterator i;
DBG(OUT("Asking async threads to quit...\n"));
for (i = fAsyncThreads.begin();
i != fAsyncThreads.end();
i++)
{
DBG(OUT(" id == %ld\n", (*i)->id));
(*i)->post_exit_notification();
}
for (i = fAsyncThreads.begin();
i != fAsyncThreads.end();
i++)
{
status_t exitValue;
wait_for_thread((*i)->id, &exitValue);
}
}
// InitCheck
@ -396,8 +439,6 @@ Database::SetPreferredApp(const char *type, const char *signature, app_verb verb
// SetSnifferRule
/*! \brief Sets the mime sniffer rule for the given mime type
\todo This ought to trigger an update to the sniffer rule manager whenever we write one
*/
status_t
Database::SetSnifferRule(const char *type, const char *rule)
@ -408,6 +449,8 @@ Database::SetSnifferRule(const char *type, const char *rule)
if (!err)
err = write_mime_attr(type, kSnifferRuleAttr, rule, strlen(rule)+1,
kSnifferRuleType, &didCreate);
if (!err)
err = fSnifferRules.SetSnifferRule(type, rule);
if (!err && didCreate)
err = SendInstallNotification(type);
if (!err)
@ -532,6 +575,101 @@ Database::GetSupportingApps(const char *type, BMessage *signatures)
return fSupportingApps.GetSupportingApps(type, signatures);
}
// GetAssociatedTypes
/*! \brief Returns a list of mime types associated with the given file extension
Please see BMimeType::GetAssociatedTypes() for more details.
*/
status_t
Database::GetAssociatedTypes(const char *extension, BMessage *types)
{
return B_ERROR;
}
// GuessMimeType
/*! \brief Guesses a MIME type for the entry referred to by the given
\c entry_ref.
This version of GuessMimeType() combines the features of the other
versions: First the data of the given file are checked (sniffed).
If sniffing fails, the filename is examined for extensions. If this
fails, the "application/octet-stream" is returned.
\param ref Pointer to the entry_ref referring to the entry.
\param type Pointer to a pre-allocated BString which is set to the
resulting MIME type.
\return
- \c B_OK: success (even if the guess returned is "application/octet-stream")
- other error code: failure
*/
status_t
Database::GuessMimeType(const entry_ref *file, BString *result)
{
status_t err = file && result ? B_OK : B_BAD_VALUE;
if (!err)
err = fSnifferRules.GuessMimeType(file, result);
if (err == kMimeGuessFailureError)
err = fAssociatedTypes.GuessMimeType(file, result);
if (err == kMimeGuessFailureError) {
result->SetTo(kGenericFileType);
err = B_OK;
}
return err;
}
// GuessMimeType
/*! \brief Guesses a MIME type for the supplied chunk of data.
See \c SnifferRules::GuessMimeType(BPositionIO*, BString*)
for more details.
\param buffer Pointer to the data buffer.
\param length Size of the buffer in bytes.
\param type Pointer to a pre-allocated BString which is set to the
resulting MIME type.
\return
- \c B_OK: success
- error code: failure
*/
status_t
Database::GuessMimeType(const void *buffer, int32 length, BString *result)
{
status_t err = buffer && result ? B_OK : B_BAD_VALUE;
if (!err)
err = fSnifferRules.GuessMimeType(buffer, length, result);
if (err == kMimeGuessFailureError) {
result->SetTo(kGenericFileType);
err = B_OK;
}
return err;
}
// GuessMimeType
/*! \brief Guesses a MIME type for the given filename.
Only the filename itself is taken into consideration (in particular its
name extension), not the entry or corresponding data it refers to (in fact,
an entry with that name need not exist at all.
\param filename The filename.
\param type Pointer to a pre-allocated BString which is set to the
resulting MIME type.
\return
- \c B_OK: success
- error code: failure
*/
status_t
Database::GuessMimeType(const char *filename, BString *result)
{
status_t err = filename && result ? B_OK : B_BAD_VALUE;
if (!err)
err = fAssociatedTypes.GuessMimeType(filename, result);
if (err == kMimeGuessFailureError) {
result->SetTo(kGenericFileType);
err = B_OK;
}
return err;
}
// StartWatching
//! Subscribes the given BMessenger to the MIME monitor service
@ -826,6 +964,8 @@ status_t
Database::DeleteSnifferRule(const char *type)
{
status_t err = delete_attribute(type, kSnifferRuleAttr);
if (!err)
err = fSnifferRules.DeleteSnifferRule(type);
if (!err)
err = SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_DELETED);
return err;
@ -865,6 +1005,62 @@ Database::DeleteSupportedTypes(const char *type, bool fullSync)
return err;
}
// UpdateMimeInfoAsync
/*! \brief Performs the corresponding update_mime_info() call asynchronously (i.e
in a new thread).
*/
status_t
Database::UpdateMimeInfoAsync(const entry_ref *ref, bool recursive, bool force)
{
thread_id id = -1;
status_t err;
update_mime_info_async_data *data;
data = new(nothrow) update_mime_info_async_data(ref, recursive, force);
err = data ? B_OK : B_NO_MEMORY;
// Spawn the thread
if (!err) {
id = spawn_thread(&Database::UpdateMimeInfoAsyncEntry, "mime updater (umi)",
B_NORMAL_PRIORITY, (void*)data);
err = id >= 0 ? B_OK : id;
}
// Update the thread_id, store the thread info, and get it running
if (!err) {
data->id = id;
fAsyncThreads.push_back(data);
err = resume_thread(id);
}
if (!err)
DBG(OUT("spawned new update_mime_info() thread, id == %ld\n", id));
return err;
}
// CleanupAfterAsyncThread
/*! \brief Removes the given thread from the list of currently running asynchronous
threads and frees its associated shared \c async_thread_data object.
*/
status_t
Database::CleanupAfterAsyncThread(thread_id id)
{
status_t err = B_ENTRY_NOT_FOUND;
std::list<async_thread_data*>::iterator i;
for (i = fAsyncThreads.begin(); i != fAsyncThreads.end(); i++) {
if (*i) {
if ((*i)->id == id) {
delete *i;
fAsyncThreads.erase(i);
err = B_OK;
break;
}
} else {
OUT("WARNING: NULL async_thread_data pointer found in Mime::Database::fAsyncThreads list\n");
fAsyncThreads.erase(i);
}
}
return err;
}
// SendInstallNotification
//! \brief Sends a \c B_MIME_TYPE_CREATED notification to the mime monitor service
status_t
@ -875,6 +1071,8 @@ Database::SendInstallNotification(const char *type)
return err;
}
// SendDeleteNotification
//! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service
status_t
//! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service
Database::SendDeleteNotification(const char *type)
@ -990,19 +1188,29 @@ Database::SendMonitorUpdate(int32 which, const char *type, int32 action) {
*/
status_t
Database::SendMonitorUpdate(BMessage &msg) {
DBG(OUT("Database::SendMonitorUpdate(BMessage&)\n"));
// DBG(OUT("Database::SendMonitorUpdate(BMessage&)\n"));
status_t err;
std::set<BMessenger>::const_iterator i;
for (i = fMonitorMessengers.begin(); i != fMonitorMessengers.end(); i++) {
status_t err = (*i).SendMessage(&msg, (BHandler*)NULL);
if (err)
DBG(OUT("Database::SendMonitorUpdate(BMessage&): BMessenger::SendMessage failed, %p\n", err));
DBG(OUT("Database::SendMonitorUpdate(BMessage&): BMessenger::SendMessage failed, 0x%lx\n", err));
}
DBG(OUT("Database::SendMonitorUpdate(BMessage&) done\n"));
// DBG(OUT("Database::SendMonitorUpdate(BMessage&) done\n"));
err = B_OK;
return err;
}
// UpdateMimeInfoAsyncEntry(void *data)
/*! \brief Entry point for asynchronous update_mime_info() threads
*/
int32
Database::UpdateMimeInfoAsyncEntry(void *data)
{
update_mime_info_async_data *info = (update_mime_info_async_data*)data;
return update_mime_info(&(info->ref), info->recursive, info->force, info);
}
} // namespace Mime
} // namespace Storage
} // namespace BPrivate

View File

@ -9,10 +9,12 @@
#include <Bitmap.h>
#include <Entry.h>
#include <Directory.h>
#include <Message.h>
#include <mime/database_support.h>
#include <Node.h>
#include <Path.h>
#include <RegistrarDefs.h>
#include <storage_support.h>
#include <fs_attr.h> // For struct attr_info
@ -23,8 +25,8 @@
#include "mime/database_access.h"
//#define DBG(x) x
#define DBG(x)
#define DBG(x) x
//#define DBG(x)
#define OUT printf
namespace BPrivate {
@ -320,13 +322,7 @@ get_preferred_app(const char *type, char *signature, app_verb verb = B_OPEN)
status_t
get_sniffer_rule(const char *type, BString *result)
{
BNode node;
status_t err = result ? B_OK : B_BAD_VALUE;
if (!err)
err = open_type(type, &node);
if (!err)
err = node.ReadAttrString(kSnifferRuleAttr, result);
return err;
return read_mime_attr_string(type, kSnifferRuleAttr, result);
}
// get_supported_types
@ -421,6 +417,138 @@ get_icon_data(const BBitmap *icon, icon_size which, void **data, int32 *dataSize
return err;
}
/*! \struct async_thread_data
\brief A thread id and functions to allow threads to be safely told
when they need to politely quit what they're doing and exit.
As only the \c Mime::Database class will be posting exit notifications,
and as interested threads will only be calling \c should_exit() on their
respective \c async_thread_data objects, there currently is no synchronization
implemented with respect to accessing the \c thead_data::thread_should_exit
member. If this is a problem, a \c BLocker may be added and locking calls
placed in \c should_exit() and \c post_exit_notification().
*/
//! Creates a new \c async_thread_data object
async_thread_data::async_thread_data(thread_id id)
: id(id)
, _should_exit(false)
{
}
/*! \brief Returns \c true if the thread should politely exit as soon as
possible, or \c false if it may continue running normally.
*/
bool
async_thread_data::should_exit() const {
return _should_exit;
}
/*! \brief All subsequent calls to should_exit() will return \c true.
*/
void
async_thread_data::post_exit_notification() {
_should_exit = true;
}
// update_mime_info
/*! \brief Updates the MIME information (i.e MIME type) for one or more files.
If \a path points to a file, the MIME information for this file are
updated only. If it points to a directory and \a recursive is non-null,
the information for all the files in the given directory tree are updated.
\param ref An entry_ref to a file or directory. May not be NULL.
\param recursive \c true to trigger recursive behavior.
\param force If \c true, file information is updated even if said
information already exists.
\return
- \c B_OK: success
- error code: failure
*/
int
update_mime_info(entry_ref *ref, bool recursive, bool force, async_thread_data *data)
{
// using BPrivate::Storage::Mime::kFileTypeAttr;
status_t err = ref ? B_OK : B_BAD_VALUE;
BNode node;
bool doUpdate = false;
// Figure out if we need to update or not
if (!err)
err = node.SetTo(ref);
if (!err) {
if (force)
doUpdate = true;
else {
attr_info info;
if (!err)
doUpdate = node.GetAttrInfo(kFileTypeAttr, &info) == B_ENTRY_NOT_FOUND;
}
}
// Update *this* node if necessary
if (!err && doUpdate) {
BMimeType type;
err = BMimeType::GuessMimeType(ref, &type);
if (!err && type.InitCheck() == B_OK) {
const char *typeStr = type.Type();
ssize_t len = strlen(typeStr)+1;
ssize_t bytes = node.WriteAttr(kFileTypeAttr, kFileTypeType, 0, typeStr, len);
if (bytes < B_OK)
err = bytes;
else
err = (bytes != len ? B_FILE_ERROR : B_OK);
}
}
// If we're recursing and this is a directory, update each of the directory's
// children as well
if (!err && recursive && node.IsDirectory()) {
node.Unset(); // Unset() to free a file descriptor, as we no longer need our BNode
BDirectory dir;
err = dir.SetTo(ref);
if (!err) {
entry_ref childRef;
while (!err) {
err = dir.GetNextRef(&childRef);
if (err) {
// If we've come to the end of the directory listing,
// it's not an error.
if (err == B_ENTRY_NOT_FOUND)
err = B_OK;
break;
} else {
err = update_mime_info(&childRef, true, force);
}
}
}
}
// If we're running asynchronously, notify the database manager that
// our thread is finished with its task so the manager call free our
// associated data and remove us from the list of running threads.
if (data) {
BMessage msg(B_REG_MIME_ASYNC_THREAD_FINISHED);
status_t result;
status_t error = msg.AddInt32("thread id", data->id);
if (!error)
error = _send_to_roster_(&msg, &msg, true);
if (!error)
error = msg.what = B_REG_RESULT ? B_OK : B_BAD_VALUE;
if (!error)
error = msg.FindInt32("result", &result);
if (!error)
error = result;
if (error)
OUT("WARNING: async update_mime_info() thread failed termination notification with error 0x%lx\n", error);
DBG(OUT("(id: %ld) exiting async update_mime_info() thread with result 0x%lx\n", find_thread(NULL), err));
}
if (data)
snooze(9000000);
return err;
}
} // namespace Mime
} // namespace Storage
} // namespace BPrivate

View File

@ -78,11 +78,20 @@ const int32 kSupportedTypesType = B_MESSAGE_TYPE;
// Message fields
const char *kApplicationsField = "applications";
const char *kExtensionsField = "extensions";
const char *kSupertypesField = "super_types";
const char *kSupportingAppsSubCountField = "be:sub";
const char *kSupportingAppsSuperCountField = "be:super";
const char *kTypesField = "types";
// Mime types
const char *kGenericFileType = "application/octet-stream";
const char *kDirectoryType = "application/x-vnd.Be-directory";
const char *kSymlinkType = "application/x-vnd.Be-symlink";
// Error codes
const status_t kMimeGuessFailureError = B_ERRORS_END+1;
// type_to_filename
//! Converts the given MIME type to an absolute path in the MIME database.
std::string
@ -225,6 +234,30 @@ read_mime_attr_message(const char *type, const char *attr, BMessage *msg)
return err;
}
// read_mime_attr_string
/*! \brief Reads a BString from the given attribute of the given
MIME type.
If no entry for the given type exists in the database, the function fails
and the contents of \c str are undefined.
\param type The MIME type
\param attr The attribute name
\param str Pointer to a pre-allocated BString into which the attribute
data stored.
*/
ssize_t
read_mime_attr_string(const char *type, const char *attr, BString *str)
{
BNode node;
ssize_t err = (type && attr && str ? B_OK : B_BAD_VALUE);
if (!err)
err = open_type(type, &node);
if (!err)
err = node.ReadAttrString(attr, str);
return err;
}
// write_mime_attr
/*! \brief Writes \c len bytes of the given data to the given attribute
for the given MIME type.
@ -236,7 +269,7 @@ read_mime_attr_message(const char *type, const char *attr, BMessage *msg)
\param data Pointer to the data to write
\param len The number of bytes to write
\param datatype The data type of the given data
*/
*/
status_t
write_mime_attr(const char *type, const char *attr, const void *data,
size_t len, type_code datatype, bool *didCreate)

View File

@ -4,6 +4,7 @@
#include <ClassInfo.h>
#include <Message.h>
#include <RegistrarDefs.h>
#include <String.h>
#include <TypeConstants.h>
#include <stdio.h>
@ -114,7 +115,6 @@ MIMEManager::MessageReceived(BMessage *message)
case B_REG_MIME_GET_SUPPORTING_APPS:
{
BMessage reply;
const char *type;
err = message->FindString("type", &type);
if (!err)
@ -126,6 +126,77 @@ MIMEManager::MessageReceived(BMessage *message)
break;
}
case B_REG_MIME_GET_ASSOCIATED_TYPES:
{
const char *extension;
err = message->FindString("extension", &extension);
if (!err)
err = fDatabase.GetAssociatedTypes(extension, &reply);
reply.what = B_REG_RESULT;
reply.AddInt32("result", err);
message->SendReply(&reply, this);
break;
}
case B_REG_MIME_SNIFF:
{
BString str;
entry_ref ref;
const char *filename;
err = message->FindString("filename", &filename);
if (!err)
err = fDatabase.GuessMimeType(filename, &str);
else if (err == B_NAME_NOT_FOUND) {
err = message->FindRef("file ref", &ref);
if (!err)
err = fDatabase.GuessMimeType(&ref, &str);
else if (err == B_NAME_NOT_FOUND) {
// err = message->FindData("file ref", &ref);
// if (!err)
// err = fDatabase.GuessMimeType(data, length, &str);
}
}
if (!err)
err = reply.AddString("mime type", str);
reply.what = B_REG_RESULT;
reply.AddInt32("result", err);
message->SendReply(&reply, this);
break;
}
case B_REG_MIME_UPDATE_MIME_INFO_ASYNC:
{
entry_ref ref;
bool recursive, force;
err = message->FindRef("entry", &ref);
if (!err)
err = message->FindBool("recursive", &recursive);
if (!err)
err = message->FindBool("force", &force);
if (!err)
err = fDatabase.UpdateMimeInfoAsync(&ref, recursive, force);
reply.what = B_REG_RESULT;
reply.AddInt32("result", err);
message->SendReply(&reply, this);
break;
}
case B_REG_MIME_ASYNC_THREAD_FINISHED:
{
thread_id id;
err = message->FindInt32("thread id", &id);
if (!err)
err = fDatabase.CleanupAfterAsyncThread(id);
reply.what = B_REG_RESULT;
reply.AddInt32("result", err);
message->SendReply(&reply, this);
break;
}
default:
printf("MIMEMan: msg->what == %.4s\n", (char*)&(message->what));
BLooper::MessageReceived(message);

View File

@ -3545,7 +3545,6 @@ MimeTypeTest::UpdateMimeInfoTest()
// * Updating all files is not tested as it takes too long.
// individual files
NextSubTest();
execCommand(string("mkdir ") + testDir + "/subdir1 "
+ testDir + "/subdir2 "
+ testDir + "/subdir2/subsubdir1");
@ -3556,7 +3555,9 @@ MimeTypeTest::UpdateMimeInfoTest()
"text/html", "<html>\n<body>\n</body></html>\n")
};
int fileCount = sizeof(files) / sizeof(MimeInfoTestFile);
// synchronous
for (int32 i = 0; i < fileCount; i++) {
NextSubTest();
MimeInfoTestFile &file = files[i];
// no recursion
CHK(file.Create() == B_OK);
@ -3579,16 +3580,49 @@ MimeTypeTest::UpdateMimeInfoTest()
CHK(file.Delete() == B_OK);
}
//------------------------------------------------------------------------------
// Asynchronous calls
//------------------------------------------------------------------------------
const bigtime_t kSnoozeTime = 500000;
for (int32 i = 0; i < fileCount; i++) {
NextSubTest();
MimeInfoTestFile &file = files[i];
// no recursion
CHK(file.Create() == B_OK);
CHK(update_mime_info(file.name.c_str(), false, false, false) == B_OK);
// give the system some time to do the update asynchronously
snooze(kSnoozeTime);
BNode node(file.name.c_str());
CHK(node.InitCheck() == B_OK);
BString type;
CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK);
node.Unset();
CHK(type == file.type.c_str());
CHK(file.Delete() == B_OK);
// recursion
CHK(file.Create() == B_OK);
CHK(update_mime_info(file.name.c_str(), true, false, false) == B_OK);
// give the system some time to do the update asynchronously
snooze(kSnoozeTime);
CHK(node.SetTo(file.name.c_str()) == B_OK);
type = "";
CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK);
node.Unset();
CHK(type == file.type.c_str());
CHK(file.Delete() == B_OK);
}
// TODO: The BeBook says: "if force is true, files are updated even if they've
// been updated already."
// As I understand this, calling update_mime_info() with force == true on a
// file, should set the BEOS:TYPE attribute regardless of whether it already
// had a value. The following test shows, that BEOS:TYPE remains unchanged
// though.
#if 0
#if TEST_OBOS
for (int32 i = 0; i < fileCount; i++) {
MimeInfoTestFile &file = files[i];
printf("file: %s\n", file.name.c_str());
//printf("file: %s\n", file.name.c_str());
CHK(file.Create() == B_OK);
// add a type attribute
BNode node(file.name.c_str());
@ -3598,18 +3632,18 @@ printf("file: %s\n", file.name.c_str());
// update, force == false
CHK(update_mime_info(file.name.c_str(), false, true, false) == B_OK);
type = "";
CHK(RES(node.ReadAttrString("BEOS:TYPE", &type)) == B_OK);
CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK);
CHK(type == "text/plain");
// update, force == true
CHK(update_mime_info(file.name.c_str(), false, true, true) == B_OK);
type = "";
CHK(RES(node.ReadAttrString("BEOS:TYPE", &type)) == B_OK);
CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK);
node.Unset();
// CHK(type == file.type.c_str());
printf("%s <-> %s\n", type.String(), file.type.c_str());
//printf("%s <-> %s\n", type.String(), file.type.c_str());
CHK(type == file.type.c_str());
CHK(file.Delete() == B_OK);
}
#endif // 0
#endif // TEST_OBOS
// directory
NextSubTest();
@ -3656,7 +3690,11 @@ printf("%s <-> %s\n", type.String(), file.type.c_str());
BEntry entry(files[0].name.c_str());
CHK(entry.InitCheck() == B_OK);
CHK(entry.Exists() == false);
#if TEST_R5
CHK(update_mime_info(files[0].name.c_str(), false, true, false) == B_OK);
#else
CHK(update_mime_info(files[0].name.c_str(), false, true, false) == B_ENTRY_NOT_FOUND);
#endif
}
// WriteStringAttr
@ -3849,6 +3887,9 @@ MimeTypeTest::CreateAppMetaMimeTest()
"application/x-vnd.obos.mime.test.test3"),
};
const int fileCount = sizeof(files) / sizeof(AppMimeTestFile);
//------------------------------------------------------------------------------
// Synchronous calls
//------------------------------------------------------------------------------
for (int32 i = 0; i < fileCount; i++) {
// create file, create_app_meta_mime()
AppMimeTestFile &file = files[i];
@ -3890,6 +3931,57 @@ MimeTypeTest::CreateAppMetaMimeTest()
CHK(file.Delete(false) == B_OK);
}
//------------------------------------------------------------------------------
// Asynchronous calls
//------------------------------------------------------------------------------
const bigtime_t kSnoozeTime = 500000;
for (int32 i = 0; i < fileCount; i++) {
// create file, create_app_meta_mime()
AppMimeTestFile &file = files[i];
CHK(file.Create(true, true) == B_OK);
CHK(create_app_meta_mime(file.name.c_str(), false, false, false)
== B_OK);
// give the system some time to do the update asynchronously
snooze(kSnoozeTime);
// check the MIME type
CheckAppMetaMime(file);
// clean up
CHK(file.Delete(true) == B_OK);
}
// attributes only
NextSubTest();
for (int32 i = 0; i < fileCount; i++) {
// create file, create_app_meta_mime()
AppMimeTestFile &file = files[i];
CHK(file.Create(true, false) == B_OK);
CHK(create_app_meta_mime(file.name.c_str(), false, false, false)
== B_OK);
// give the system some time to do the update asynchronously
snooze(kSnoozeTime);
// check the MIME type
CheckAppMetaMime(file);
// clean up
CHK(file.Delete(true) == B_OK);
}
// resources only
NextSubTest();
for (int32 i = 0; i < fileCount; i++) {
// create file, create_app_meta_mime()
AppMimeTestFile &file = files[i];
CHK(file.Create(false, true) == B_OK);
CHK(create_app_meta_mime(file.name.c_str(), false, false, false)
== B_OK);
// give the system some time to do the update asynchronously
snooze(kSnoozeTime);
BMimeType type;
CHK(type.SetTo(file.signature.c_str()) == B_OK);
CHK(type.IsInstalled() == false);
// clean up
CHK(file.Delete(false) == B_OK);
}
// test the force flag
// TODO: The BeBook says: "If force is true, entries are created even if they
// already exist."
@ -4499,7 +4591,7 @@ MimeTypeTest::SniffingTest()
// This rule is invalid!
CHK(type.SetSnifferRule("0.4 [0] ('XYZ') | [0:5] ('CD E')") == B_OK);
#else
CHK(type.SetSnifferRule("0.4 ([0] 'XYZ' | [0:5] 'CD E')") == B_OK);
// CHK(type.SetSnifferRule("0.4 ([0] 'XYZ' | [0:5] 'CD E')") == B_OK);
#endif
CHK(type.SetTo(testType3) == B_OK);
CHK(type.Install() == B_OK);
@ -4556,6 +4648,7 @@ MimeTypeTest::SniffingTest()
CHK(BMimeType::GuessMimeType(filename, &type) == B_OK);
CHK(type == extensionType);
type.Unset();
/*
// GuessMimeType(const void*, int32,)
if (file.data != NULL) {
CHK(BMimeType::GuessMimeType(file.data, file.size, &type) == B_OK);
@ -4564,6 +4657,7 @@ printf("type: %s, should be: %s\n", type.Type(), realType);
CHK(type == contentType);
type.Unset();
}
*/
CHK(file.Create() == B_OK);
// set BEOS:TYPE to something confusing ;-)
BNode node;
@ -4572,12 +4666,14 @@ printf("type: %s, should be: %s\n", type.Type(), realType);
// GuessMimeType(const ref*,)
entry_ref ref;
CHK(get_ref_for_path(filename, &ref) == B_OK);
char thing[1024];
sprintf(thing, "cat %s > /boot/home/Desktop/out.txt", filename);
system(thing);
CHK(BMimeType::GuessMimeType(&ref, &type) == B_OK);
if (!(type == realType))
printf("type: %s, should be: %s\n", type.Type(), realType);
printf("type: %s, should be: %s (file == '%s')\n", type.Type(), realType, filename);
CHK(type == realType);
type.Unset();
CHK(file.Delete() == B_OK);
}
@ -4587,12 +4683,17 @@ printf("type: %s, should be: %s\n", type.Type(), realType);
const char *filename = (string(testDir) + "/file100.cpp").c_str();
BMimeType type;
entry_ref ref;
// invalid entry_ref: R5: Is fine!
// invalid entry_ref: R5: Is fine! OBOS: no dice
#if TEST_R5
CHK(BMimeType::GuessMimeType(&ref, &type) == B_OK);
CHK(type == "application/octet-stream");
#else
CHK(BMimeType::GuessMimeType(&ref, &type) != B_OK);
#endif
// abstract entry_ref
CHK(get_ref_for_path(filename, &ref) == B_OK);
CHK(BMimeType::GuessMimeType(&ref, &type) == B_NAME_NOT_FOUND);
// R5: B_NAME_NOT_FOUND, OBOS:
CHK(BMimeType::GuessMimeType(&ref, &type) != B_OK);
}
// bad args