]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/mimetype.cpp
wxMkdir() has 2nd param under Unix
[wxWidgets.git] / src / common / mimetype.cpp
index b94fe97f1b623f010feac50e245d749a95753b8c..4cc2d843db7b878fa7f9cc14fedb2287a64acd3f 100644 (file)
@@ -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
@@ -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; }
 
@@ -492,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
 // ============================================================================
@@ -510,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) == '%' &&
@@ -525,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;
@@ -536,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() ) {
@@ -557,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;
     }
@@ -666,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;
@@ -696,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) ) {
@@ -877,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, '=');
@@ -944,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++ )
                     ;
             }
@@ -952,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++;
@@ -962,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" ) {
@@ -987,8 +1023,13 @@ 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;
             }
         }
@@ -1018,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++ ) {
@@ -1230,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;
                 }
             }
@@ -1260,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