+ Added SetSupportedTypes() test

+ Modified BMimeType::SetSupportedTypes functionality so it keeps track of
stranded types (i.e. previously supported types that have not had the now
unsupporting app signature removed from their supporting apps list yet due
to a false fullSync parameter) over consecutive SetSupportedTypes(...,
false) calls and updates all appropriate stranded types on the next
SetSupportedTypes(..., true) call.
+ Added fullSync parameter to BMimeType::DeleteSupportedTypes
+ Made BMimeType::Delete() do a DeleteSupportedTypes(..., true) call to
properly update the supporting apps lists when a mime type is deleted.
+ Added initial BMimeType::Get/SetSnifferRule
+ Updated BMimeType::CheckSnifferRule() to return B_BAD_VALUE when passed
a NULL rule string.
+ Brought CheckSnifferRule() tests up to date
+ Added lots of Mime::Database doxygen
+ Added any missing mime monitor notifications in Mime::Database
+ Possibly made some other changes as well... :-)


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1004 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Tyler Dauwalder 2002-09-09 08:12:03 +00:00
parent baa326e0ec
commit e3a2f2069e
10 changed files with 881 additions and 82 deletions

View File

@ -49,7 +49,7 @@ public:
status_t SetIconForType(const char *type, const char *fileType, const void *data,
size_t dataSize, icon_size which);
status_t SetPreferredApp(const char *type, const char *signature, app_verb verb = B_OPEN);
// status_t SetSnifferRule(const char *);
status_t SetSnifferRule(const char *type, const char *rule);
status_t SetSupportedTypes(const char *type, const BMessage *types, bool fullSync);
// Non-atomic Get()
@ -80,7 +80,7 @@ public:
status_t DeleteIconForType(const char *type, const char *fileType, icon_size which);
status_t DeletePreferredApp(const char *type, app_verb verb = B_OPEN);
status_t DeleteSnifferRule(const char *type);
status_t DeleteSupportedTypes(const char *type);
status_t DeleteSupportedTypes(const char *type, bool fullSync);
private:
status_t SendInstallNotification(const char *type);

View File

@ -28,7 +28,9 @@ public:
~SupportingApps();
status_t GetSupportingApps(const char *type, BMessage *apps);
status_t SetSupportedTypes(const char *app, const BMessage *types, bool fullSync);
status_t DeleteSupportedTypes(const char *app, bool fullSync);
private:
status_t AddSupportingApp(const char *type, const char *app);
status_t RemoveSupportingApp(const char *type, const char *app);
@ -37,6 +39,8 @@ private:
std::map<std::string, std::set<std::string> > fSupportedTypes; // app sig => set of supported types
std::map<std::string, std::set<std::string> > fSupportingApps; // mime type => set of supporting apps
std::map<std::string, std::set<std::string> > fStrandedTypes; // app sig => set of no longer supported types for whom the
// given app is still listed as a supporting app
bool fHaveDoneFullBuild;
};

View File

@ -30,7 +30,7 @@ status_t get_icon(const char *type, BBitmap *icon, icon_size size);
status_t get_icon_for_type(const char *type, const char *fileType, BBitmap *icon,
icon_size which);
status_t get_preferred_app(const char *type, char *signature, app_verb verb);
status_t get_sniffer_rule(BString *result);
status_t get_sniffer_rule(const char *type, BString *result);
status_t get_supported_types(const char *type, BMessage *types);
bool is_installed(const char *type);

View File

