Back to index

lightning-sunbird  0.9+nobinonly
nsMimeMapper.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 //
00039 // Mike Pinkerton
00040 // Netscape Communications
00041 //
00042 // See header file for details
00043 //
00044 
00045 #include "nsMimeMapper.h"
00046 #include "nsITransferable.h"
00047 #include "nsString.h"
00048 #include "nsReadableUtils.h"
00049 #include "nsCRT.h"
00050 
00051 #include <Drag.h>
00052 #include <Scrap.h>
00053 
00054 
00055 enum {
00056   kScrapFlavorTypeURL       = FOUR_CHAR_CODE('url '),
00057   kScrapFlavorTypeURLDesc   = FOUR_CHAR_CODE('urld')
00058 };
00059 
00060 nsMimeMapperMac::nsMimeMapperMac ( const char* inMappings )
00061   : mCounter(0)
00062 {
00063   if (inMappings && strlen(inMappings) )
00064     ParseMappings ( inMappings );
00065 }
00066 
00067 
00068 nsMimeMapperMac::~nsMimeMapperMac ( )
00069 {
00070 
00071 }   
00072 
00073 
00074 //
00075 // MapMimeTypeToMacOSType
00076 //
00077 // Given a mime type, map this into the appropriate MacOS clipboard type. For
00078 // types that we don't know about intrinsicly, use a trick to get a unique 4
00079 // character code.
00080 //
00081 // When a mapping is made, store it in the current mapping list so it can
00082 // be exported along with the data.
00083 //
00084 ResType
00085 nsMimeMapperMac::MapMimeTypeToMacOSType ( const char* aMimeStr, PRBool inAddIfNotPresent )
00086 {
00087   ResType format = 0;
00088 
00089   // first check if it is already in our list.
00090   for ( MimeMapConstIterator it = mMappings.begin(); it != mMappings.end(); ++it ) {
00091     if ( it->second.Equals(aMimeStr) ) {
00092       format = it->first;
00093       break;
00094     }
00095   }
00096 
00097   // if it's not there, do a mapping and put it there. Some things we want to map
00098   // to specific MacOS types, like 'TEXT'. Others are internal and we don't really
00099   // care about what they look like, just that they have a fairly unique flavor type.
00100   //
00101   // Don't put standard MacOS flavor mappings into the mapping list because we'll
00102   // pick them up by special casing MapMacsOSTypeToMimeType(). This means that
00103   // the low two bytes of the generated flavor can be used as an index into the list.
00104   if ( !format ) {
00105     if ( PL_strcmp(aMimeStr, kUnicodeMime) == 0 )
00106       format = kScrapFlavorTypeUnicode;
00107     else if ( PL_strcmp(aMimeStr, kTextMime) == 0 )
00108       format = kScrapFlavorTypeText;
00109     else if ( PL_strcmp(aMimeStr, kFileMime) == 0 )
00110       format = kDragFlavorTypeHFS;
00111     else if ( PL_strcmp(aMimeStr, kFilePromiseMime) == 0 )
00112       format = kDragFlavorTypePromiseHFS;
00113     else if ( PL_strcmp(aMimeStr, kNativeImageMime) == 0 )
00114       format = kScrapFlavorTypePicture;
00115     else if ( PL_strcmp(aMimeStr, kURLDataMime) == 0 )
00116       format = kScrapFlavorTypeURL;
00117     else if ( PL_strcmp(aMimeStr, kURLDescriptionMime) == 0 )
00118       format = kScrapFlavorTypeURLDesc;
00119 #if NOT_YET
00120     else if ( PL_strcmp(aMimeStr, kPNGImageMime) == 0 )
00121       format = kScrapFlavorTypePicture;
00122     else if ( PL_strcmp(aMimeStr, kJPEGImageMime) == 0 )
00123       format = kScrapFlavorTypePicture;
00124     else if ( PL_strcmp(aMimeStr, kGIFImageMime) == 0 )
00125       format = kScrapFlavorTypePicture;
00126 #endif 
00127 
00128     else if ( inAddIfNotPresent ) {
00129       // create the flavor based on the unique id in the lower two bytes and 'MZ' in the
00130       // upper two bytes.
00131       format = mCounter++;
00132       format |= ('..MZ' << 16);     
00133  
00134       // stick it in the mapping list
00135       mMappings.push_back ( MimePair(format, nsCAutoString(aMimeStr)) );
00136     }
00137   
00138   }
00139 
00140   if ( inAddIfNotPresent )
00141     NS_ASSERTION ( format, "Didn't map mimeType to a macOS type for some reason" );   
00142   return format;
00143   
00144 } // MapMimeTypeToMacOSType
00145 
00146 
00147 //
00148 // MapMacOSTypeToMimeType
00149 //
00150 // Given a MacOS flavor, map this back into the Mozilla mimetype. Uses the mappings
00151 // that have already been loaded into this class. If there aren't any, that's ok too, but
00152 // we probably won't get a match in that case.
00153 //
00154 void
00155 nsMimeMapperMac::MapMacOSTypeToMimeType ( ResType inMacType, nsCAutoString & outMimeStr )
00156 {
00157   switch ( inMacType ) {
00158   
00159     case kScrapFlavorTypeText:      outMimeStr = kTextMime;           break;
00160     case kScrapFlavorTypeUnicode:   outMimeStr = kUnicodeMime;        break;
00161     case kDragFlavorTypeHFS:        outMimeStr = kFileMime;           break;
00162     case kDragFlavorTypePromiseHFS: outMimeStr = kFilePromiseMime;    break;
00163     case kDragPromisedFlavor:       outMimeStr = kFilePromiseMime;    break;
00164     case kScrapFlavorTypeURL:       outMimeStr = kURLDataMime;        break;
00165     case kScrapFlavorTypeURLDesc:   outMimeStr = kURLDescriptionMime; break;
00166     
00167     // if someone gives us PICT (or we could have put it there), use
00168     // the native image mime type.
00169     case kScrapFlavorTypePicture: outMimeStr = kNativeImageMime; break;
00170     
00171     // This flavor is the old 4.x Composer flavor for HTML. The actual data is a binary
00172     // data structure which we do NOT want to deal with in any way shape or form. I am
00173     // only including this flavor here so we don't accidentally use it ourselves and
00174     // get very very confused. 
00175     case 'EHTM':
00176       // Fall through to the unknown case.
00177   
00178     default:
00179 
00180       outMimeStr = "unknown";
00181 
00182       // if the flavor starts with 'MZ' then it's probably one of our encoded ones. If not,
00183       // we have no idea what it is. The way this was encoded means that we can use the
00184       // lower two byts of the flavor as an index into our mapping list.
00185       if ( inMacType & ('..MZ' << 16) ) {
00186         unsigned short index = inMacType & 0x0000FFFF;    // extract the index into our internal list
00187         if ( index < mMappings.size() )
00188           outMimeStr = mMappings[index].second;
00189         else
00190           NS_WARNING("Found a flavor starting with 'MZ..' that isn't one of ours!");
00191       }
00192         
00193   } // case of which flavor
00194 
00195 } // MapMacOSTypeToMimeType
00196 
00197 
00198 //
00199 // ParseMappings
00200 //
00201 // The mappings are of the form
00202 //   1..N of (<4 char code> <space> <mime type>).
00203 //
00204 // It is perfectly acceptable for there to be no mappings (either |inMappings|
00205 // is null or an emtpy string). 
00206 //
00207 // NOTE: we make the assumption that the data is NULL terminated.
00208 //
00209 void
00210 nsMimeMapperMac::ParseMappings ( const char* inMappings )
00211 {
00212   if ( !inMappings )
00213     return;
00214 
00215   const char* currPosition = inMappings;
00216   while ( *currPosition ) {
00217     char mimeType[100];
00218     ResType flavor = nsnull;
00219 
00220     sscanf ( currPosition, "%ld %s ", &flavor, mimeType );
00221     mMappings.push_back( MimePair(flavor, nsCAutoString(mimeType)) );
00222 
00223     currPosition += 10 + 2 + strlen(mimeType);  // see ExportMapping() for explanation of this calculation
00224     
00225     ++mCounter;
00226   } // while we're not at the end yet
00227   
00228 } // ParseMappings
00229 
00230 
00231 //
00232 // ExportMapping
00233 //
00234 // The mappings are of the form
00235 //   <# of pairs> 1..N of (<4 char code> <space> <mime type> <space>)
00236 //
00237 // Caller is responsible for disposing of the memory allocated here. |outLength| counts
00238 // the null at the end of the string.
00239 //
00240 char*
00241 nsMimeMapperMac::ExportMapping ( short * outLength ) const
00242 {
00243   NS_WARN_IF_FALSE ( outLength, "No out param provided" );
00244   if ( outLength )
00245     *outLength = 0;
00246 
00247 #if 0
00248 // I'm leaving this code in here just to prove a point. If we were allowed to
00249 // use string stream's (we're not, because of bloat), this is all the code I'd have
00250 // to write to do all the crap down below.
00251   ostringstream ostr;
00252 
00253   // for each pair, write out flavor and mime types
00254   for ( MimeMapConstIterator it = mMappings.begin(); it != mMappings.end(); ++it ) {
00255     const char* mimeType = ToNewCString(it->second);
00256        ostr << it->first << ' ' << mimeType << ' ';
00257        delete [] mimeType;
00258   }
00259   
00260   return ostr.str().c_str();
00261 #endif
00262 
00263   char* exportBuffer = nsnull;
00264   
00265   // figure out about how long the composed string will be
00266   short len = 0;
00267   for ( MimeMapConstIterator it = mMappings.begin(); it != mMappings.end(); ++it ) {
00268     len += 10;  // <4 char code> (any decimal representation of 'MZXX' will be 10 digits)
00269     len += 2;   // for the two spaces
00270     len += it->second.Length();  // <mime type>
00271   }  
00272 
00273   // create a string of that length and fill it in with each mapping. We have to
00274   // consider the possibility that there aren't any generic (internal mozilla) flavors
00275   // so the map could be empty.
00276   exportBuffer = NS_STATIC_CAST(char*, nsMemory::Alloc(len + 1));      // don't forget the NULL
00277   if ( !exportBuffer )
00278     return nsnull;
00279   *exportBuffer = '\0';                          // null terminate at the start for strcat()
00280   if ( len ) {
00281     char* posInString = exportBuffer;
00282     for ( MimeMapConstIterator it = mMappings.begin(); it != mMappings.end(); ++it ) {
00283       // create a buffer for this mapping, fill it in, and append it to our
00284       // ongoing result buffer, |exportBuffer|. 
00285       char* currMapping = new char[10 + 2 + it->second.Length() + 1];  // same computation as above, plus NULL
00286       char* mimeType = ToNewCString(it->second);
00287       if ( currMapping && mimeType ) {
00288         sprintf(currMapping, "%ld %s ", it->first, mimeType);
00289         strcat(posInString, currMapping);
00290         posInString += strlen(currMapping);     // advance marker to get ready for next mapping
00291       }
00292       nsMemory::Free ( mimeType );
00293       nsCRT::free ( currMapping );
00294     }
00295       
00296     *posInString = '\0';                        // null terminate our resulting string
00297   } // if there is anything in our list
00298   
00299   if ( outLength )
00300     *outLength = len + 1;  // don't forget the NULL
00301   return exportBuffer;
00302   
00303 } // ExportMapping