X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3c67202dee33f95fa48b176dec8994340c70eaa2..dd3646fd302ad7ee05b5848ecd5dc03444048ca7:/src/common/mimetype.cpp diff --git a/src/common/mimetype.cpp b/src/common/mimetype.cpp index 1e268d586d..4cc2d843db 100644 --- a/src/common/mimetype.cpp +++ b/src/common/mimetype.cpp @@ -124,8 +124,10 @@ public: wxFileType *GetFileTypeFromMimeType(const wxString& mimeType); // this are NOPs under Windows - void ReadMailcap(const wxString& filename) { } - void ReadMimeTypes(const wxString& filename) { } + bool ReadMailcap(const wxString& filename, bool fallback = TRUE) + { return TRUE; } + bool ReadMimeTypes(const wxString& filename) + { return TRUE; } }; #else // Unix @@ -170,7 +172,7 @@ public: // * compose and composetyped fields are used to determine the program to be // called to create a new message pert in the specified format (unused). // -// Parameter/filename xpansion: +// Parameter/filename xpansion: // * %s is replaced with the (full) file name // * %t is replaced with MIME type/subtype of the entry // * for multipart type only %n is replaced with the nnumber of parts and %F is @@ -189,7 +191,7 @@ public: // comments. Each record has one of two following forms: // a) for "brief" format: // -// b) for "expanded" format: +// b) for "expanded" format: // type= \ desc="" \ exts="ext" // // We try to autodetect the format of mime.types: if a non-comment line starts @@ -220,9 +222,27 @@ public: // operations // prepend this element to the list void Prepend(MailCapEntry *next) { m_next = next; } - // append to the list + // insert into the list at given position + void Insert(MailCapEntry *next, size_t pos) + { + // FIXME slooow... + MailCapEntry *cur; + size_t n = 0; + for ( cur = next; cur != NULL; cur = cur->m_next, n++ ) { + if ( n == pos ) + break; + } + + wxASSERT_MSG( n == pos, "invalid position in MailCapEntry::Insert" ); + + m_next = cur->m_next; + cur->m_next = this; + } + // append this element to the list void Append(MailCapEntry *next) { + wxCHECK_RET( next != NULL, "Append()ing to what?" ); + // FIXME slooow... MailCapEntry *cur; for ( cur = next; cur->m_next != NULL; cur = cur->m_next ) @@ -230,9 +250,7 @@ public: cur->m_next = this; - // we initialize it in the ctor and there is no reason to both Prepend() - // and Append() one and the same entry - wxASSERT( m_next == NULL ); + wxASSERT_MSG( !m_next, "Append()ing element already in the list?" ); } private: @@ -252,15 +270,15 @@ friend class wxFileTypeImpl; // give it access to m_aXXX variables public: // ctor loads all info into memory for quicker access later on - // @@ it would be nice to load them all, but parse on demand only... + // TODO it would be nice to load them all, but parse on demand only... wxMimeTypesManagerImpl(); // implement containing class functions wxFileType *GetFileTypeFromExtension(const wxString& ext); wxFileType *GetFileTypeFromMimeType(const wxString& mimeType); - void ReadMailcap(const wxString& filename); - void ReadMimeTypes(const wxString& filename); + bool ReadMailcap(const wxString& filename, bool fallback = FALSE); + bool ReadMimeTypes(const wxString& filename); // accessors // get the string containing space separated extensions for the given @@ -285,8 +303,8 @@ public: bool GetExtensions(wxArrayString& extensions); bool GetMimeType(wxString *mimeType) const { *mimeType = m_manager->m_aTypes[m_index]; return TRUE; } - bool GetIcon(wxIcon *icon) const - { return FALSE; } // @@ maybe with Gnome/KDE integration... + bool GetIcon(wxIcon * WXUNUSED(icon)) const + { return FALSE; } // TODO maybe with Gnome/KDE integration... bool GetDescription(wxString *desc) const { *desc = m_manager->m_aDescriptions[m_index]; return TRUE; } @@ -337,8 +355,8 @@ wxString wxFileType::ExpandCommand(const wxString& command, case 's': // '%s' expands into file name (quoted because it might // contain spaces) - except if there are already quotes - // there because otherwise some programs may get confused by - // double double quotes + // there because otherwise some programs may get confused + // by double double quotes #if 0 if ( *(pc - 2) == '"' ) str << params.GetFileName(); @@ -448,6 +466,28 @@ wxFileType::GetPrintCommand(wxString *printCmd, // wxMimeTypesManager // ---------------------------------------------------------------------------- +bool wxMimeTypesManager::IsOfType(const wxString& mimeType, + const wxString& wildcard) +{ + wxASSERT_MSG( mimeType.Find('*') == wxNOT_FOUND, + "first MIME type can't contain wildcards" ); + + // all comparaisons are case insensitive (2nd arg of IsSameAs() is FALSE) + if ( wildcard.BeforeFirst('/').IsSameAs(mimeType.BeforeFirst('/'), FALSE) ) + { + wxString strSubtype = wildcard.AfterFirst('/'); + + if ( strSubtype == '*' || + strSubtype.IsSameAs(mimeType.AfterFirst('/'), FALSE) ) + { + // matches (either exactly or it's a wildcard) + return TRUE; + } + } + + return FALSE; +} + wxMimeTypesManager::wxMimeTypesManager() { m_impl = new wxMimeTypesManagerImpl; @@ -470,6 +510,16 @@ wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType) return m_impl->GetFileTypeFromMimeType(mimeType); } +bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback) +{ + return m_impl->ReadMailcap(filename, fallback); +} + +bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename) +{ + return m_impl->ReadMimeTypes(filename); +} + // ============================================================================ // real (OS specific) implementation // ============================================================================ @@ -488,9 +538,9 @@ bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const // it's the default value of the key if ( key.QueryValue("", *command) ) { // transform it from '%1' to '%s' style format string - // @@ we don't make any attempt to verify that the string is valid, - // i.e. doesn't contain %2, or second %1 or .... But we do make - // sure that we return a string with _exactly_ one '%s'! + // NB: we don't make any attempt to verify that the string is valid, + // i.e. doesn't contain %2, or second %1 or .... But we do make + // sure that we return a string with _exactly_ one '%s'! size_t len = command->Len(); for ( size_t n = 0; n < len; n++ ) { if ( command->GetChar(n) == '%' && @@ -503,7 +553,7 @@ bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const } // we didn't find any '%1'! - // @@@ hack: append the filename at the end, hope that it will do + // HACK: append the filename at the end, hope that it will do *command << " %s"; return TRUE; @@ -514,7 +564,7 @@ bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const return FALSE; } -// @@ this function is half implemented +// TODO this function is half implemented bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) { if ( m_ext.IsEmpty() ) { @@ -535,7 +585,7 @@ bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const { // suppress possible error messages wxLogNull nolog; - wxRegKey key(wxRegKey::HKCR, m_strFileType); + wxRegKey key(wxRegKey::HKCR, /*m_strFileType*/ "." + m_ext); if ( key.Open() && key.QueryValue("Content Type", *mimeType) ) { return TRUE; } @@ -644,8 +694,8 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) wxFileType * wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) { - // @@@ I don't know of any official documentation which mentions this - // location, but as a matter of fact IE uses it, so why not we? + // HACK I don't know of any official documentation which mentions this + // location, but as a matter of fact IE uses it, so why not we? static const char *szMimeDbase = "MIME\\Database\\Content Type\\"; wxString strKey = szMimeDbase; @@ -674,7 +724,7 @@ wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const wxString command; MailCapEntry *entry = m_manager->m_aEntries[m_index]; while ( entry != NULL ) { - // notice that an empty command would always succeed (@@ is it ok?) + // notice that an empty command would always succeed (it's ok) command = wxFileType::ExpandCommand(entry->GetTestCmd(), params); if ( command.IsEmpty() || (system(command) == 0) ) { @@ -796,8 +846,25 @@ wxMimeTypesManagerImpl::wxMimeTypesManagerImpl() wxFileType * wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) { - wxFAIL_MSG("not implemented (must parse mime.types)"); + size_t count = m_aExtensions.GetCount(); + for ( size_t n = 0; n < count; n++ ) { + wxString extensions = m_aExtensions[n]; + while ( !extensions.IsEmpty() ) { + wxString field = extensions.BeforeFirst(' '); + extensions = extensions.AfterFirst(' '); + + // consider extensions as not being case-sensitive + if ( field.IsSameAs(ext, FALSE /* no case */) ) { + // found + wxFileType *fileType = new wxFileType; + fileType->m_impl->Init(this, n); + + return fileType; + } + } + } + // not found return NULL; } @@ -838,29 +905,39 @@ wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) } } -void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) +bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) { wxLogTrace("--- Parsing mime.types file '%s' ---", strFileName.c_str()); wxTextFile file(strFileName); if ( !file.Open() ) - return; + return FALSE; // the information we extract wxString strMimeType, strDesc, strExtensions; size_t nLineCount = file.GetLineCount(); + const char *pc = NULL; for ( size_t nLine = 0; nLine < nLineCount; nLine++ ) { - // now we're at the start of the line - const char *pc = file[nLine].c_str(); + if ( pc == NULL ) { + // now we're at the start of the line + pc = file[nLine].c_str(); + } + else { + // we didn't finish with the previous line yet + nLine--; + } // skip whitespace while ( isspace(*pc) ) pc++; // comment? - if ( *pc == '#' ) + if ( *pc == '#' ) { + // skip the whole line + pc = NULL; continue; + } // detect file format const char *pEqualSign = strchr(pc, '='); @@ -905,7 +982,7 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) } } else { - // unquoted stringends at the first space + // unquoted string ends at the first space for ( pEnd = pc; !isspace(*pEnd); pEnd++ ) ; } @@ -913,8 +990,7 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) // now we have the RHS (field value) wxString strRHS(pc, pEnd - pc); - // check that it's more or less what we're waiting for, i.e. that - // only '\' is left on the line + // check what follows this entry if ( *pEnd == '"' ) { // skip this quote pEnd++; @@ -923,14 +999,13 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) for ( pc = pEnd; isspace(*pc); pc++ ) ; - // only '\\' may be left on the line normally - bool entryEnded = *pc == '\0'; - if ( !entryEnded && ((*pc != '\\') || (*++pc != '\0')) ) { - wxLogWarning(_("Mime.types file %s, line %d: extra characters " - "after the field value ignored."), - strFileName.c_str(), nLine + 1); + // if there is something left, it may be either a '\\' to continue + // the line or the next field of the same entry + bool entryEnded = *pc == '\0', + nextFieldOnSameLine = FALSE; + if ( !entryEnded ) { + nextFieldOnSameLine = ((*pc != '\\') || (pc[1] != '\0')); } - // if there is a trailing backslash entryEnded = FALSE // now see what we got if ( strLHS == "type" ) { @@ -948,12 +1023,27 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) } if ( !entryEnded ) { - // as we don't reset strMimeType, the next line in this entry + if ( !nextFieldOnSameLine ) + pc = NULL; + //else: don't reset it + + // as we don't reset strMimeType, the next field in this entry // will be interpreted correctly. + continue; } } + // although it doesn't seem to be covered by RFCs, some programs + // (notably Netscape) create their entries with several comma + // separated extensions (RFC mention the spaces only) + strExtensions.Replace(",", " "); + + // also deal with the leading dot + if ( !strExtensions.IsEmpty() && strExtensions[0] == '.' ) { + strExtensions.erase(0, 1); + } + int index = m_aTypes.Index(strMimeType); if ( index == wxNOT_FOUND ) { // add a new entry @@ -969,24 +1059,35 @@ void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) } m_aExtensions[index] += strExtensions; } + + // finished with this line + pc = NULL; } // check our data integriry wxASSERT( m_aTypes.Count() == m_aEntries.Count() && m_aTypes.Count() == m_aExtensions.Count() && m_aTypes.Count() == m_aDescriptions.Count() ); + + return TRUE; } -void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) +bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName, + bool fallback) { wxLogTrace("--- Parsing mailcap file '%s' ---", strFileName.c_str()); wxTextFile file(strFileName); if ( !file.Open() ) - return; + return FALSE; - // see the comments near the end of function for the reason we need this + // see the comments near the end of function for the reason we need these + // variables (search for the next occurence of them) + // indices of MIME types (in m_aTypes) we already found in this file wxArrayInt aEntryIndices; + // aLastIndices[n] is the index of last element in + // m_aEntries[aEntryIndices[n]] from this file + wxArrayInt aLastIndices; size_t nLineCount = file.GetLineCount(); for ( size_t nLine = 0; nLine < nLineCount; nLine++ ) { @@ -1014,8 +1115,8 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) } currentToken = Field_Type; // the flags and field values on the current line - bool needsterminal = false, - copiousoutput = false; + bool needsterminal = FALSE, + copiousoutput = FALSE; wxString strType, strOpenCmd, strPrintCmd, @@ -1077,8 +1178,8 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) // is this something of the form foo=bar? const char *pEq = strchr(curField, '='); if ( pEq != NULL ) { - wxString lhs = curField.Before('='), - rhs = curField.After('='); + wxString lhs = curField.BeforeFirst('='), + rhs = curField.AfterFirst('='); lhs.Trim(TRUE); // from right rhs.Trim(FALSE); // from left @@ -1126,12 +1227,14 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) { // don't flood the user with error messages // if we don't understand something in his - // mailcap + // mailcap, but give them in debug mode + // because this might be useful for the + // programmer wxLogDebug ( - _("Mailcap file %s, line %d: unknown " - "field '%s' for the MIME type " - "'%s' ignored."), + "Mailcap file %s, line %d: unknown " + "field '%s' for the MIME type " + "'%s' ignored.", strFileName.c_str(), nLine + 1, curField.c_str(), @@ -1179,26 +1282,51 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) m_aDescriptions.Add(strDesc); } else { - // modify the existing entry: the entry in one and the same file - // are read in top-to-bottom order, i.e. the entries read first - // should be tried before the entries below. However, the files - // read later should override the settings in the files read - // before, thus we Append() the new entry to the list if it has - // already occured in _this_ file, but Prepend() it if it - // occured in some of the previous ones. - if ( aEntryIndices.Index(nIndex) == wxNOT_FOUND ) { - // first time in this file - aEntryIndices.Add(nIndex); - entry->Prepend(m_aEntries[nIndex]); - m_aEntries[nIndex] = entry; + // modify the existing entry: the entries in one and the same + // file are read in top-to-bottom order, i.e. the entries read + // first should be tried before the entries below. However, + // the files read later should override the settings in the + // files read before (except if fallback is TRUE), thus we + // Insert() the new entry to the list if it has already + // occured in _this_ file, but Prepend() it if it occured in + // some of the previous ones and Append() to it in the + // fallback case + + if ( fallback ) { + // 'fallback' parameter prevents the entries from this + // file from overriding the other ones - always append + MailCapEntry *entryOld = m_aEntries[nIndex]; + if ( entryOld ) + entry->Append(entryOld); + else + m_aEntries[nIndex] = entry; } else { - // not the first time in _this_ file - entry->Append(m_aEntries[nIndex]); + int entryIndex = aEntryIndices.Index(nIndex); + if ( entryIndex == wxNOT_FOUND ) { + // first time in this file + aEntryIndices.Add(nIndex); + aLastIndices.Add(0); + + entry->Prepend(m_aEntries[nIndex]); + m_aEntries[nIndex] = entry; + } + else { + // not the first time in _this_ file + size_t nEntryIndex = (size_t)entryIndex; + MailCapEntry *entryOld = m_aEntries[nIndex]; + if ( entryOld ) + entry->Insert(entryOld, aLastIndices[nEntryIndex]); + else + m_aEntries[nIndex] = entry; + + // the indices were shifted by 1 + aLastIndices[nEntryIndex]++; + } } if ( !strDesc.IsEmpty() ) { - // @@ replace the old one - what else can we do?? + // replace the old one - what else can we do?? m_aDescriptions[nIndex] = strDesc; } } @@ -1209,6 +1337,8 @@ void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) m_aTypes.Count() == m_aExtensions.Count() && m_aTypes.Count() == m_aDescriptions.Count() ); } + + return TRUE; } #endif // OS type