1//---------------------------------------------------------------------- 2// This software is part of the Haiku distribution and is covered 3// by the MIT License. 4//--------------------------------------------------------------------- 5/*! 6 \file MimeType.cpp 7 BMimeType implementation. 8*/ 9#include "MimeType.h" 10 11#include <Bitmap.h> 12 13#include <ctype.h> // For tolower() 14#include <new> // For new(nothrow) 15#include <stdio.h> // For printf() 16#include <string.h> // For strncpy() 17 18using namespace BPrivate; 19 20// Private helper functions 21bool isValidMimeChar(const char ch); 22status_t toLower(const char *str, char *result); 23 24//using namespace BPrivate::Storage::Mime; 25using namespace std; 26 27const char *B_PEF_APP_MIME_TYPE = "application/x-be-executable"; 28const char *B_PE_APP_MIME_TYPE = "application/x-vnd.be-peexecutable"; 29const char *B_ELF_APP_MIME_TYPE = "application/x-vnd.be-elfexecutable"; 30const char *B_RESOURCE_MIME_TYPE = "application/x-be-resource"; 31const char *B_FILE_MIME_TYPE = "application/octet-stream"; 32// Might be defined platform depended, but ELF will certainly be the common 33// format for all platforms anyway. 34const char *B_APP_MIME_TYPE = B_ELF_APP_MIME_TYPE; 35 36// constructor 37/*! \brief Creates an uninitialized BMimeType object. 38*/ 39BMimeType::BMimeType() 40 : fType(NULL) 41 , fCStatus(B_NO_INIT) 42{ 43} 44 45// constructor 46/*! \brief Creates a BMimeType object and initializes it to the supplied 47 MIME type. 48 The supplied string must specify a valid MIME type or supertype. 49 \see SetTo() for further information. 50 \param mimeType The MIME string. 51*/ 52BMimeType::BMimeType(const char *mimeType) 53 : fType(NULL) 54 , fCStatus(B_NO_INIT) 55{ 56 SetTo(mimeType); 57} 58 59// destructor 60/*! \brief Frees all resources associated with this object. 61*/ 62BMimeType::~BMimeType() 63{ 64 Unset(); 65} 66 67// SetTo 68/*! \brief Initializes this object to the supplied MIME type. 69 The supplied string must specify a valid MIME type or supertype. 70 Valid MIME types are given by the following grammar: 71 MIMEType ::= Supertype "/" [ Subtype ] 72 Supertype ::= "application" | "audio" | "image" | "message" 73 | "multipart" | "text" | "video" 74 Subtype ::= MIMEChar MIMEChar* 75 MIMEChar ::= any character except white spaces, CTLs and '/', '<', '>', 76 '@',, ',', ';', ':', '"', '(', ')', '[', ']', '?', '=', '\' 77 (Note: RFC1341 also forbits '.', but it is allowed here.) 78 79 Currently the supertype is not restricted to one of the seven types given, 80 but can be an arbitrary string (obeying the same rule as the subtype). 81 Nevertheless it is a very bad idea to use another supertype. 82 The supplied MIME string is copied; the caller retains the ownership. 83 \param mimeType The MIME string. 84 \return 85 - \c B_OK: Everything went fine. 86 - \c B_BAD_VALUE: \c NULL or invalid \a mimeString. 87 - \c B_NO_MEMORY: Insufficient memory to copy the MIME string. 88*/ 89status_t 90BMimeType::SetTo(const char *mimeType) 91{ 92 if (!mimeType || !BMimeType::IsValid(mimeType)) { 93 fCStatus = B_BAD_VALUE; 94 } else { 95 Unset(); 96 fType = new(std::nothrow) char[strlen(mimeType)+1]; 97 if (fType) { 98 strcpy(fType, mimeType); 99 fCStatus = B_OK; 100 } else { 101 fCStatus = B_NO_MEMORY; 102 } 103 } 104 return fCStatus; 105} 106 107// Unset 108/*! \brief Returns the object to an uninitialized state. 109*/ 110void 111BMimeType::Unset() 112{ 113 if (fType) 114 delete [] fType; 115 fType = NULL; 116 fCStatus = B_NO_INIT; 117} 118 119// InitCheck 120/*! Returns the result of the most recent constructor or SetTo() call. 121 \return 122 - \c B_OK: The object is properly initialized. 123 - A specific error code otherwise. 124*/ 125status_t 126BMimeType::InitCheck() const 127{ 128 return fCStatus; 129} 130 131// Type 132/*! \brief Returns the MIME string represented by this object. 133 \return The MIME string, if the object is properly initialized, \c NULL 134 otherwise. 135*/ 136const char * 137BMimeType::Type() const 138{ 139 return fType; 140} 141 142// IsValid 143/*! \brief Returns whether the object represents a valid MIME type. 144 \see SetTo() for further information. 145 \return \c true, if the object is properly initialized, \c false 146 otherwise. 147*/ 148bool 149BMimeType::IsValid() const 150{ 151 return InitCheck() == B_OK && BMimeType::IsValid(Type()); 152} 153 154// IsSupertypeOnly 155/*! \brief Returns whether this objects represents a supertype. 156 \return \c true, if the object is properly initialized and represents a 157 supertype, \c false otherwise. 158*/ 159bool 160BMimeType::IsSupertypeOnly() const 161{ 162 if (fCStatus == B_OK) { 163 // We assume here fCStatus will be B_OK *only* if 164 // the MIME string is valid 165 int len = strlen(fType); 166 for (int i = 0; i < len; i++) { 167 if (fType[i] == '/') 168 return false; 169 } 170 return true; 171 } else 172 return false; 173} 174 175// IsInstalled 176//! Returns whether or not this type is currently installed in the MIME database 177/*! To add the MIME type to the database, call \c Install(). 178 To remove the MIME type from the database, call \c Delete(). 179 180 \return 181 - \c true: The MIME type is currently installed in the database 182 - \c false: The MIME type is not currently installed in the database 183*/ 184// bool 185// BMimeType::IsInstalled() const 186// { 187// return InitCheck() == B_OK && is_installed(Type()); 188// } 189 190// GetSupertype 191/*! \brief Returns the supertype of the MIME type represented by this object. 192 The supplied object is initialized to this object's supertype. If this 193 BMimeType is not properly initialized, the supplied object will be Unset(). 194 \param superType A pointer to the BMimeType object that shall be 195 initialized to this object's supertype. 196 \return 197 - \c B_OK: Everything went fine. 198 - \c B_BAD_VALUE: \c NULL \a superType, this object is not initialized, 199 or this object <i> is </i> a supertype. 200*/ 201status_t 202BMimeType::GetSupertype(BMimeType *superType) const 203{ 204 if (!superType) 205 return B_BAD_VALUE; 206 superType->Unset(); 207 208 status_t err = (fCStatus == B_OK ? B_OK : B_BAD_VALUE); 209 if (!err) { 210 int len = strlen(fType); 211 int i; 212 for (i = 0; i < len; i++) { 213 if (fType[i] == '/') 214 break; 215 } 216 if (i == len) 217 err = B_BAD_VALUE; // IsSupertypeOnly() == true 218 else { 219 char superMime[B_MIME_TYPE_LENGTH]; 220 strncpy(superMime, fType, i); 221 superMime[i] = 0; 222 err = superType->SetTo(superMime); 223 } 224 } 225 return err; 226} 227 228// == 229/*! \brief Returns whether this and the supplied MIME type are equal. 230 Two BMimeType objects are said to be equal, if they represent the same 231 MIME string, ignoring case, or if both are not initialized. 232 \param type The BMimeType to be compared with. 233 \return \c true, if the objects are equal, \c false otherwise. 234*/ 235bool 236BMimeType::operator==(const BMimeType &type) const 237{ 238 char lower1[B_MIME_TYPE_LENGTH]; 239 char lower2[B_MIME_TYPE_LENGTH]; 240 241 if (InitCheck() == B_OK && type.InitCheck() == B_OK) { 242 status_t err = toLower(Type(), lower1); 243 if (!err) 244 err = toLower(type.Type(), lower2); 245 if (!err) 246 err = (strcmp(lower1, lower2) == 0 ? B_OK : B_ERROR); 247 return err == B_OK; 248 } else if (InitCheck() == B_NO_INIT && type.InitCheck() == B_NO_INIT) { 249 return true; 250 } else { 251 return false; 252 } 253} 254 255// == 256/*! \brief Returns whether this and the supplied MIME type are equal. 257 A BMimeType objects equals a MIME string, if its MIME string equals the 258 latter one, ignoring case, or if it is uninitialized and the MIME string 259 is \c NULL. 260 \param type The MIME string to be compared with. 261 \return \c true, if the MIME types are equal, \c false otherwise. 262*/ 263bool 264BMimeType::operator==(const char *type) const 265{ 266 BMimeType mime; 267 if (type) 268 mime.SetTo(type); 269 return (*this) == mime; 270} 271 272// Contains 273/*! \brief Returns whether this MIME type is a supertype of or equals the 274 supplied one. 275 \param type The MIME type. 276 \return \c true, if this MIME type is a supertype of or equals the 277 supplied one, \c false otherwise. 278*/ 279bool 280BMimeType::Contains(const BMimeType *type) const 281{ 282 if (!type) 283 return false; 284 if (*this == *type) 285 return true; 286 BMimeType super; 287 if (type->GetSupertype(&super) == B_OK && *this == super) 288 return true; 289 return false; 290} 291 292// IsValid 293/*! \brief Returns whether the given string represents a valid MIME type. 294 \see SetTo() for further information. 295 \return \c true, if the given string represents a valid MIME type. 296*/ 297bool 298BMimeType::IsValid(const char *string) 299{ 300 if (!string) 301 return false; 302 303 bool foundSlash = false; 304 int len = strlen(string); 305 if (len >= B_MIME_TYPE_LENGTH || len == 0) 306 return false; 307 308 for (int i = 0; i < len; i++) { 309 char ch = string[i]; 310 if (ch == '/') { 311 if (foundSlash || i == 0 || i == len-1) 312 return false; 313 else 314 foundSlash = true; 315 } else if (!isValidMimeChar(ch)) { 316 return false; 317 } 318 } 319 return true; 320} 321 322bool isValidMimeChar(const char ch) 323{ 324 return ch > 32 // Handles white space and most CTLs 325 && ch != '/' 326 && ch != '<' 327 && ch != '>' 328 && ch != '@' 329 && ch != ',' 330 && ch != ';' 331 && ch != ':' 332 && ch != '"' 333 && ch != '(' 334 && ch != ')' 335 && ch != '[' 336 && ch != ']' 337 && ch != '?' 338 && ch != '=' 339 && ch != '\\' 340 && ch != 127; // DEL 341} 342 343// SetType 344/*! \brief Initializes this object to the supplied MIME type. 345 \deprecated This method has the same semantics as SetTo(). 346 Use SetTo() instead. 347*/ 348status_t 349BMimeType::SetType(const char *mimeType) 350{ 351 return SetTo(mimeType); 352} 353 354// GuessMimeType 355status_t 356BMimeType::GuessMimeType(const entry_ref *ref, BMimeType *type) 357{ 358 if (!ref || !type) 359 return B_BAD_VALUE; 360 361 // get BEntry 362 BEntry entry; 363 status_t error = entry.SetTo(ref); 364 if (error != B_OK) 365 return error; 366 367 // does entry exist? 368 if (!entry.Exists()) 369 return B_ENTRY_NOT_FOUND; 370 371 // check entry type 372 if (entry.IsDirectory()) 373 return type->SetType("application/x-vnd.be-directory"); 374 if (entry.IsSymLink()) 375 return type->SetType("application/x-vnd.be-symlink"); 376 if (!entry.IsFile()) 377 return B_ERROR; 378 379 // we have a file, read the first 4 bytes 380 BFile file; 381 char buffer[4]; 382 if (file.SetTo(ref, B_READ_ONLY) == B_OK 383 && file.Read(buffer, 4) == 4) { 384 return GuessMimeType(buffer, 4, type); 385 } 386 387 // we couldn't open or read the file 388 return type->SetType(B_FILE_MIME_TYPE); 389} 390 391// GuessMimeType 392status_t 393BMimeType::GuessMimeType(const void *_buffer, int32 length, BMimeType *type) 394{ 395 const uint8 *buffer = (const uint8*)_buffer; 396 if (!buffer || !type) 397 return B_BAD_VALUE; 398 399 // we only know ELF files 400 if (length >= 4 && buffer[0] == 0x7f && buffer[1] == 'E' && buffer[2] == 'L' 401 && buffer[3] == 'F') { 402 return type->SetType(B_ELF_APP_MIME_TYPE); 403 } 404 405 return type->SetType(B_FILE_MIME_TYPE); 406} 407 408// GuessMimeType 409status_t 410BMimeType::GuessMimeType(const char *filename, BMimeType *type) 411{ 412 if (!filename || !type) 413 return B_BAD_VALUE; 414 415 entry_ref ref; 416 status_t error = get_ref_for_path(filename, &ref); 417 return (error == B_OK ? GuessMimeType(&ref, type) : error); 418} 419 420void BMimeType::_ReservedMimeType1() {} 421void BMimeType::_ReservedMimeType2() {} 422void BMimeType::_ReservedMimeType3() {} 423 424// = 425/*! \brief Unimplemented assignment operator. 426*/ 427BMimeType & 428BMimeType::operator=(const BMimeType &) 429{ 430 return *this; // not implemented 431} 432 433// copy constructor 434/*! \brief Unimplemented copy constructor. 435*/ 436BMimeType::BMimeType(const BMimeType &) 437{ 438} 439 440 441// Returns a lowercase version of str in result. Result must 442// be preallocated and is assumed to be of adequate length. 443status_t 444toLower(const char *str, char *result) { 445 if (!str || !result) 446 return B_BAD_VALUE; 447 int len = strlen(str); 448 int i; 449 for (i = 0; i < len; i++) 450 result[i] = tolower(str[i]); 451 result[i] = 0; 452 return B_OK; 453} 454 455 456 457