@ -48,7 +48,6 @@ namespace Mime {
\brief Mime::Database is the master of the MIME data base.
All write and non-atomic read accesses are carried out by this class.
Monitoring is handled by
\note No error checking (other than checks for NULL pointers) is performed
by this class on the mime type strings passed to it. It's assumed
@ -56,7 +55,7 @@ namespace Mime {
*/
// constructor
/*! \brief Creates and initializes a MimeDatabase.
/*! \brief Creates and initializes a Mime::Database object.
*/
Database::Database()
: fCStatus(B_NO_INIT)
@ -110,8 +109,10 @@ Database::Install(const char *type)
bool didCreate = false;
BNode node;
err = open_or_create_type(type, &node, &didCreate);
if (didCreate)
if (!err && didCreate) {
fInstalledTypes.AddType(type);
err = SendInstallNotification(type);
}
}
}
return err;
@ -129,14 +130,21 @@ Database::Delete(const char *type)
{
BEntry entry;
status_t err = (type ? B_OK : B_BAD_VALUE);
// Open the type
if (!err)
err = entry.SetTo(type_to_filename(type).c_str());
err = entry.SetTo(type_to_filename(type).c_str());
// Remove it
if (!err)
err = entry.Remove();
if (!err) {
// Notify the installed types database
if (!err)
fInstalledTypes.RemoveType(type);
// Notify the supporting apps database
if (!err)
err = fSupportingApps.DeleteSupportedTypes(type, true);
// Notify the monitor service
if (!err)
err = SendDeleteNotification(type);
}
return err;
}
@ -158,6 +166,8 @@ Database::SetAppHint(const char *type, const entry_ref *ref)
if (!err)
err = write_mime_attr(type, kAppHintAttr, path.Path(), strlen(path.Path())+1,
kAppHintType, &didCreate);
if (!err && didCreate)
err = SendInstallNotification(type);
if (!err)
err = SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_MODIFIED);
return err;
@ -186,6 +196,8 @@ Database::SetAttrInfo(const char *type, const BMessage *info)
status_t err = (type && info) ? B_OK : B_BAD_VALUE;
if (!err)
err = write_mime_attr_message(type, kAttrInfoAttr, info, &didCreate);
if (!err && didCreate)
err = SendInstallNotification(type);
if (!err)
err = SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_MODIFIED);
return err;
@ -224,8 +236,10 @@ Database::SetLongDescription(const char *type, const char *description)
if (!err)
err = write_mime_attr(type, kLongDescriptionAttr, description, strlen(description)+1,
kLongDescriptionType, &didCreate);
if (!err && didCreate)
err = SendInstallNotification(type);
if (!err)
err = SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_MODIFIED);
err = SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_MODIFIED);
return err;
}
@ -249,6 +263,8 @@ Database::SetFileExtensions(const char *type, const BMessage *extensions)
status_t err = (type && extensions) ? B_OK : B_BAD_VALUE;
if (!err)
err = write_mime_attr_message(type, kFileExtensionsAttr, extensions, &didCreate);
if (!err && didCreate)
err = SendInstallNotification(type);
if (!err)
err = SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_MODIFIED);
return err;
@ -337,10 +353,18 @@ Database::SetIconForType(const char *type, const char *fileType, const void *dat
bool didCreate = false;
if (!err)
err = open_or_create_type(type, &node, &didCreate);
if (!err && didCreate)
err = SendInstallNotification(type);
if (!err)
err = node.WriteAttr(attr.c_str(), attrType, 0, data, attrSize);
if (err >= 0)
err = err == (ssize_t)attrSize ? B_OK : B_FILE_ERROR;
if (!err) {
if (fileType)
err = SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, (which == B_LARGE_ICON), B_META_MIME_MODIFIED);
else
err = SendMonitorUpdate(B_ICON_CHANGED, type, (which == B_LARGE_ICON), B_META_MIME_MODIFIED);
}
return err;
}
@ -363,12 +387,48 @@ Database::SetPreferredApp(const char *type, const char *signature, app_verb verb
if (!err)
err = write_mime_attr(type, kPreferredAppAttr, signature, strlen(signature)+1,
kPreferredAppType, &didCreate);
if (!err && didCreate)
err = SendInstallNotification(type);
if (!err)
err = SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_MODIFIED);
return err;
}
// 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)
{
DBG(OUT("Database::SetSnifferRule()\n"));
bool didCreate = false;
status_t err = (type && rule) ? B_OK : B_BAD_VALUE;
if (!err)
err = write_mime_attr(type, kSnifferRuleAttr, rule, strlen(rule)+1,
kSnifferRuleType, &didCreate);
if (!err && didCreate)
err = SendInstallNotification(type);
if (!err)
err = SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_MODIFIED);
return err;
}
// SetSupportedTypes
/*! \brief Sets the list of MIME types supported by the MIME type and
syncs the internal supporting apps database either partially or
completely.
Please see BMimeType::SetSupportedTypes() for details.
\param type The mime type of interest
\param types The supported types to be assigned to the file.
\param syncAll \c true to also synchronize the previously supported
types, \c false otherwise.
\return
- \c B_OK: success
- other error codes: failure
*/
status_t
Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSync)
{
@ -389,6 +449,9 @@ Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSy
// Write the attr
if (!err)
err = write_mime_attr_message(type, kSupportedTypesAttr, types, &didCreate);
// Notify the monitor if we created the type when we opened it
if (!err && didCreate)
err = SendInstallNotification(type);
// Update the supporting apps map
if (!err)
err = fSupportingApps.SetSupportedTypes(type, types, fullSync);
@ -398,24 +461,71 @@ Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSy
return err;
}
// GetInstalledSupertypes
/*! \brief Fetches a BMessage listing all the MIME supertypes currently
installed in the MIME database.
The types are copied into the \c "super_types" field of the passed-in \c BMessage.
The \c BMessage must be pre-allocated.
\param super_types Pointer to a pre-allocated \c BMessage into which the
MIME supertypes will be copied.
\return
- \c B_OK: Success
- "error code": Failure
*/
status_t
Database::GetInstalledSupertypes(BMessage *supertypes)
{
return fInstalledTypes.GetInstalledSupertypes(supertypes);
}
// GetInstalledTypes
/*! \brief Fetches a BMessage listing all the MIME types currently installed
in the MIME database.
The types are copied into the \c "types" field of the passed-in \c BMessage.
The \c BMessage must be pre-allocated.
\param types Pointer to a pre-allocated \c BMessage into which the
MIME types will be copied.
\return
- \c B_OK: Success
- "error code": Failure
*/
status_t
Database::GetInstalledTypes(BMessage *types)
{
return fInstalledTypes.GetInstalledTypes(types);
}
// GetInstalledTypes
/*! \brief Fetches a BMessage listing all the MIME subtypes of the given
supertype currently installed in the MIME database.
The types are copied into the \c "types" field of the passed-in \c BMessage.
The \c BMessage must be pre-allocated.
\param super_type Pointer to a string containing the MIME supertype whose
subtypes you wish to retrieve.
\param subtypes Pointer to a pre-allocated \c BMessage into which the appropriate
MIME subtypes will be copied.
\return
- \c B_OK: Success
- "error code": Failure
*/
status_t
Database::GetInstalledTypes(const char *supertype, BMessage *subtypes)
{
return fInstalledTypes.GetInstalledTypes(supertype, subtypes);
}
// GetSupportingApps
/*! \brief Fetches a \c BMessage containing a list of MIME signatures of
applications that are able to handle files of this MIME type.
Please see BMimeType::GetSupportingApps() for more details.
*/
status_t
Database::GetSupportingApps(const char *type, BMessage *signatures)
{
@ -520,12 +630,23 @@ status_t
Database::StopWatching(BMessenger target)
{
DBG(OUT("Database::StopWatching()\n"));
status_t err = fMonitorMessengers.find(target) != fMonitorMessengers.end() ? B_OK : B_ENTRY_NOT_FOUND;
status_t err = target.IsValid() ? B_OK : B_BAD_VALUE;
if (!err)
err = fMonitorMessengers.find(target) != fMonitorMessengers.end() ? B_OK : B_ENTRY_NOT_FOUND;
if (!err)
fMonitorMessengers.erase(target);
return err;
}
// DeleteAppHint
//! Deletes the app hint attribute for the given type
/*! A \c B_APP_HINT_CHANGED notification is sent to the mime monitor service.
\param type The mime type of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteAppHint(const char *type)
{
@ -535,6 +656,15 @@ Database::DeleteAppHint(const char *type)
return err;
}
// DeleteAttrInfo
//! Deletes the attribute info attribute for the given type
/*! A \c B_ATTR_INFO_CHANGED notification is sent to the mime monitor service.
\param type The mime type of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteAttrInfo(const char *type)
{
@ -544,6 +674,15 @@ Database::DeleteAttrInfo(const char *type)
return err;
}
// DeleteShortDescription
//! Deletes the short description attribute for the given type
/*! A \c B_SHORT_DESCRIPTION_CHANGED notification is sent to the mime monitor service.
\param type The mime type of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteShortDescription(const char *type)
{
@ -553,6 +692,15 @@ Database::DeleteShortDescription(const char *type)
return err;
}
// DeleteLongDescription
//! Deletes the long description attribute for the given type
/*! A \c B_LONG_DESCRIPTION_CHANGED notification is sent to the mime monitor service.
\param type The mime type of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteLongDescription(const char *type)
{
@ -562,6 +710,15 @@ Database::DeleteLongDescription(const char *type)
return err;
}
// DeleteFileExtensions
//! Deletes the associated file extensions attribute for the given type
/*! A \c B_FILE_EXTENSIONS_CHANGED notification is sent to the mime monitor service.
\param type The mime type of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteFileExtensions(const char *type)
{
@ -571,6 +728,16 @@ Database::DeleteFileExtensions(const char *type)
return err;
}
// DeleteIcon
//! Deletes the icon of the given size for the given type
/*! A \c B_ICON_CHANGED notification is sent to the mime monitor service.
\param type The mime type of interest
\param which The icon size of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteIcon(const char *type, icon_size which)
{
@ -581,6 +748,22 @@ Database::DeleteIcon(const char *type, icon_size which)
return err;
}
// DeleteIconForType
/*! \brief Deletes the icon of the given size associated with the given file type for the given
application signature.
(If this function seems confusing, please see BMimeType::GetIconForType() for a
better description of what the *IconForType() functions are used for.)
A \c B_ICON_FOR_TYPE_CHANGED notification is sent to the mime monitor service.
\param type The mime type of the application whose custom icon you are deleting.
\param which The mime type for which you no longer wish \c type to have a custom icon.
\param which The icon size of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteIconForType(const char *type, const char *fileType, icon_size which)
{
@ -596,6 +779,16 @@ Database::DeleteIconForType(const char *type, const char *fileType, icon_size wh
return err;
}
// DeletePreferredApp
//! Deletes the preferred app for the given app verb for the given type
/*! A \c B_PREFERRED_APP_CHANGED notification is sent to the mime monitor service.
\param type The mime type of interest
\param which The app verb of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeletePreferredApp(const char *type, app_verb verb = B_OPEN)
{
@ -618,6 +811,17 @@ Database::DeletePreferredApp(const char *type, app_verb verb = B_OPEN)
return err;
}
// DeleteSnifferRule
//! Deletes the sniffer rule for the given type
/*! A \c B_SNIFFER_RULE_CHANGED notification is sent to the mime monitor service,
and the corresponding rule is removed from the internal database of sniffer
rules.
\param type The mime type of interest
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteSnifferRule(const char *type)
{
@ -627,15 +831,42 @@ Database::DeleteSnifferRule(const char *type)
return err;
}
// DeleteSupportedTypes
//! Deletes the supported types list for the given type
/*! A \c B_SUPPORTED_TYPES_CHANGED notification is sent to the mime monitor service.
If \c fullSync is \c true, the given type is removed from the internal list
of supporting applictions for each previously supported type. If \c fullSync
is \c false, the said removal will occur the next time SetSupportedTypes() or
DeleteSupportedTypes() is called with a \c true \c fullSync paramter, or
\c Delete() is called for the given type.
\param type The mime type of interest
\param fullSync Whether or not to remove the type as a supporting app for
all previously supported types
\return
- B_OK: success
- B_ENTRY_NOT_FOUND: no such attribute existed
- "error code": failure
*/
status_t
Database::DeleteSupportedTypes(const char *type)
Database::DeleteSupportedTypes(const char *type, bool fullSync)
{
status_t err = delete_attribute(type, kSupportedTypesAttr);
// Update the supporting apps database. If fullSync is specified,
// do so even if the supported types attribute didn't exist, as
// stranded types *may* exist in the database due to previous
// calls to {Set,Delete}SupportedTypes() with fullSync == false.
if (!err)
err = fSupportingApps.DeleteSupportedTypes(type, fullSync);
else if (fullSync && err == B_ENTRY_NOT_FOUND)
fSupportingApps.DeleteSupportedTypes(type, fullSync);
// Send a monitor notification
if (!err)
err = SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_DELETED);
return err;
}
// SendInstallNotification
//! \brief Sends a \c B_MIME_TYPE_CREATED notification to the mime monitor service
status_t
Database::SendInstallNotification(const char *type)
{
@ -645,6 +876,7 @@ Database::SendInstallNotification(const char *type)
}
status_t
//! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service
Database::SendDeleteNotification(const char *type)
{
// Tell the backend first

View File

@ -18,6 +18,7 @@
#include <new>
#include <stdio.h>
#include <iostream>
#define DBG(x) x
//#define DBG(x)
@ -114,14 +115,34 @@ SupportingApps::GetSupportingApps(const char *type, BMessage *apps)
}
// SetSupportedTypes
/*! \brief Sets the list of supported types for the given application.
/*! \brief Sets the list of supported types for the given application and
updates the supporting apps mappings.
All types listed as being supported types will including the given
app signature in their list of supporting apps following this call.
If \a fullSync is true, all types previously but no longer supported
by this application with no longer list this application as a
supporting app.
If \a fullSync is false, said previously supported types will be
saved to a "stranded types" mapping and appropriately synchronized
the next time SetSupportedTypes() is called with a \c true \a fullSync
parameter.
The stranded types mapping is properly maintained even in the event
of types being removed and then re-added to the list of supporting
types with consecutive \c false \a fullSync parameters.
\param app The application whose supported types you are setting
\param types Pointer to a \c BMessage containing an array of supported
mime types in its \c Mime::kTypesField field.
mime types in its \c Mime::kTypesField field.
\param fullSync If \c true, \c app is removed as a supporting application
of any types for which it is no longer a supporting application
as of this call to SetSupportedTypes(). If \c false, said
mappings are not updated.
for any types for which it is no longer a supporting application
(including types which were removed as supporting types with
previous callsto SetSupportedTypes(..., false)). If \c false,
said mappings are not updated until the next SetSupportedTypes(..., true)
call.
*/
status_t
SupportingApps::SetSupportedTypes(const char *app, const BMessage *types, bool fullSync)
@ -132,9 +153,11 @@ SupportingApps::SetSupportedTypes(const char *app, const BMessage *types, bool f
std::set<std::string> oldTypes;
std::set<std::string> &newTypes = fSupportedTypes[app];
std::set<std::string> &strandedTypes = fStrandedTypes[app];
// Make a copy of the previous types if we're doing a full sync
if (!err && fullSync)
if (!err)
oldTypes = newTypes;
if (!err) {
// Read through the list of new supported types, creating the new
// supported types list and adding the app as a supporting app for
@ -148,21 +171,51 @@ SupportingApps::SetSupportedTypes(const char *app, const BMessage *types, bool f
AddSupportingApp(type, app);
}
// Update the list of stranded types by removing any types that are newly
// re-supported and adding any types that are newly un-supported
for (std::set<std::string>::const_iterator i = newTypes.begin();
i != newTypes.end();
i++)
{
strandedTypes.erase(*i);
}
for (std::set<std::string>::const_iterator i = oldTypes.begin();
i != oldTypes.end();
i++)
{
if (newTypes.find(*i) == newTypes.end())
strandedTypes.insert(*i);
}
// Now, if we're doing a full sync, remove the app as a supporting
// app for any types it no longer supports
if (fullSync) {
for (std::set<std::string>::iterator i = oldTypes.begin();
i != oldTypes.end();
// app for any of its stranded types and then clear said list of
// stranded types.
if (fullSync) {
for (std::set<std::string>::const_iterator i = strandedTypes.begin();
i != strandedTypes.end();
i++)
{
if (newTypes.find(*i) == newTypes.end())
RemoveSupportingApp((*i).c_str(), app);
}
}
RemoveSupportingApp((*i).c_str(), app);
}
strandedTypes.clear();
}
}
return err;
}
// DeleteSupportedTypes
/*! \brief Clears the given application's supported types list and optionally
removes the application from each of said types' supporting apps list.
\param app The application whose supported types you are clearing
\param fullSync See SupportingApps::SetSupportedTypes()
*/
status_t
SupportingApps::DeleteSupportedTypes(const char *app, bool fullSync)
{
BMessage types;
return SetSupportedTypes(app, &types, fullSync);
}
// AddSupportingApp
/*! \brief Adds the given application signature to the set of supporting
apps for the given type.
@ -210,6 +263,7 @@ SupportingApps::BuildSupportingAppsTable()
{
fSupportedTypes.clear();
fSupportingApps.clear();
fStrandedTypes.clear();
BDirectory dir;
status_t err = dir.SetTo(kApplicationDatabaseDir.c_str());

View File

@ -307,6 +307,28 @@ get_preferred_app(const char *type, char *signature, app_verb verb = B_OPEN)
return err >= 0 ? B_OK : err ;
}
// get_sniffer_rule
/*! \brief Fetches the sniffer rule for the given MIME type.
\param type The MIME type of interest
\param result Pointer to a pre-allocated BString into which the type's
sniffer rule is copied.
\return
- \c B_OK: Success
- \c B_ENTRY_NOT_FOUND: No such preferred application exists
- "error code": Failure
*/
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;
}
// get_supported_types
status_t
get_supported_types(const char *type, BMessage *types)

