Back to index

lightning-sunbird  0.9+nobinonly
xptiManifest.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mike McCabe <mccabe@netscape.com>
00024  *   John Bandhauer <jband@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 /* Implementation of xptiManifest. */
00041 
00042 #include "xptiprivate.h"
00043 #include "nsManifestLineReader.h"
00044 #include "nsString.h"
00045 
00046 static const char g_Disclaimer[] = "# Generated file. ** DO NOT EDIT! **";
00047 
00048 static const char g_TOKEN_Files[]          = "Files";
00049 static const char g_TOKEN_ArchiveItems[]   = "ArchiveItems";
00050 static const char g_TOKEN_Interfaces[]     = "Interfaces";
00051 static const char g_TOKEN_Header[]         = "Header";
00052 static const char g_TOKEN_Version[]        = "Version";
00053 static const char g_TOKEN_AppDir[]         = "AppDir";
00054 static const char g_TOKEN_Directories[]    = "Directories";
00055 
00056 static const int  g_VERSION_MAJOR          = 2;
00057 static const int  g_VERSION_MINOR          = 0;
00058 
00059 /***************************************************************************/
00060 
00061 static PRBool 
00062 GetCurrentAppDirString(xptiInterfaceInfoManager* aMgr, nsACString &aStr)
00063 {
00064     nsCOMPtr<nsILocalFile> appDir;
00065     aMgr->GetApplicationDir(getter_AddRefs(appDir));
00066     if(appDir)
00067         return NS_SUCCEEDED(appDir->GetPersistentDescriptor(aStr));
00068     return PR_FALSE;
00069 }
00070 
00071 static PRBool 
00072 CurrentAppDirMatchesPersistentDescriptor(xptiInterfaceInfoManager* aMgr, 
00073                                          const char *inStr)
00074 {
00075     nsCOMPtr<nsILocalFile> appDir;
00076     aMgr->GetApplicationDir(getter_AddRefs(appDir));
00077 
00078     nsCOMPtr<nsILocalFile> descDir;
00079     nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, getter_AddRefs(descDir));
00080     if(NS_FAILED(rv))
00081         return PR_FALSE;
00082 
00083     rv = descDir->SetPersistentDescriptor(nsDependentCString(inStr));
00084     if(NS_FAILED(rv))
00085         return PR_FALSE;
00086     
00087     PRBool matches;
00088     rv = appDir->Equals(descDir, &matches);
00089     return NS_SUCCEEDED(rv) && matches;
00090 }
00091 
00092 PR_STATIC_CALLBACK(PLDHashOperator)
00093 xpti_InterfaceWriter(PLDHashTable *table, PLDHashEntryHdr *hdr,
00094                      PRUint32 number, void *arg)
00095 {
00096     xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value;
00097     PRFileDesc* fd = (PRFileDesc*)  arg;
00098 
00099     char* iidStr = entry->GetTheIID()->ToString();
00100     if(!iidStr)
00101         return PL_DHASH_STOP;
00102 
00103     const xptiTypelib& typelib = entry->GetTypelibRecord();
00104 
00105     PRBool success =  PR_fprintf(fd, "%d,%s,%s,%d,%d,%d\n",
00106                                  (int) number,
00107                                  entry->GetTheName(),
00108                                  iidStr,
00109                                  (int) typelib.GetFileIndex(),
00110                                  (int) (typelib.IsZip() ? 
00111                                  typelib.GetZipItemIndex() : -1),
00112                                  (int) entry->GetScriptableFlag());
00113 
00114     nsCRT::free(iidStr);
00115 
00116     return success ? PL_DHASH_NEXT : PL_DHASH_STOP;
00117 }
00118 
00119 
00120 // static
00121 PRBool xptiManifest::Write(xptiInterfaceInfoManager* aMgr,
00122                            xptiWorkingSet*           aWorkingSet)
00123 {
00124 
00125     PRBool succeeded = PR_FALSE;
00126     PRFileDesc* fd = nsnull;
00127     PRUint32 i;
00128     PRUint32 size32;
00129     PRIntn interfaceCount = 0;
00130     nsCAutoString appDirString;
00131     
00132     nsCOMPtr<nsILocalFile> tempFile;
00133     if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(tempFile)) || !tempFile)
00134         return PR_FALSE;
00135 
00136     nsCAutoString originalLeafName;
00137     tempFile->GetNativeLeafName(originalLeafName);
00138 
00139     nsCAutoString leafName;
00140     leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp"));
00141 
00142     tempFile->SetNativeLeafName(leafName);
00143 
00144     // All exits via "goto out;" from here on...
00145     if(NS_FAILED(tempFile->
00146                  OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
00147                                   0666, &fd)) || !fd)
00148     {
00149         goto out;
00150     }
00151 
00152     // write file header comments
00153 
00154     if(!PR_fprintf(fd, "%s\n", g_Disclaimer))
00155         goto out;
00156 
00157     // write the [Header] block, version number, and appdir.
00158 
00159     if(!PR_fprintf(fd, "\n[%s,%d]\n", g_TOKEN_Header, 2))
00160         goto out;
00161 
00162     if(!PR_fprintf(fd, "%d,%s,%d,%d\n", 
00163                        0, g_TOKEN_Version, g_VERSION_MAJOR, g_VERSION_MINOR))
00164         goto out;
00165 
00166     GetCurrentAppDirString(aMgr, appDirString);
00167     if(appDirString.IsEmpty())
00168         goto out;
00169 
00170     if(!PR_fprintf(fd, "%d,%s,%s\n", 
00171                        1, g_TOKEN_AppDir, appDirString.get()))
00172         goto out;
00173 
00174     // write Directories list
00175 
00176     if(!PR_fprintf(fd, "\n[%s,%d]\n", 
00177                        g_TOKEN_Directories, 
00178                        (int) aWorkingSet->GetDirectoryCount()))
00179         goto out;
00180 
00181     for(i = 0; i < aWorkingSet->GetDirectoryCount(); i++)
00182     {
00183         nsCOMPtr<nsILocalFile> dir;        
00184         nsCAutoString str;
00185 
00186         aWorkingSet->GetDirectoryAt(i, getter_AddRefs(dir));
00187         if(!dir)
00188             goto out;
00189 
00190         dir->GetPersistentDescriptor(str);
00191         if(str.IsEmpty())
00192             goto out;
00193         
00194         if(!PR_fprintf(fd, "%d,%s\n", (int) i, str.get()))
00195             goto out;
00196     }
00197 
00198     // write Files list
00199 
00200     if(!PR_fprintf(fd, "\n[%s,%d]\n", 
00201                        g_TOKEN_Files, 
00202                        (int) aWorkingSet->GetFileCount()))
00203         goto out;
00204 
00205     for(i = 0; i < aWorkingSet->GetFileCount(); i++)
00206     {
00207         const xptiFile& file = aWorkingSet->GetFileAt(i);
00208 
00209         LL_L2UI(size32, file.GetSize());
00210     
00211         if(!PR_fprintf(fd, "%d,%s,%d,%u,%lld\n",
00212                            (int) i,
00213                            file.GetName(),
00214                            (int) file.GetDirectory(),
00215                            size32, PRInt64(file.GetDate())))
00216         goto out;
00217     }
00218 
00219     // write ArchiveItems list
00220 
00221     if(!PR_fprintf(fd, "\n[%s,%d]\n", 
00222                        g_TOKEN_ArchiveItems, 
00223                        (int) aWorkingSet->GetZipItemCount()))
00224         goto out;
00225 
00226     for(i = 0; i < aWorkingSet->GetZipItemCount(); i++)
00227     {
00228         if(!PR_fprintf(fd, "%d,%s\n",
00229                            (int) i,
00230                            aWorkingSet->GetZipItemAt(i).GetName()))
00231         goto out;
00232     }
00233 
00234     // write the Interfaces list
00235 
00236     interfaceCount = aWorkingSet->mNameTable->entryCount;
00237 
00238     if(!PR_fprintf(fd, "\n[%s,%d]\n", 
00239                        g_TOKEN_Interfaces, 
00240                        (int) interfaceCount))
00241         goto out;
00242 
00243     if(interfaceCount != (PRIntn)
00244         PL_DHashTableEnumerate(aWorkingSet->mNameTable, 
00245                                xpti_InterfaceWriter, fd))
00246         goto out;
00247 
00248 
00249     if(PR_SUCCESS == PR_Close(fd))
00250     {
00251         succeeded = PR_TRUE;
00252     }
00253     fd = nsnull;
00254 
00255 out:
00256     if(fd)
00257         PR_Close(fd);
00258     
00259     if(succeeded)
00260     {
00261         // delete the old file and rename this
00262         nsCOMPtr<nsILocalFile> mainFile;
00263         if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(mainFile)) || !mainFile)
00264             return PR_FALSE;
00265     
00266         PRBool exists;
00267         if(NS_FAILED(mainFile->Exists(&exists)))
00268             return PR_FALSE;
00269 
00270         if(exists && NS_FAILED(mainFile->Remove(PR_FALSE)))
00271             return PR_FALSE;
00272     
00273         nsCOMPtr<nsIFile> parent;
00274         mainFile->GetParent(getter_AddRefs(parent));
00275             
00276         // MoveTo means rename.
00277         if(NS_FAILED(tempFile->MoveToNative(parent, originalLeafName)))
00278             return PR_FALSE;
00279     }
00280 
00281     return succeeded;
00282 }        
00283 
00284 /***************************************************************************/
00285 /***************************************************************************/
00286 
00287 static char* 
00288 ReadManifestIntoMemory(xptiInterfaceInfoManager* aMgr,
00289                        PRUint32* pLength)
00290 {
00291     PRFileDesc* fd = nsnull;
00292     PRInt32 flen;
00293     PRInt64 fileSize;
00294     char* whole = nsnull;
00295     PRBool success = PR_FALSE;
00296 
00297     nsCOMPtr<nsILocalFile> aFile;
00298     if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(aFile)) || !aFile)
00299         return nsnull;
00300 
00301 #ifdef DEBUG
00302     {
00303         static PRBool shown = PR_FALSE;
00304         
00305         nsCAutoString path;
00306         if(!shown && NS_SUCCEEDED(aFile->GetNativePath(path)) && !path.IsEmpty())
00307         {
00308             printf("Type Manifest File: %s\n", path.get());
00309             shown = PR_TRUE;        
00310         } 
00311     }            
00312 #endif
00313 
00314     if(NS_FAILED(aFile->GetFileSize(&fileSize)) || !(flen = nsInt64(fileSize)))
00315         return nsnull;
00316 
00317     whole = new char[flen];
00318     if (!whole)
00319         return nsnull;
00320 
00321     // All exits from on here should be via 'goto out' 
00322 
00323     if(NS_FAILED(aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd)) || !fd)
00324         goto out;
00325 
00326     if(flen > PR_Read(fd, whole, flen))
00327         goto out;
00328 
00329     success = PR_TRUE;
00330 
00331  out:
00332     if(fd)
00333         PR_Close(fd);
00334 
00335     if(!success)     
00336     {
00337         delete [] whole;
00338         return nsnull;
00339     }
00340 
00341     *pLength = flen;
00342     return whole;    
00343 }
00344 
00345 static
00346 PRBool ReadSectionHeader(nsManifestLineReader& reader, 
00347                          const char *token, int minCount, int* count)
00348 {
00349     while(1)
00350     {
00351         if(!reader.NextLine())
00352             break;
00353         if(*reader.LinePtr() == '[')
00354         {
00355             char* p = reader.LinePtr() + (reader.LineLength() - 1);
00356             if(*p != ']')
00357                 break;
00358             *p = 0;
00359 
00360             char* values[2];
00361             int lengths[2];
00362             if(2 != reader.ParseLine(values, lengths, 2))
00363                 break;
00364 
00365             // ignore the leading '['
00366             if(0 != PL_strcmp(values[0]+1, token))
00367                 break;
00368 
00369             if((*count = atoi(values[1])) < minCount)
00370                 break;
00371             
00372             return PR_TRUE;
00373         }
00374     }
00375     return PR_FALSE;
00376 }
00377 
00378 
00379 // static
00380 PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr,
00381                           xptiWorkingSet*           aWorkingSet)
00382 {
00383     int i;
00384     char* whole = nsnull;
00385     PRBool succeeded = PR_FALSE;
00386     PRUint32 flen;
00387     nsManifestLineReader reader;
00388     xptiHashEntry* hashEntry;
00389     int headerCount = 0;
00390     int dirCount = 0;
00391     int fileCount = 0;
00392     int zipItemCount = -1;
00393     int interfaceCount = 0;
00394     int dir;
00395     int flags;
00396     char* values[6];    // 6 is currently the max items we need to parse
00397     int lengths[6];
00398     PRUint32 size32;
00399     PRInt64 size;
00400     PRInt64 date;
00401 
00402     whole = ReadManifestIntoMemory(aMgr, &flen);
00403     if(!whole)
00404         return PR_FALSE;
00405 
00406     reader.Init(whole, flen);
00407 
00408     // All exits from here on should be via 'goto out' 
00409     
00410     // Look for "Header" section
00411 
00412     // This version accepts only version 1,0. We also freak if the header
00413     // has more than one entry. The rationale is that we want to force an
00414     // autoreg if the xpti.dat file was written by *any* other version of
00415     // the software. Future versions may wish to support updating older
00416     // manifests in some interesting way.
00417 
00418     if(!ReadSectionHeader(reader, g_TOKEN_Header, 2, &headerCount))
00419         goto out;
00420 
00421     if(headerCount != 2)
00422         goto out;
00423 
00424     // Verify the version number
00425 
00426     if(!reader.NextLine())
00427         goto out;
00428 
00429     // index,VersionLiteral,major,minor
00430     if(4 != reader.ParseLine(values, lengths, 4))
00431         goto out;
00432 
00433     // index
00434     if(0 != atoi(values[0]))
00435         goto out;
00436 
00437     // VersionLiteral
00438     if(0 != PL_strcmp(values[1], g_TOKEN_Version))
00439         goto out;
00440 
00441     // major
00442     if(g_VERSION_MAJOR != atoi(values[2]))
00443         goto out;
00444 
00445     // minor
00446     if(g_VERSION_MINOR != atoi(values[3]))
00447         goto out;
00448 
00449     // Verify the application directory
00450 
00451     if(!reader.NextLine())
00452         goto out;
00453 
00454     // index,AppDirLiteral,directoryname
00455     if(3 != reader.ParseLine(values, lengths, 3))
00456         goto out;
00457 
00458     // index
00459     if(1 != atoi(values[0]))
00460         goto out;
00461 
00462     // AppDirLiteral
00463     if(0 != PL_strcmp(values[1], g_TOKEN_AppDir))
00464         goto out;
00465 
00466     if(!CurrentAppDirMatchesPersistentDescriptor(aMgr, values[2]))
00467         goto out;
00468 
00469     // Look for "Directories" section
00470 
00471     if(!ReadSectionHeader(reader, g_TOKEN_Directories, 1, &dirCount))
00472         goto out;
00473     else
00474     {
00475         // To validate that the directory list matches the current search path
00476         // we first confirm that the list lengths match.
00477 
00478         nsCOMPtr<nsISupportsArray> searchPath;
00479         aMgr->GetSearchPath(getter_AddRefs(searchPath));
00480 
00481         PRUint32 searchPathCount;
00482         searchPath->Count(&searchPathCount);
00483         
00484         if(dirCount != (int) searchPathCount)
00485             goto out;
00486     }
00487 
00488     // Read the directory records
00489 
00490     for(i = 0; i < dirCount; ++i)
00491     {
00492         if(!reader.NextLine())
00493             goto out;
00494        
00495         // index,directoryname
00496         if(2 != reader.ParseLine(values, lengths, 2))
00497             goto out;
00498 
00499         // index
00500         if(i != atoi(values[0]))
00501             goto out;
00502 
00503         // directoryname
00504         if(!aWorkingSet->DirectoryAtMatchesPersistentDescriptor(i, values[1]))
00505             goto out;    
00506     }
00507 
00508     // Look for "Files" section
00509 
00510     if(!ReadSectionHeader(reader, g_TOKEN_Files, 1, &fileCount))
00511         goto out;
00512 
00513 
00514     // Alloc room in the WorkingSet for the filearray.
00515 
00516     if(!aWorkingSet->NewFileArray(fileCount))   
00517         goto out;    
00518 
00519     // Read the file records
00520 
00521     for(i = 0; i < fileCount; ++i)
00522     {
00523         if(!reader.NextLine())
00524             goto out;
00525 
00526         // index,filename,dirIndex,dilesSize,filesDate
00527         if(5 != reader.ParseLine(values, lengths, 5))
00528             goto out;
00529 
00530         // index
00531         if(i != atoi(values[0]))
00532             goto out;
00533 
00534         // filename
00535         if(!*values[1])
00536             goto out;
00537 
00538         // dirIndex
00539         dir = atoi(values[2]);
00540         if(dir < 0 || dir > dirCount)
00541             goto out;
00542 
00543         // fileSize
00544         size32 = atoi(values[3]);
00545         if(size32 <= 0)
00546             goto out;
00547         LL_UI2L(size, size32);
00548 
00549         // fileDate
00550         date = nsCRT::atoll(values[4]);
00551         if(LL_IS_ZERO(date))
00552             goto out;
00553         
00554         // Append a new file record to the array.
00555 
00556         aWorkingSet->AppendFile(
00557             xptiFile(nsInt64(size), nsInt64(date), dir, values[1], aWorkingSet));
00558     }
00559 
00560     // Look for "ZipItems" section
00561 
00562     if(!ReadSectionHeader(reader, g_TOKEN_ArchiveItems, 0, &zipItemCount))
00563         goto out;
00564 
00565     // Alloc room in the WorkingSet for the zipItemarray.
00566 
00567     if(zipItemCount)
00568         if(!aWorkingSet->NewZipItemArray(zipItemCount))   
00569             goto out;    
00570 
00571     // Read the zipItem records
00572 
00573     for(i = 0; i < zipItemCount; ++i)
00574     {
00575         if(!reader.NextLine())
00576             goto out;
00577 
00578         // index,filename
00579         if(2 != reader.ParseLine(values, lengths, 2))
00580             goto out;
00581 
00582         // index
00583         if(i != atoi(values[0]))
00584             goto out;
00585 
00586         // filename
00587         if(!*values[1])
00588             goto out;
00589         
00590         // Append a new zipItem record to the array.
00591 
00592         aWorkingSet->AppendZipItem(xptiZipItem(values[1], aWorkingSet));
00593     }
00594 
00595     // Look for "Interfaces" section
00596 
00597     if(!ReadSectionHeader(reader, g_TOKEN_Interfaces, 1, &interfaceCount))
00598         goto out;
00599 
00600     // Read the interface records
00601 
00602     for(i = 0; i < interfaceCount; ++i)
00603     {
00604         int fileIndex;
00605         int zipItemIndex;
00606         nsIID iid;
00607         xptiInterfaceEntry* entry;
00608         xptiTypelib typelibRecord;
00609 
00610         if(!reader.NextLine())
00611             goto out;
00612 
00613         // index,interfaceName,iid,fileIndex,zipIndex,flags
00614         if(6 != reader.ParseLine(values, lengths, 6))
00615             goto out;
00616 
00617         // index
00618         if(i != atoi(values[0]))
00619             goto out;
00620 
00621         // interfaceName
00622         if(!*values[1])
00623             goto out;
00624 
00625         // iid
00626         if(!iid.Parse(values[2]))
00627             goto out;
00628 
00629         // fileIndex
00630         fileIndex = atoi(values[3]);
00631         if(fileIndex < 0 || fileIndex >= fileCount)
00632             goto out;
00633 
00634         // zipIndex (NOTE: -1 is a valid value)
00635         zipItemIndex = atoi(values[4]);
00636         if(zipItemIndex < -1 || zipItemIndex >= zipItemCount)
00637             goto out;
00638 
00639         // flags
00640         flags = atoi(values[5]);
00641         if(flags != 0 && flags != 1)
00642             goto out;
00643         
00644         // Build an InterfaceInfo and hook it in.
00645 
00646         if(zipItemIndex == -1)
00647             typelibRecord.Init(fileIndex);
00648         else
00649             typelibRecord.Init(fileIndex, zipItemIndex);
00650         
00651         entry = xptiInterfaceEntry::NewEntry(values[1], lengths[1],
00652                                              iid, typelibRecord, 
00653                                              aWorkingSet);
00654         if(!entry)
00655             goto out;    
00656         
00657         entry->SetScriptableFlag(flags==1);
00658 
00659         // Add our entry to the iid hashtable.
00660 
00661         hashEntry = (xptiHashEntry*)
00662             PL_DHashTableOperate(aWorkingSet->mNameTable, 
00663                                  entry->GetTheName(), PL_DHASH_ADD);
00664         if(hashEntry)
00665             hashEntry->value = entry;
00666     
00667         // Add our entry to the name hashtable.
00668 
00669         hashEntry = (xptiHashEntry*)
00670             PL_DHashTableOperate(aWorkingSet->mIIDTable, 
00671                                  entry->GetTheIID(), PL_DHASH_ADD);
00672         if(hashEntry)
00673             hashEntry->value = entry;
00674     }
00675 
00676     // success!
00677 
00678     succeeded = PR_TRUE;
00679 
00680  out:
00681     if(whole)
00682         delete [] whole;
00683 
00684     if(!succeeded)
00685     {
00686         // Cleanup the WorkingSet on failure.
00687         aWorkingSet->InvalidateInterfaceInfos();
00688         aWorkingSet->ClearHashTables();
00689         aWorkingSet->ClearFiles();
00690     }
00691     return succeeded;
00692 }        
00693 
00694 // static 
00695 PRBool xptiManifest::Delete(xptiInterfaceInfoManager* aMgr)
00696 {
00697     nsCOMPtr<nsILocalFile> aFile;
00698     if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(aFile)) || !aFile)
00699         return PR_FALSE;
00700 
00701     PRBool exists;
00702     if(NS_FAILED(aFile->Exists(&exists)))
00703         return PR_FALSE;
00704 
00705     if(exists && NS_FAILED(aFile->Remove(PR_FALSE)))
00706         return PR_FALSE;
00707     
00708     return PR_TRUE;
00709 }
00710