Back to index

lightning-sunbird  0.9+nobinonly
nsZipExtractor.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Samir Gehani <sgehani@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 #include "nsZipExtractor.h"
00041 
00042 #define STANDALONE 1
00043 #include "zipstub.h"
00044 #include "zipfile.h"
00045 
00046 nsZipExtractor::nsZipExtractor(char *aSrc, char *aDest) :
00047     mSrc(NULL),
00048     mDest(NULL)
00049 {
00050     if (aSrc)
00051         mSrc = strdup(aSrc);
00052     if (aDest)
00053         mDest = strdup(aDest);
00054 }
00055 
00056 nsZipExtractor::~nsZipExtractor()
00057 {
00058     XI_IF_FREE(mSrc);
00059     XI_IF_FREE(mDest);
00060 }
00061 
00062 int
00063 nsZipExtractor::Extract(nsComponent *aXPIEngine, int aTotal)
00064 {
00065     DUMP("Extract");
00066 
00067     char apath[MAXPATHLEN]; /* archive path */
00068     char bindir[512];
00069     char zpath[MAXPATHLEN]; /* path of file in zip archive */
00070     char epath[MAXPATHLEN]; /* path of file after being extracted */
00071     char *leaf = NULL, *lslash = NULL;
00072     struct stat dummy;
00073     int i, bFoundAll = FALSE, err = OK;
00074     PRInt32 zerr = ZIP_OK;
00075     PRUint32 len;
00076     void *hZip = NULL, *hFind = NULL;
00077 
00078     if (!aXPIEngine || !(aXPIEngine->GetArchive()))
00079         return E_PARAM;
00080 
00081     len=snprintf(apath,sizeof(apath),"%s/%s", mSrc, aXPIEngine->GetArchive());
00082     if ( len >= sizeof(apath) )
00083         return E_PARAM; /* this should be something like E_PATH_TOO_LONG */
00084 
00085     if (-1 == stat(apath, &dummy))
00086         return E_NO_DOWNLOAD;
00087 
00088     /* initialize archive etc.
00089      */
00090     zerr = ZIP_OpenArchive(apath, &hZip);
00091     if (zerr != ZIP_OK) return E_EXTRACTION;
00092     hFind = ZIP_FindInit(hZip, (const char *) NULL);
00093     if (!hFind)
00094     {
00095         err = E_EXTRACTION;
00096         goto au_revoir;
00097     }
00098 
00099     /* extract files
00100      */
00101     i = 0;
00102     while (!bFoundAll)
00103     {
00104         memset(zpath, 0, MAXPATHLEN);
00105         zerr = ZIP_FindNext(hFind, zpath, MAXPATHLEN);
00106         if (zerr == ZIP_ERR_FNF)
00107         {
00108             bFoundAll = true;
00109             break;
00110         }
00111         if (zerr != ZIP_OK)
00112         {
00113             err = E_EXTRACTION;
00114             goto au_revoir;
00115         }
00116 
00117         /* directory encountered: ignore entry
00118          */
00119         lslash = strrchr(zpath, '/');
00120         if (lslash == (zpath + strlen(zpath) - 1))
00121             continue;
00122 
00123         if (!lslash)
00124             leaf = zpath;
00125         else
00126             leaf = lslash + 1;
00127         if (!leaf)
00128             continue;
00129 
00130         /* update UI
00131          */
00132         if (gCtx->opt->mMode != nsXIOptions::MODE_SILENT)
00133             nsInstallDlg::MajorProgressCB(leaf, i,
00134                 aTotal, nsInstallDlg::ACT_EXTRACT);
00135 
00136         len=snprintf(epath,sizeof(epath),"%s/%s", mDest, zpath);
00137         if ( len >= sizeof(apath) )
00138         {
00139             err = E_PARAM; /* this should be something like E_PATH_TOO_LONG */
00140             goto au_revoir;
00141         }
00142         err = DirCreateRecursive(epath);
00143         if (err != OK) goto au_revoir;
00144 
00145         zerr = ZIP_ExtractFile(hZip, zpath, epath);
00146         if (zerr != ZIP_OK)
00147         {
00148             err = E_EXTRACTION;
00149             goto au_revoir;
00150         }
00151 
00152         i++;
00153     }
00154 
00155     len=snprintf(bindir,sizeof(bindir),"%s/%s", mDest, TMP_EXTRACT_SUBDIR);
00156     if ( len >= sizeof(bindir) )
00157     {
00158         err = E_PARAM; /* this should be something like E_PATH_TOO_LONG */
00159         goto au_revoir;
00160     }
00161 
00162     if (-1 == stat(bindir, &dummy))
00163         err = E_EXTRACTION;
00164 
00165 au_revoir:
00166     /* close archive etc.
00167      */
00168     if (hFind)
00169         ZIP_FindFree(hFind);
00170     if (hZip)
00171         ZIP_CloseArchive(&hZip);
00172     return err;
00173 }
00174 
00175 int
00176 nsZipExtractor::DirCreateRecursive(char *aPath)
00177 {
00178     PRUint32 len;
00179     int err = OK;
00180     char *slash = NULL;
00181     char currdir[MAXPATHLEN];
00182     struct stat dummy;
00183 
00184     if (!aPath || !mDest)
00185         return E_PARAM;
00186 
00187     slash = aPath + strlen(mDest);
00188     if (*slash != '/')
00189         return E_INVALID_PTR;
00190 
00191     while (slash)
00192     {
00193         len = slash - aPath;
00194         if (len >= sizeof(currdir)) return E_PARAM; // should not happen, just being defensive
00195 
00196         snprintf(currdir,len+1,"%s",aPath);
00197 
00198         if (-1 == stat(currdir, &dummy))
00199         {
00200             if (-1 == mkdir(currdir, 0755))
00201                 return E_MKDIR_FAIL;
00202         }
00203 
00204         slash = strchr(slash+1, '/');
00205     }
00206 
00207     return err;
00208 }