View File

@ -1037,7 +1037,7 @@ Parser::Parse(const char *rule, Rule *result, BString *parseError) {
if (parseError)
parseError->SetTo(ErrorMessage(err, rule).c_str());
delete err;
return B_BAD_MIME_SNIFFER_RULE;
return rule ? B_BAD_MIME_SNIFFER_RULE : B_BAD_VALUE;
}
}

View File

@ -89,44 +89,39 @@ MIMEManager::MessageReceived(BMessage *message)
case B_REG_MIME_GET_INSTALLED_TYPES:
{
BMessage types;
const char *supertype;
err = message->FindString("supertype", &supertype);
if (err == B_NAME_NOT_FOUND)
err = fDatabase.GetInstalledTypes(&types);
err = fDatabase.GetInstalledTypes(&reply);
else if (!err)
err = fDatabase.GetInstalledTypes(supertype, &types);
err = fDatabase.GetInstalledTypes(supertype, &reply);
reply.what = B_REG_RESULT;
reply.AddInt32("result", err);
reply.AddMessage("types", &types);
message->SendReply(&reply, this);
break;
}
case B_REG_MIME_GET_INSTALLED_SUPERTYPES:
{
BMessage types;
err = fDatabase.GetInstalledSupertypes(&types);
err = fDatabase.GetInstalledSupertypes(&reply);
reply.what = B_REG_RESULT;
reply.AddInt32("result", err);
reply.AddMessage("types", &types);
message->SendReply(&reply, this);
break;
}
case B_REG_MIME_GET_SUPPORTING_APPS:
{
BMessage apps;
BMessage reply;
const char *type;
err = message->FindString("type", &type);
if (!err)
err = fDatabase.GetSupportingApps(type, &apps);
err = fDatabase.GetSupportingApps(type, &reply);
reply.what = B_REG_RESULT;
reply.AddInt32("result", err);
reply.AddMessage("signatures", &apps);
message->SendReply(&reply, this);
break;
}
@ -228,7 +223,16 @@ MIMEManager::HandleSetParam(BMessage *message)
if (!err)
err = fDatabase.SetPreferredApp(type, signature, (app_verb)verb);
break;
}
}
case B_REG_MIME_SNIFFER_RULE:
{
const char *rule;
err = message->FindString("sniffer rule", &rule);
if (!err)
err = fDatabase.SetSnifferRule(type, rule);
break;
}
case B_REG_MIME_SUPPORTED_TYPES:
{
@ -324,8 +328,13 @@ MIMEManager::HandleDeleteParam(BMessage *message)
break;
case B_REG_MIME_SUPPORTED_TYPES:
err = fDatabase.DeleteSupportedTypes(type);
break;
{
bool fullSync;
err = message->FindBool("full sync", &fullSync);
if (!err)
err = fDatabase.DeleteSupportedTypes(type, fullSync);
break;
}
default:
err = B_BAD_VALUE;

View File

@ -70,7 +70,9 @@ static const char *testApp2 = "/boot/beos/apps/CDPlayer";
static const char *fakeTestApp = "/__this_isn't_likely_to_exist__";
// BMessage field names
static const char *applicationsField = "applications";
static const char *typeField = "type";
static const char *typesField = "types";
static const char *fileExtField = "extensions";
static const char *attrInfoField_Name = "attr:name";
static const char *attrInfoField_PublicName = "attr:public_name";
@ -195,6 +197,10 @@ MimeTypeTest::Suite() {
&MimeTypeTest::InstalledTypesTest) );
suite->addTest( new TC("BMimeType::Preferred App Test",
&MimeTypeTest::PreferredAppTest) );
suite->addTest( new TC("BMimeType::Supporting Apps Test",
&MimeTypeTest::SupportingAppsTest) );
suite->addTest( new TC("BMimeType::Supported Types Test",
&MimeTypeTest::SupportedTypesTest) );
suite->addTest( new TC("BMimeType::Wildcard Apps Test",
&MimeTypeTest::WildcardAppsTest) );
@ -215,10 +221,6 @@ MimeTypeTest::Suite() {
&MimeTypeTest::SnifferRuleTest) );
suite->addTest( new TC("BMimeType::Sniffing Test",
&MimeTypeTest::SniffingTest) );
// In progress
suite->addTest( new TC("BMimeType::Supporting Apps Test",
&MimeTypeTest::SupportingAppsTest) );
return suite;
@ -2233,7 +2235,7 @@ MimeTypeTest::InstallDeleteTest() {
CHK(type_exists(testType));
CHK(mime.IsInstalled());
#if !TEST_R5
CHK(mime.Install() != B_OK); // We ought to return something standard and logical here
CHK(mime.Install() != B_OK); // We ought to return something standard and logical here, as R5 is random
#endif
CHK(mime.Delete() == B_OK);
CHK(!type_exists(testType));
@ -2271,6 +2273,256 @@ void FillWithMimeTypes(ContainerAdapter &container, BMessage &typeMessage, const
}
}
bool
types_fields_are_identical(const BMessage &msg1, const BMessage &msg2)
{
const char *str1;
const char *str2;
int i = 0;
bool result = true;
while (true) {
status_t err1 = msg1.FindString(typesField, i, &str1);
status_t err2 = msg2.FindString(typesField, i, &str2);
if (err1 != err2) {
result = false;
break;
}
if (err1 != B_OK)
break;
result &= to_lower(str1) == to_lower(str2);
i++;
}
return result;
}
bool
is_supporting_app_for_all_types_in_message(const char *app, const BMessage &msg)
{
const char *str;
bool result = true;
for (int i = 0; msg.FindString(typesField, i, &str) == B_OK; i++) {
BMimeType supportedType(str);
BMessage appMsg;
// Get a list of supporting apps
CHK(supportedType.InitCheck() == B_OK);
CHK(supportedType.GetSupportingApps(&appMsg) == B_OK);
// cout << "-----------------------------------------------------------" << endl;
// cout << str << endl;
// cout << "-----------------------------------------------------------" << endl;
// appMsg.PrintToStream();
// Look for our supporting app
int32 directlySupportingAppsCount;
CHK(appMsg.FindInt32("be:sub", &directlySupportingAppsCount) == B_OK);
bool foundType = false;
const char *supportingApp;
for (int j = 0;
j < directlySupportingAppsCount
&& appMsg.FindString(applicationsField, &supportingApp) == B_OK;
j++)
{
foundType |= to_lower(app) == to_lower(supportingApp);
}
result &= foundType;
}
return result;
}
void
MimeTypeTest::SupportedTypesTest() {
#if TEST_R5
Outputf("(no tests actually performed for R5 version)\n");
#else
// Create some messages to sling around
const int32 WHAT = 0;
BMessage msg1a(WHAT), msg1b(WHAT), msg2(WHAT), msg3(WHAT), msgEmpty(WHAT);
CHK(msg3.AddString(typesField, testType1) == B_OK);
CHK(msg3.AddString(typesField, testType2) == B_OK);
CHK(msg3.AddString(typesField, testType3) == B_OK);
CHK(msg2.AddString(typesField, testType2) == B_OK);
CHK(msg2.AddString(typesField, testType3) == B_OK);
CHK(msg1a.AddString(typesField, testType5) == B_OK);
CHK(msg1b.AddString(typesField, testType2) == B_OK);
CHK(msg1a == msg1a);
CHK(msg1b == msg1b);
CHK(msg2 == msg2);
CHK(msg3 == msg3);
CHK(msg1a != msg2);
CHK(msg1a != msg3);
CHK(msg1a != msgEmpty);
// Uninitialized
NextSubTest();
{
BMimeType mime;
BMessage msg;
CHK(mime.InitCheck() == B_NO_INIT);
CHK(mime.SetSupportedTypes(&msg, true) != B_OK);
CHK(mime.SetSupportedTypes(&msg, false) != B_OK);
CHK(mime.GetSupportedTypes(&msg) != B_OK);
CHK(mime.DeleteSupportedTypes() != B_OK);
}
// Test that deleting a type from the database also removes
// the app as a supporting app for all types it previously
// supported
NextSubTest();
{
BMessage msg;
BMimeType mime(testType);
CHK(mime.InitCheck() == B_OK);
if (!mime.IsInstalled())
CHK(mime.Install() == B_OK);
// Set a list of supported types
CHK(mime.SetSupportedTypes(&msg3, true) == B_OK);
// Verify that each of those types now lists the
// type as a directly supporting app
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true);
// Delete the type
CHK(mime.Delete() == B_OK);
// Verify that each of those types no longer lists the
// type as a directly supporting app
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == false);
}
// Test that SetSupportedTypes(..., false) does not remove the app as a supporting
// app for newly unsupported types, while SetSupportedTypes(..., true) does. Also
// test that supported types stranded by multiple sequential calls to
// SetSupportedTypes(..., false) are properly updated so as to no longer list the
// app as a supporting app once SetSupportedTypes(..., true) is finally called.
NextSubTest();
{
BMessage msg;
BMimeType mime(testType);
CHK(mime.InitCheck() == B_OK);
// Uninstall then reinstall to clear attributes, etc
if (mime.IsInstalled())
CHK(mime.Delete() == B_OK);
if (!mime.IsInstalled())
CHK(mime.Install() == B_OK);
CHK(mime.IsInstalled());
// Set a list of supported types
CHK(mime.SetSupportedTypes(&msg3, true) == B_OK);
CHK(mime.GetSupportedTypes(&msg) == B_OK);
CHK(types_fields_are_identical(msg3, msg) == true);
CHK(types_fields_are_identical(msg2, msg) == false);
CHK(types_fields_are_identical(msg1a, msg) == false);
CHK(types_fields_are_identical(msg1b, msg) == false);
CHK(types_fields_are_identical(msgEmpty, msg) == false);
// Verify that each of those types now lists the
// type as a directly supporting app
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true);
// Set (no sync) to a new list of supported types containing one
// fewer type than the original list
CHK(mime.SetSupportedTypes(&msg2, false) == B_OK);
CHK(mime.GetSupportedTypes(&msg) == B_OK);
CHK(types_fields_are_identical(msg3, msg) == false);
CHK(types_fields_are_identical(msg2, msg) == true);
CHK(types_fields_are_identical(msg1a, msg) == false);
CHK(types_fields_are_identical(msg1b, msg) == false);
CHK(types_fields_are_identical(msgEmpty, msg) == false);
// Verify that the app is still listed as a supporting app for
// *all* of the originally supported types (even the one no longer
// listed as being supported)
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true);
// Set (no sync) to a new list of supported types containing an
// entirely new, never supported type
CHK(mime.SetSupportedTypes(&msg1a, false) == B_OK);
CHK(mime.GetSupportedTypes(&msg) == B_OK);
CHK(types_fields_are_identical(msg3, msg) == false);
CHK(types_fields_are_identical(msg2, msg) == false);
CHK(types_fields_are_identical(msg1a, msg) == true);
CHK(types_fields_are_identical(msg1b, msg) == false);
CHK(types_fields_are_identical(msgEmpty, msg) == false);
// Verify that the app is still listed as a supporting app for
// *all* of the originally supported types (none of which are
// supported any longer) as well as the newly supported type.
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true);
// Set (no sync) to a new list of supported types containing only
// one of the originally supported types that had been previously
// removed.
CHK(mime.SetSupportedTypes(&msg1b, false) == B_OK);
CHK(mime.GetSupportedTypes(&msg) == B_OK);
CHK(types_fields_are_identical(msg3, msg) == false);
CHK(types_fields_are_identical(msg2, msg) == false);
CHK(types_fields_are_identical(msg1a, msg) == false);
CHK(types_fields_are_identical(msg1b, msg) == true);
CHK(types_fields_are_identical(msgEmpty, msg) == false);
// Verify that the app is still listed as a supporting app for
// *all* of the originally supported types (only one of which is
// supported any longer) as well as the previous supported type.
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == true);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true);
// Set (with sync) to the same list as last time (containing the
// one type from the original list of supported types)
CHK(mime.SetSupportedTypes(&msg1b, true) == B_OK);
CHK(mime.GetSupportedTypes(&msg) == B_OK);
CHK(types_fields_are_identical(msg3, msg) == false);
CHK(types_fields_are_identical(msg2, msg) == false);
CHK(types_fields_are_identical(msg1a, msg) == false);
CHK(types_fields_are_identical(msg1b, msg) == true);
CHK(types_fields_are_identical(msgEmpty, msg) == false);
// Verify that the app is now only listed as a supporting app for the
// most recently supported type.
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true);
// Test SetSupportedTypes(NULL, false) for shits and giggles
CHK(mime.SetSupportedTypes(NULL, false) == B_OK);
CHK(mime.GetSupportedTypes(&msg) == B_ENTRY_NOT_FOUND);
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true);
// Now test that SetSupportedTypes(NULL, true) updates the supporting
// apps mappings, even if the supported types attribute has already
// been removed.
CHK(mime.SetSupportedTypes(NULL, true) == B_ENTRY_NOT_FOUND);
CHK(mime.GetSupportedTypes(&msg) == B_ENTRY_NOT_FOUND);
CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false);
CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == false);
}
#endif // #if TEST_R5 else
}
void
MimeTypeTest::SupportingAppsTest() {
/* {
@ -2305,6 +2557,7 @@ MimeTypeTest::SupportingAppsTest() {
std::set<std::string> typeList; // Stores all installed MIME types
std::set<std::string> appList; // Stores all installed application subtypes
std::map< std::string, std::set<std::string> > typeAppMap; // Stores mapping of types to apps that support them
std::map< std::string, std::set<std::string> > fakeTypeAppMap; // Used to keep timing info for R5 and OBOS tests orthogonal
// Get a list of all the types in the database
{
@ -2362,7 +2615,8 @@ MimeTypeTest::SupportingAppsTest() {
type++)
{
NextSubTest();
typeAppMap[*type].insert(app);
typeAppMap[*type].insert(app);
fakeTypeAppMap[*type].insert(app);
}
} else {
// Just in case some bozo writes something other than a flattened
@ -2378,7 +2632,7 @@ MimeTypeTest::SupportingAppsTest() {
}
}
#if !TEST_R5
//#if !TEST_R5
// Now, add in all the types listed in MIME_DB_DIR/__mime_table
{
BEntry entry((std::string(mimeDatabaseDir) + "/__mime_table").c_str());
@ -2402,12 +2656,16 @@ MimeTypeTest::SupportingAppsTest() {
const char *app;
for (int j = 0; j < count; j++) {
CHK(msg.FindString(type, j, &app) == B_OK);
#if TEST_R5
typeAppMap[type].insert(to_lower(app));
#else
fakeTypeAppMap[type].insert(to_lower(app));
#endif
}
}
}
}
#endif
//#endif
// For each installed type, get a list of the supported apps, and
// verify that the list matches the list we generated. Also check
@ -3147,13 +3405,13 @@ MimeTypeTest::MonitoringTest()
CHK(target3.IsValid() == false);
// R5: An invalid messenger is fine for any reason?!
#if !TEST_R5
CHK(RES(BMimeType::StartWatching(target3)) == B_BAD_VALUE);
CHK(BMimeType::StartWatching(target3) == B_BAD_VALUE);
#endif
CHK(BMimeType::StartWatching(target) == B_OK);
#if !TEST_R5
CHK(BMimeType::StopWatching(target3) == B_BAD_VALUE);
#endif
CHK(BMimeType::StopWatching(target2) == B_BAD_VALUE);
CHK(BMimeType::StopWatching(target2) != B_OK); // R5 == B_BAD_VALUE, OBOS == B_ENTRY_NOT_FOUND
CHK(BMimeType::StopWatching(target) == B_OK);
// delete
CHK(type.Delete() == B_OK);
@ -3814,8 +4072,15 @@ MimeTypeTest::SnifferRuleTest()
{ "0.5 \n [0:3] \t ('ABCD' \n | 'abcd' | 'EFGH')", NULL },
{ "0.8 [ 0 : 3 ] ('ABCDEFG' | 'abcdefghij')", NULL },
{ "0.8 [0:3] ('ABCDEFG' & 'abcdefg')", NULL },
// These two rules are accepted by the R5 sniffer checker, but not
// by the parser. Thus, we're not accepting them with either.
#if TEST_R5
{ "1.0 ('ABCD') | ('EFGH')", NULL },
{ "1.0 [0:3] ('ABCD') | [2:4] ('EFGH')", NULL },
#else
{ "1.0 ('ABCD') | ('EFGH')", "Sniffer pattern error: missing pattern" },
{ "1.0 [0:3] ('ABCD') | [2:4] ('EFGH')", "Sniffer pattern error: missing pattern" },
#endif
{ "0.8 [0:3] (\\077Mkl0x34 & 'abcdefgh')", NULL },
{ "0.8 [0:3] (\\077034 & 'abcd')", NULL },
{ "0.8 [0:3] (\\077\\034 & 'ab')", NULL },
@ -3834,55 +4099,229 @@ MimeTypeTest::SnifferRuleTest()
{ "0.8 [0:3] (\"ab'\" & 'abc')", NULL },
{ "0.8 [0:3] (\"ab\\\\\" & 'abc')", NULL },
{ "0.8 [-5:-3] (\"abc\" & 'abc')", NULL },
// Also accepted by the R5 sniffer but not the R5 parser. We reject.
#if TEST_R5
{ "0.8 [5:3] (\"abc\" & 'abc')", NULL },
{ "1.2 ('ABCD')", NULL },
#else
{ "0.8 [5:3] (\"abc\" & 'abc')", "Sniffer Parser Error -- Invalid range: [5:3]" },
#endif
{ "1.0 ('ABCD')", NULL },
{ ".2 ('ABCD')", NULL },
{ "0. ('ABCD')", NULL },
{ "-1 ('ABCD')", NULL },
{ "1 ('ABCD')", NULL },
{ "+1 ('ABCD')", NULL },
{ "1E25 ('ABCD')", NULL },
// We accept extended notation floating point numbers now, but
// not invalid priorities. Thus our checker chokes on these rules,
// whilest R5's does not
#if TEST_R5
{ "1E25 ('ABCD')", NULL },
{ "1e25 ('ABCD')", NULL },
#else
{ "1E25 ('ABCD')", "Sniffer pattern error: invalid priority" },
{ "1e25 ('ABCD')", "Sniffer pattern error: invalid priority" },
#endif
// R5 chokes on this rule :-( Why? I don't know. :-)
#if TEST_R5
{ "1e-3 ('ABCD')", "Sniffer pattern error: missing pattern" },
#else
{ "1e-3 ('ABCD')", NULL },
#endif
{ "+.003e2 ('ABCD')", NULL },
// R5 chokes on this one too. See how much better our checker/parser is? ;-)
#if TEST_R5
{ "-123e-9999999999 ('ABCD')", "Sniffer pattern error: bad token" }, // Hooray for the stunning accuracy of floating point :-)
#else
{ "-123e-9999999999 ('ABCD')", NULL }, // Hooray for the stunning accuracy of floating point :-)
#endif
// invalid rules
{ "0.0 ('')", "Sniffer pattern error: illegal empty pattern" },
{ "('ABCD')", "Sniffer pattern error: match level expected" },
{ "[0:3] ('ABCD')", "Sniffer pattern error: match level expected" },
{ "0.0 ('')",
"Sniffer pattern error: illegal empty pattern" },
{ "('ABCD')",
"Sniffer pattern error: match level expected" },
{ "[0:3] ('ABCD')",
"Sniffer pattern error: match level expected" },
{ "0.8 [0:3] ( | 'abcdefghij')",
"Sniffer pattern error: missing pattern" },
{ "0.8 [0:3] ('ABCDEFG' | )",
"Sniffer pattern error: missing pattern" },
{ "[0:3] ('ABCD')", "Sniffer pattern error: match level expected" },
{ "1.0 (ABCD')", "Sniffer pattern error: misplaced single quote" },
{ "1.0 ('ABCD)", "Sniffer pattern error: unterminated rule" },
{ "1.0 (ABCD)", "Sniffer pattern error: missing pattern" },
{ "1.0 (ABCD 'ABCD')", "Sniffer pattern error: missing pattern" },
{ "1.0 'ABCD')", "Sniffer pattern error: missing pattern" },
{ "1.0 ('ABCD'", "Sniffer pattern error: unterminated rule" },
{ "1.0 'ABCD'", "Sniffer pattern error: missing sniff pattern" },
{ "[0:3] ('ABCD')",
"Sniffer pattern error: match level expected" },
{ "1.0 (ABCD')",
#if TEST_R5
"Sniffer pattern error: misplaced single quote"
#else
"Sniffer pattern error: invalid character 'A'"
#endif
},
{ "1.0 ('ABCD)",
#if TEST_R5
"Sniffer pattern error: unterminated rule"
#else
"Sniffer pattern error: unterminated single-quoted string"
#endif
},
{ "1.0 (ABCD)",
#if TEST_R5
"Sniffer pattern error: missing pattern"
#else
"Sniffer pattern error: invalid character 'A'"
#endif
},
{ "1.0 (ABCD 'ABCD')",
#if TEST_R5
"Sniffer pattern error: missing pattern"
#else
"Sniffer pattern error: invalid character 'A'"
#endif
},
{ "1.0 'ABCD')",
#if TEST_R5
"Sniffer pattern error: missing pattern"
#else
"Sniffer pattern error: missing pattern"
#endif
},
{ "1.0 ('ABCD'",
"Sniffer pattern error: unterminated rule" },
{ "1.0 'ABCD'",
#if TEST_R5
"Sniffer pattern error: missing sniff pattern"
#else
"Sniffer pattern error: missing pattern"
#endif
},
{ "0.5 [0:3] ('ABCD' | 'abcd' | [13] 'EFGH')",
"Sniffer pattern error: missing pattern" },
"Sniffer pattern error: missing pattern" },
{ "0.5('ABCD'|'abcd'|[13]'EFGH')",
"Sniffer pattern error: missing pattern" },
"Sniffer pattern error: missing pattern" },
{ "0.5[0:3]([10]'ABCD'|[17]'abcd'|[13]'EFGH')",
"Sniffer pattern error: missing pattern" },
"Sniffer pattern error: missing pattern" },
{ "0.8 [0x10:3] ('ABCDEFG' | 'abcdefghij')",
"Sniffer pattern error: pattern offset expected" },
"Sniffer pattern error: pattern offset expected" },
{ "0.8 [0:A] ('ABCDEFG' | 'abcdefghij')",
"Sniffer pattern error: pattern range end expected" },
#if TEST_R5
"Sniffer pattern error: pattern range end expected"
#else
"Sniffer pattern error: invalid character 'A'"
#endif
},
{ "0.8 [0:3] ('ABCDEFG' & 'abcdefghij')",
"Sniffer pattern error: pattern and mask lengths do not match" },
"Sniffer pattern error: pattern and mask lengths do not match" },
{ "0.8 [0:3] ('ABCDEFG' & 'abcdefg' & 'xyzwmno')",
"Sniffer pattern error: unterminated rule" },
{ "0.8 [0:3] (\\g&b & 'a')", "Sniffer pattern error: missing mask" },
#if TEST_R5
"Sniffer pattern error: unterminated rule"
#else
"Sniffer pattern error: expecting '|', ')', or possibly '&'"
#endif
},
{ "0.8 [0:3] (\\g&b & 'a')",
#if TEST_R5
"Sniffer pattern error: missing mask"
#else
"Sniffer pattern error: invalid character 'b'"
#endif
},
{ "0.8 [0:3] (\\19 & 'a')",
"Sniffer pattern error: pattern and mask lengths do not match" },
"Sniffer pattern error: pattern and mask lengths do not match" },
{ "0.8 [0:3] (0x345 & 'ab')",
"Sniffer pattern error: bad hex literal" },
"Sniffer pattern error: bad hex literal" },
{ "0.8 [0:3] (0x3457M & 'abc')",
"Sniffer pattern error: expecting '|' or '&'" },
#if TEST_R5
"Sniffer pattern error: expecting '|' or '&'"
#else
"Sniffer pattern error: invalid character 'M'"
#endif
},
{ "0.8 [0:3] (0x3457\\7 & 'abc')",
"Sniffer pattern error: expecting '|' or '&'" },
#if TEST_R5
"Sniffer pattern error: expecting '|' or '&'"
#else
"Sniffer pattern error: expecting '|', ')', or possibly '&'"
#endif
},
// Miscellaneous tests designed to hit every remaining
// relevant "throw new Err()" statement in our scanner.
// R5 versions may come later, but I don't really see any
// good reason why at this point...
#if !TEST_R5
{ "\x03 ", "Sniffer pattern error: invalid character '\x03'" },
{ "\"blah", "Sniffer pattern error: unterminated double-quoted string" },
{ "0xThisIsNotAHexCode", "Sniffer pattern error: incomplete hex code" },
{ "0xAndNeitherIsThis:-)", "Sniffer pattern error: bad hex literal" },
{ ".NotAFloat", "Sniffer pattern error: incomplete floating point number" },
{ "-NotANumber", "Sniffer pattern error: incomplete signed number" },
{ "+NotANumber", "Sniffer pattern error: incomplete signed number" },
{ "0.0e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "1.0e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ ".0e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "0e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "1e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1.e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1.e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1.0e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1.0e", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "0.0e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "1.0e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ ".0e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "0e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "1e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1.e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1.e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1.0e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1.0e-", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "0.0e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "1.0e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ ".0e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "0e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "1e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1.e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1.e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "-1.0e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "+1.0e+", "Sniffer pattern error: incomplete extended-notation floating point number" },
{ "\\11\\", "Sniffer pattern error: incomplete escape sequence" },
{ "\"Escape!! \\", "Sniffer pattern error: incomplete escape sequence" },
{ "'Escape!! \\", "Sniffer pattern error: incomplete escape sequence" },
{ "\\x", "Sniffer pattern error: incomplete escaped hex code" },
{ "\\xNotAHexCode", "Sniffer pattern error: incomplete escaped hex code" },
{ "\\xAlsoNotAHexCode", "Sniffer pattern error: incomplete escaped hex code" },
{ "\\x0", "Sniffer pattern error: incomplete escaped hex code" },
{ "1.0 (\\377)", NULL },
{ "\\400", "Sniffer pattern error: invalid octal literal (octals must be between octal 0 and octal 377 inclusive)" },
{ "\\777", "Sniffer pattern error: invalid octal literal (octals must be between octal 0 and octal 377 inclusive)" },
{ "1.0 (\\800)", NULL },
{ NULL, "Sniffer pattern error: NULL pattern" },
{ "-2", "Sniffer pattern error: invalid priority" },
{ "+2", "Sniffer pattern error: invalid priority" },
{ "1.0", "Sniffer pattern error: missing expression" },
#endif // !TEST_R5
//! \todo Our parser chokes on this rule and I have no idea why
// I don't currently understand what's wrong with the following rule...
// R5 rejects it though, for whatever reason.
#if TEST_R5
{ "1E-25 ('ABCD')", "Sniffer pattern error: missing pattern" },
#else
// { "1E-25 ('ABCD')", NULL },
#endif
};
const int testCaseCount = sizeof(testCases) / sizeof(test_case);
BMimeType type;
CHK(type.SetTo(testType) == B_OK);
@ -3893,18 +4332,37 @@ MimeTypeTest::SnifferRuleTest()
BString parseError;
status_t error = BMimeType::CheckSnifferRule(testCase.rule,
&parseError);
// printf("\n---------------------\n");
// printf("rule == '%s', %s\n", testCase.rule, (testCase.error ? "should not pass" : "should pass"));
if (testCase.error == NULL) {
if (error != B_OK)
printf("error: %s\n", parseError.String());
printf("\nerror:\n%s\n", parseError.String());
CHK(error == B_OK);
CHK(type.SetSnifferRule(testCase.rule) == B_OK);
BString rule;
CHK(type.GetSnifferRule(&rule) == B_OK);
CHK(rule == testCase.rule);
} else {
CHK(error == B_BAD_MIME_SNIFFER_RULE);
// printf("error == 0x%lx\n", error);
// if (parseError.FindLast(testCase.error) < 0) {
// printf("\nexpected:\n%s\n", testCase.error);
// printf("\nfound:\n%s\n", parseError.String());
// }
CHK(error == (testCase.rule ? B_BAD_MIME_SNIFFER_RULE : B_BAD_VALUE));
CHK(parseError.FindLast(testCase.error) >= 0);
// R5 treats a NULL rule string as an error, and thus R5::SetSnifferRule(NULL) fails.
// We also treat a NULL rule string as an error, but OBOS::SetSnifferRule(NULL) does
// not fail, as all OBOS::BMimeType::Set*(NULL) calls are equivalent to the
// corresponding OBOS::BMimeType::Delete*() calls.
#if TEST_R5
CHK(type.SetSnifferRule(testCase.rule) == B_BAD_MIME_SNIFFER_RULE);
#else
if (testCase.rule)
CHK(type.SetSnifferRule(testCase.rule) == B_BAD_MIME_SNIFFER_RULE);
else
CHK(type.SetSnifferRule(testCase.rule) == B_OK);
#endif
}
}
@ -3920,23 +4378,38 @@ printf("error: %s\n", parseError.String());
CHK(type.GetSnifferRule(NULL) == B_BAD_VALUE);
#endif
BString rule;
// NULL rule to SetSnifferRule unsets the attribute
NextSubTest();
#if TEST_R5
CHK(type.IsInstalled() == true);
CHK(type.SetSnifferRule(NULL) == B_OK);
BString rule;
CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND);
#else
CHK(type.IsInstalled() == true);
if (type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND)
CHK(type.SetSnifferRule("0.0 ('abc')") == B_OK);
CHK(type.GetSnifferRule(&rule) == B_OK);
CHK(type.SetSnifferRule(NULL) == B_OK);
CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND);
CHK(type.SetSnifferRule(NULL) == B_ENTRY_NOT_FOUND);
#endif
// bad args: uninstalled type
CHK(type.Delete() == B_OK);
CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND);
CHK(type.SetSnifferRule("0.0 ('ABC')") == B_OK);
#if TEST_R5
CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND);
#else
CHK(type.GetSnifferRule(&rule) == B_OK);
#endif
// bad args: uninitialized BMimeType
type.Unset();
CHK(type.GetSnifferRule(&rule) == B_BAD_VALUE);
CHK(type.SetSnifferRule("0.0 ('ABC')") == B_BAD_VALUE);
CHK(type.GetSnifferRule(&rule) != B_OK);
CHK(type.SetSnifferRule("0.0 ('ABC')") != B_OK);
}
// helper class for GuessMimeType() tests
@ -4016,8 +4489,12 @@ MimeTypeTest::SniffingTest()
CHK(type.SetSnifferRule("0.4 ('ABCD')") == B_OK);
CHK(type.SetTo(testType2) == B_OK);
CHK(type.Install() == B_OK);
// This rule is invalid!
#if TEST_R5
// 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);
#endif
CHK(type.SetTo(testType3) == B_OK);
CHK(type.Install() == B_OK);
CHK(type.SetSnifferRule("0.3 [0:8] ('ABCD' | 'EFGH')") == B_OK);

View File

@ -46,6 +46,7 @@ public:
void ShortDescriptionTest();
void PreferredAppTest();
void SupportingAppsTest();
void SupportedTypesTest();
void WildcardAppsTest();
void InitTest();