Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Public Attributes | Private Member Functions | Private Attributes
nsZipArchive Class Reference

nsZipArchive -- a class for reading the PKZIP file format. More...

#include <nsZipArchive.h>

Collaboration diagram for nsZipArchive:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 nsZipArchive ()
 constructing does not open the archive.
 ~nsZipArchive ()
 destructing the object closes the archive
PRInt32 OpenArchiveWithFileDesc (PRFileDesc *fd)
 OpenArchive.
PRInt32 Test (const char *aEntryName, PRFileDesc *aFd)
 Test the integrity of items in this archive by running a CRC check after extracting each item into a memory buffer.
PRInt32 CloseArchive ()
 Closes an open archive.
PRInt32 GetItem (const char *aFilename, nsZipItem **result)
 GetItem.
PRInt32 ReadInit (const char *zipEntry, nsZipReadState *aRead, PRFileDesc *aFd)
 ReadInit.
PRInt32 ExtractFile (const char *zipEntry, const char *aOutname, PRFileDesc *aFd)
 ExtractFile.
PRInt32 ExtractItemToFileDesc (nsZipItem *item, PRFileDesc *outFD, PRFileDesc *aFd)
nsZipFindFindInit (const char *aPattern)
 FindInit.
PRInt32 FindNext (nsZipFind *aFind, nsZipItem **aResult)
 FindNext.
PRInt32 FindFree (nsZipFind *aFind)

Public Attributes

const PRInt32 kMagic
 cookie used to validate supposed objects passed from C code
const PRUint32 kArenaBlockSize
 Block size by which Arena grows.

Private Member Functions

nsZipArchiveoperator= (const nsZipArchive &rhs)
 nsZipArchive (const nsZipArchive &rhs)
PRInt32 BuildFileList (PRFileDesc *aFd)
nsZipItemGetFileItem (const char *zipEntry)
PRUint32 HashName (const char *aName)
PRInt32 SeekToItem (const nsZipItem *aItem, PRFileDesc *aFd)
PRInt32 CopyItemToDisk (const nsZipItem *aItem, PRFileDesc *outFD, PRFileDesc *aFd)
PRInt32 InflateItem (const nsZipItem *aItem, PRFileDesc *outFD, PRFileDesc *aFd)
PRInt32 TestItem (const nsZipItem *aItem, PRFileDesc *aFd)

Private Attributes

nsZipItemmFiles [ZIP_TABSIZE]
PLArenaPool mArena

Detailed Description

nsZipArchive -- a class for reading the PKZIP file format.

Definition at line 165 of file nsZipArchive.h.


Constructor & Destructor Documentation

constructing does not open the archive.

See OpenArchive()

Definition at line 1739 of file nsZipArchive.cpp.

  : kMagic(ZIP_MAGIC), kArenaBlockSize(1*1024)
#ifdef STANDALONE
    , mFd(0)
#endif
{
  MOZ_COUNT_CTOR(nsZipArchive);

  // initialize the table to NULL
  memset(mFiles, 0, sizeof mFiles);

#ifndef STANDALONE
  // Initialize our arena
  PL_INIT_ARENA_POOL(&mArena, "ZipArena", kArenaBlockSize);
#endif
}

Here is the call graph for this function:

destructing the object closes the archive

Definition at line 1756 of file nsZipArchive.cpp.

Here is the call graph for this function:


Member Function Documentation

Definition at line 880 of file nsZipArchive.cpp.

{
  PRInt32   status = ZIP_OK;
  PRUint8   buf[4*BR_BUF_SIZE];

  ZipEnd     *End;

  //-----------------------------------------------------------------------
  // locate the central directory via the End record
  //-----------------------------------------------------------------------
  PRInt32  pos = 0L;
  PRInt32  bufsize = 0;

  //-- get archive size using end pos
  pos = PR_Seek(aFd, 0, PR_SEEK_END);
#ifndef STANDALONE
  if (pos <= 0)
#else
  if (pos || ((pos = ftell(aFd)) <= 0))
#endif
    status = ZIP_ERR_CORRUPT;

  while (status == ZIP_OK)
  {
    //-- read backwards in 1K-sized chunks (unless file is less than 1K)
    pos > BR_BUF_SIZE ? bufsize = BR_BUF_SIZE : bufsize = pos;
    pos -= bufsize;

    if (!ZIP_Seek(aFd, pos, PR_SEEK_SET))
    {
      status = ZIP_ERR_CORRUPT;
      break;
    }

    if (PR_Read(aFd, buf, bufsize) != (READTYPE)bufsize)
    {
      status = ZIP_ERR_CORRUPT;
      break;
    }

    //-- scan for ENDSIG
    PRUint8 *endp = buf + bufsize;
    PRUint32 endsig;
    PRBool bEndsigFound = PR_FALSE;

    for (endp -= ZIPEND_SIZE; endp >= buf; endp--)
    {
      endsig = xtolong(endp);
      if (endsig == ENDSIG)
      {
        bEndsigFound = PR_TRUE;
        break;
      }
    }

    if (bEndsigFound)
    {
      End = (ZipEnd *) endp;

      //-- set pos to start of central directory
      pos = xtolong(End->offset_central_dir);
      if (!ZIP_Seek(aFd, pos, PR_SEEK_SET))
        status = ZIP_ERR_CORRUPT;

      break;
    }

    if(pos <= 0)
      //-- We're at the beginning of the file, and still no sign
      //-- of the end signiture.  File must be corrupted!
      status = ZIP_ERR_CORRUPT;

    //-- backward read must overlap ZipEnd length
    pos += ZIPEND_SIZE;

  } /* while looking for end signature */


  //-------------------------------------------------------
  // read the central directory headers
  //-------------------------------------------------------
  if (status == ZIP_OK)
  {
    //-- we think we found the central directory, read in the first chunk
    pos = 0;
    bufsize = PR_Read(aFd, &buf, sizeof(buf));
    if (bufsize < (PRInt32)(ZIPCENTRAL_SIZE + ZIPEND_SIZE))
    {
      // We know we read the end sig and got pointed at the central
      // directory--there should be at least this much
      //
      // (technically there can be a completely empty archive with only a
      // ZipEnd structure; that's pointless and might as well be an error.)
      status = ZIP_ERR_DISK;
    }

    //-- verify it's a central directory record
    if (xtolong(buf) != CENTRALSIG)
      status = ZIP_ERR_CORRUPT;
  }

  //-- loop through directory records
  //
  //-- we enter the loop positioned at a central directory record
  //-- with enough valid data in the buffer to contain one
  while (status == ZIP_OK)
  {
    //-------------------------------------------------------
    // read the fixed-size data
    //-------------------------------------------------------
    ZipCentral* central = (ZipCentral*)(buf+pos);

    PRUint32 namelen = xtoint(central->filename_len);
    PRUint32 extralen = xtoint(central->extrafield_len);
    PRUint32 commentlen = xtoint(central->commentfield_len);

    //-- sanity check variable sizes and refuse to deal with
    //-- anything too big: it's likely a corrupt archive
    if (namelen > BR_BUF_SIZE || extralen > BR_BUF_SIZE || commentlen > 2*BR_BUF_SIZE) {
      status = ZIP_ERR_CORRUPT;
      break;
    }

#ifndef STANDALONE
    // Arena allocate the nsZipItem
    void *mem;
    PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsZipItem));
    // Use placement new to arena allcoate the nsZipItem
    nsZipItem* item = mem ? new (mem) nsZipItem() : nsnull;
#else
    nsZipItem* item = new nsZipItem();
#endif
    if (!item)
    {
      status = ZIP_ERR_MEMORY;
      break;
    }

    item->headerOffset = xtolong(central->localhdr_offset);
    item->dataOffset = 0;
    item->hasDataOffset = PR_FALSE;
    item->size = xtolong(central->size);
    item->realsize = xtolong(central->orglen);
    item->crc32 = xtolong(central->crc32);
    PRUint32 external_attributes = xtolong(central->external_attributes);
    item->mode = ExtractMode(external_attributes);
    item->isSymlink = IsSymlink(external_attributes);
    item->time = xtoint(central->time);
    item->date = xtoint(central->date);

    PRUint16 compression = xtoint(central->method);
    item->compression = (compression < UNSUPPORTED) ? (PRUint8)compression
                                                    : UNSUPPORTED;

    pos += ZIPCENTRAL_SIZE;

    //-------------------------------------------------------
    // get the item name
    //-------------------------------------------------------
#ifndef STANDALONE
    PL_ARENA_ALLOCATE(mem, &mArena, (namelen + 1));
    item->name = (char *) mem;
    if (!item->name)
    {
      status = ZIP_ERR_MEMORY;
      // No need to delete name. It gets deleted only when the entire arena
      // goes away.
      break;
    }
#else
    item->name = new char[namelen + 1];
    if (!item->name)
    {
      status = ZIP_ERR_MEMORY;
      delete item;
      break;
    }
#endif

    PRUint32 leftover = (PRUint32)(bufsize - pos);
    if (leftover < namelen)
    {
      //-- not enough data left in buffer for the name.
      //-- move leftover to top of buffer and read more
      memcpy(buf, buf+pos, leftover);
      bufsize = leftover + PR_Read(aFd, buf+leftover, bufsize-leftover);
      pos = 0;

      //-- make sure we were able to read enough
      if ((PRUint32)bufsize < namelen)
      {
        status = ZIP_ERR_CORRUPT;
        break;
      }
    }
    memcpy(item->name, buf+pos, namelen);
    item->name[namelen] = 0;

    //-- add item to file table
    PRUint32 hash = HashName(item->name);
    item->next = mFiles[hash];
    mFiles[hash] = item;

    pos += namelen;

    //-------------------------------------------------------
    // set up to process the next item at the top of loop
    //-------------------------------------------------------
    leftover = (PRUint32)(bufsize - pos);
    if (leftover < (extralen + commentlen + ZIPCENTRAL_SIZE))
    {
      //-- not enough data left to process at top of loop.
      //-- move leftover and read more
      memcpy(buf, buf+pos, leftover);
      bufsize = leftover + PR_Read(aFd, buf+leftover, bufsize-leftover);
      pos = 0;

      //-- make sure we were able to read enough
      if ((PRUint32)bufsize < (extralen + commentlen + sizeof(PRUint32)))
      {
        status = ZIP_ERR_CORRUPT;
        break;
      }
    }
    //-- set position to start of next ZipCentral record
    pos += extralen + commentlen;

    // verify we're at an expected structure in the file
    PRUint32 sig = xtolong(buf+pos);
    if (sig != CENTRALSIG)
    {
      //-- we must be done or else archive is corrupt
      if (sig != ENDSIG)
        status = ZIP_ERR_CORRUPT;
      break;
    }

    //-- make sure we've read enough
    if (bufsize < pos + ZIPCENTRAL_SIZE)
    {
      status = ZIP_ERR_CORRUPT;
      break;
    }
  } /* while reading central directory records */

#if defined(DEBUG)
  if (status != ZIP_OK) {
    const char* msgs[] = { "ZIP_OK", "ZIP_ERR_GENERAL", "ZIP_ERR_MEMORY", "ZIP_ERR_DISK", "ZIP_ERR_CORRUPT", "ZIP_ERR_PARAM", "ZIP_ERR_FNF", "ZIP_ERR_UNSUPPORTED", "ZIP_ERR_SMALLBUF", "UNKNOWN" };
    printf("nsZipArchive::BuildFileList  status = %d '%s'\n", (int)status, msgs[(status <= 0 && status >= -8) ? -status : 9]);
  }
#endif

  return status;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Closes an open archive.

Definition at line 547 of file nsZipArchive.cpp.

{
  
#ifndef STANDALONE
  PL_FinishArenaPool(&mArena);

  // CAUTION:
  // We dont need to delete each of the nsZipItem as the memory for
  // the zip item and the filename it holds are both allocated from the Arena.
  // Hence, destroying the Arena is like destroying all the memory
  // for all the nsZipItem in one shot. But if the ~nsZipItem is doing
  // anything more than cleaning up memory, we should start calling it.

  memset(mFiles, 0, sizeof(mFiles));

#else
  // delete nsZipItems in table
  nsZipItem* pItem;
  for (int i = 0; i < ZIP_TABSIZE; ++i)
  {
    pItem = mFiles[i];
    while (pItem != 0)
    {
      mFiles[i] = pItem->next;
      delete pItem;
      pItem = mFiles[i];
    }
    mFiles[i] = 0;              // make sure we don't double-delete
  }
  
  if (mFd) {
    PR_Close(mFd);
    mFd = 0;
  }
#endif

  return ZIP_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRInt32 nsZipArchive::CopyItemToDisk ( const nsZipItem aItem,
PRFileDesc outFD,
PRFileDesc aFd 
) [private]

Definition at line 1218 of file nsZipArchive.cpp.

{
  PRInt32     status = ZIP_OK;
  PRUint32    chunk, pos, size, crc;

  PR_ASSERT(aItem != 0 && fOut != 0);

  PRFileDesc* fd = aFd;
  
  //-- move to the start of file's data
  if (SeekToItem(aItem, aFd) != ZIP_OK)
    return ZIP_ERR_CORRUPT;

  char buf[ZIP_BUFLEN];

  //-- initialize crc
  crc = crc32(0L, Z_NULL, 0);

  //-- copy chunks until file is done
  size = aItem->size;
  for (pos=0; pos < size; pos += chunk)
  {
    chunk = (pos+ZIP_BUFLEN <= size) ? ZIP_BUFLEN : size - pos;

    if (PR_Read(fd, buf, chunk) != (READTYPE)chunk)
    {
      //-- unexpected end of data in archive
      status = ZIP_ERR_CORRUPT;
      break;
    }

    //-- incrementally update crc32
    crc = crc32(crc, (const unsigned char*)buf, chunk);

    if (PR_Write(fOut, buf, chunk) < (READTYPE)chunk)
    {
      //-- Couldn't write all the data (disk full?)
      status = ZIP_ERR_DISK;
      break;
    }
  }

  //-- verify crc32
  if ((status == ZIP_OK) && (crc != aItem->crc32))
      status = ZIP_ERR_CORRUPT;

  return status;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRInt32 nsZipArchive::ExtractFile ( const char *  zipEntry,
const char *  aOutname,
PRFileDesc aFd 
)

ExtractFile.

Parameters:
zipEntryname of file in archive to extract
aOutnamewhere to extract on disk
Returns:
status code

Definition at line 660 of file nsZipArchive.cpp.

{
  //-- Find item in archive
  nsZipItem* item = GetFileItem(zipEntry);
  if (!item)
    return ZIP_ERR_FNF;

  // delete any existing file so that we overwrite the file permissions
  PR_Delete(aOutname);

  PRFileDesc* fOut = PR_Open(aOutname, ZFILE_CREATE, item->mode);
  if (fOut == 0)
    return ZIP_ERR_DISK;

#if defined(XP_UNIX) && defined(STANDALONE)
  // When STANDALONE is defined, PR_Open ignores its 3d argument.
  mode_t msk = umask(0);
  umask(msk);
  chmod(aOutname, item->mode & ~msk);
#endif

  PRInt32 status = ExtractItemToFileDesc(item, fOut, aFd);
  PR_Close(fOut);

  if (status != ZIP_OK)
  {
    PR_Delete(aOutname);
  }
#if defined(XP_UNIX)
  else
  {
    if (item->isSymlink)
    {
      status = ResolveSymlink(aOutname, item);
    }
  }
#endif
  return status;
}

Here is the call graph for this function:

Definition at line 702 of file nsZipArchive.cpp.

{
  //-- sanity check arguments
  if (item == 0 || outFD == 0)
    return ZIP_ERR_PARAM;

  PRInt32 status;

  //-- extract the file using the appropriate method
  switch(item->compression)
  {
    case STORED:
      status = CopyItemToDisk(item, outFD, aFd);
      break;

    case DEFLATED:
      status = InflateItem(item, outFD, aFd);
      break;

    default:
      //-- unsupported compression type
      return ZIP_ERR_UNSUPPORTED;
  }

  return status;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 827 of file nsZipArchive.cpp.

{
  if (aFind->mArchive != this)
    return ZIP_ERR_PARAM;

  delete aFind;
  return ZIP_OK;
}

Here is the caller graph for this function:

nsZipFind * nsZipArchive::FindInit ( const char *  aPattern)

FindInit.

Initializes a search for files in the archive. FindNext() returns the actual matches. FindFree() must be called when you're done

Parameters:
aPatterna string or RegExp pattern to search for (may be NULL to find all files in archive)
Returns:
a structure used in FindNext. NULL indicates error

Definition at line 733 of file nsZipArchive.cpp.

{
  PRBool  regExp = PR_FALSE;
  char*   pattern = 0;

  // validate the pattern
  if (aPattern)
  {
    switch (NS_WildCardValid((char*)aPattern))
    {
      case INVALID_SXP:
        return 0;

      case NON_SXP:
        regExp = PR_FALSE;
        break;

      case VALID_SXP:
        regExp = PR_TRUE;
        break;

      default:
        // undocumented return value from RegExpValid!
        PR_ASSERT(PR_FALSE);
        return 0;
    }

    pattern = PL_strdup(aPattern);
    if (!pattern)
      return 0;
  }

  return new nsZipFind(this, pattern, regExp);
}

Here is the caller graph for this function:

PRInt32 nsZipArchive::FindNext ( nsZipFind aFind,
nsZipItem **  aResult 
)

FindNext.

Parameters:
aFindthe Find structure returned by FindInit
aResultthe next item that matches the pattern

Definition at line 773 of file nsZipArchive.cpp.

{
  PRInt32    status;
  PRBool     found  = PR_FALSE;
  PRUint16   slot   = aFind->mSlot;
  nsZipItem* item   = aFind->mItem;

  if (aFind->mArchive != this)
    return ZIP_ERR_PARAM;

  // we start from last match, look for next
  while (slot < ZIP_TABSIZE && !found)
  {
    if (item != 0)
      item = item->next;    // move to next in current chain
    else
      item = mFiles[slot];  // starting a new slot

    if (item == 0)
    { // no more in this chain, move to next slot
      ++slot;
      continue;
    }
    else if (aFind->mPattern == 0)
      found = PR_TRUE;            // always match
    else if (aFind->mRegExp)
      found = (NS_WildCardMatch(item->name, aFind->mPattern, PR_FALSE) == MATCH);
    else
#if defined(STANDALONE) && defined(XP_MAC)
      // simulate <regexp>* matches
      found = (strncmp(item->name, aFind->mPattern, strlen(aFind->mPattern)) == 0);
#else
      found = (PL_strcmp(item->name, aFind->mPattern) == 0);
#endif
  }

  if (found)
  {
      *aResult = item;
      aFind->mSlot = slot;
      aFind->mItem = item;
      status = ZIP_OK;
  }
  else
    status = ZIP_ERR_FNF;

  return status;
}

Here is the caller graph for this function:

nsZipItem * nsZipArchive::GetFileItem ( const char *  zipEntry) [private]

Definition at line 1138 of file nsZipArchive.cpp.

{
  PR_ASSERT(zipEntry != 0);

  nsZipItem* item = mFiles[ HashName(zipEntry) ];

  for (; item != 0; item = item->next)
  {
    if (0 == PL_strcmp(zipEntry, item->name))
      break; //-- found it
  }

  return item;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRInt32 nsZipArchive::GetItem ( const char *  aFilename,
nsZipItem **  result 
)

GetItem.

Parameters:
aFilenameName of file in the archive
Returns:
status code

Definition at line 589 of file nsZipArchive.cpp.

{
    //-- Parameter validity check
    if (aFilename == 0)
        return ZIP_ERR_PARAM;

    nsZipItem* item;

    //-- find file information
    item = GetFileItem(aFilename);
    if (item == 0)
    {
        return ZIP_ERR_FNF;
    }

    *result = item; // Return a pointer to the struct
    return ZIP_OK;
}

Here is the call graph for this function:

PRUint32 nsZipArchive::HashName ( const char *  aName) [private]

Definition at line 1157 of file nsZipArchive.cpp.

{
  PRUint32 val = 0;
  PRUint8* c;

  PR_ASSERT(aName != 0);

  for (c = (PRUint8*)aName; *c != 0; c++) {
    val = val*37 + *c;
  }

  return (val % ZIP_TABSIZE);
}

Here is the caller graph for this function:

PRInt32 nsZipArchive::InflateItem ( const nsZipItem aItem,
PRFileDesc outFD,
PRFileDesc aFd 
) [private]

Definition at line 1410 of file nsZipArchive.cpp.

{
  PRInt32     status = ZIP_OK;
  PRUint32    chunk, inpos, outpos, size, crc;
  PRUint32    bigBufSize=0;
  z_stream    zs;
  int         zerr;
  PRBool      bInflating = PR_FALSE;
  PRBool      bRead;
  PRBool      bWrote;
  PRBool      bToFile;
  Bytef*      old_next_out;

  // -- if aOutname is null, we'll be writing to a buffer instead of a file
  if (fOut != 0)
  {
    PR_ASSERT(aItem != 0);
    bToFile = PR_TRUE;
  }
  else
  {
    // -- Writing to a buffer, so bigBuf must not be null.
    PR_ASSERT(aItem);
    bToFile = PR_FALSE;
    bigBufSize = aItem->realsize;
  }

  //-- move to the start of file's data
  if (SeekToItem(aItem, aFd) != ZIP_OK)
    return ZIP_ERR_CORRUPT;

  //-- allocate deflation buffers
  Bytef inbuf[ZIP_BUFLEN];
  Bytef outbuf[ZIP_BUFLEN];

  //-- set up the inflate
  memset(&zs, 0, sizeof(zs));
#ifndef STANDALONE
  //-- ensure we have our zlib allocator for better performance
  if (!gZlibAllocator) {
    gZlibAllocator = new nsRecyclingAllocator(NBUCKETS, NS_DEFAULT_RECYCLE_TIMEOUT, "libjar");
  }

  zs.zalloc = zlibAlloc;
  zs.zfree = zlibFree;
  zs.opaque = gZlibAllocator;
#endif

  zerr = inflateInit2(&zs, -MAX_WBITS);
  if (zerr != Z_OK)
  {
    status = ZIP_ERR_GENERAL;
    goto cleanup;
  }
  bInflating = PR_TRUE;


  //-- inflate loop
  size = aItem->size;
  outpos = inpos = 0;
  zs.next_out = outbuf;
  zs.avail_out = ZIP_BUFLEN;
  crc = crc32(0L, Z_NULL, 0);
  while (zerr == Z_OK)
  {
    bRead  = PR_FALSE;
    bWrote = PR_FALSE;

    if (zs.avail_in == 0 && zs.total_in < size)
    {
      //-- no data to inflate yet still more in file:
      //-- read another chunk of compressed data

      inpos = zs.total_in;  // input position
      chunk = (inpos + ZIP_BUFLEN <= size) ? ZIP_BUFLEN : size - inpos;

      if (PR_Read(aFd, inbuf, chunk) != (READTYPE)chunk)
      {
        //-- unexpected end of data
        status = ZIP_ERR_CORRUPT;
        break;
      }

      zs.next_in  = inbuf;
      zs.avail_in = chunk;
      bRead       = PR_TRUE;
    }

    if (zs.avail_out == 0)
    {
      //-- write inflated buffer to disk and make space
      if (PR_Write(fOut, outbuf, ZIP_BUFLEN) < ZIP_BUFLEN)
      {
        //-- Couldn't write all the data (disk full?)
        status = ZIP_ERR_DISK;
        break;
      }

      outpos = zs.total_out;
      zs.next_out  = outbuf;
      zs.avail_out = ZIP_BUFLEN;
      bWrote       = PR_TRUE;
    }

    if(bRead || bWrote)
    {
      old_next_out = zs.next_out;

      zerr = inflate(&zs, Z_PARTIAL_FLUSH);

      //-- incrementally update crc32
      crc = crc32(crc, (const unsigned char*)old_next_out, zs.next_out - old_next_out);
    }
    else
      zerr = Z_STREAM_END;

#if defined STANDALONE && defined XP_WIN
    ProcessWindowsMessages();
#endif
  } // while

  //-- verify crc32
  if ((status == ZIP_OK) && (crc != aItem->crc32))
  {
      status = ZIP_ERR_CORRUPT;
      goto cleanup;
  }

  //-- write last inflated bit to disk
  if (zerr == Z_STREAM_END && outpos < zs.total_out)
  {
    chunk = zs.total_out - outpos;
    if (PR_Write(fOut, outbuf, chunk) < (READTYPE)chunk)
      status = ZIP_ERR_DISK;
  }

  //-- convert zlib error to return value
  if (status == ZIP_OK && zerr != Z_OK && zerr != Z_STREAM_END)
  {
    status = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT;
  }

  //-- if found no errors make sure we've converted the whole thing
  PR_ASSERT(status != ZIP_OK || zs.total_in == aItem->size);
  PR_ASSERT(status != ZIP_OK || zs.total_out == aItem->realsize);

cleanup:
  if (bInflating)
  {
    //-- free zlib internal state
    inflateEnd(&zs);
  }

  return status;
}

Here is the call graph for this function:

Here is the caller graph for this function:

OpenArchive.

It's an error to call this more than once on the same nsZipArchive object. If we were allowed to use exceptions this would have been part of the constructor

Parameters:
aArchiveNamefull pathname of archive
Returns:
status code

Definition at line 491 of file nsZipArchive.cpp.

{
  //-- validate arguments
  if (fd == 0)
    return ZIP_ERR_PARAM;

  //-- get table of contents for archive
  return BuildFileList(fd);
}

Here is the call graph for this function:

nsZipArchive& nsZipArchive::operator= ( const nsZipArchive rhs) [private]
PRInt32 nsZipArchive::ReadInit ( const char *  zipEntry,
nsZipReadState aRead,
PRFileDesc aFd 
)

ReadInit.

Prepare to read from an item in the archive. Takes ownership of the file descriptor, and will retain responsibility for closing it property upon destruction.

Parameters:
zipEntryname of item in file
aReadis filled with appropriate values
Returns:
status code

Definition at line 611 of file nsZipArchive.cpp.

{
 
  //-- Parameter validity check
  if (zipEntry == 0 || aRead == 0)
    return ZIP_ERR_PARAM;

  //-- find item
  nsZipItem* item = GetFileItem(zipEntry);
  if (!item) {
    PR_Close(aFd);
    return ZIP_ERR_FNF;
  }

  //-- verify we can handle the compression type
  if (item->compression != DEFLATED && item->compression != STORED) {
    PR_Close(aFd);
    return ZIP_ERR_UNSUPPORTED;
  }

  SeekToItem(item, aFd);

#ifdef STANDALONE
  // in standalone, nsZipArchive owns the file descriptor
  mFd = aFd;
#endif
  
  // in non-standalone builds, the nsZipReadState will take ownership
  // of the file descriptor
  aRead->Init(item, aFd);
    
  return ZIP_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRInt32 nsZipArchive::SeekToItem ( const nsZipItem aItem,
PRFileDesc aFd 
) [private]

Definition at line 1174 of file nsZipArchive.cpp.

{
  PR_ASSERT (aItem);

  PRFileDesc* fd = aFd;
  
  //-- the first time an item is used we need to calculate its offset
  if (!aItem->hasDataOffset)
  {
    //-- read local header to get variable length values and calculate
    //-- the real data offset
    //--
    //-- NOTE: extralen is different in central header and local header
    //--       for archives created using the Unix "zip" utility. To set
    //--       the offset accurately we need the _local_ extralen.
    if (!ZIP_Seek(fd, aItem->headerOffset, PR_SEEK_SET))
      return ZIP_ERR_CORRUPT;

    ZipLocal   Local;
    if (PR_Read(fd, (char*)&Local, ZIPLOCAL_SIZE) != (READTYPE) ZIPLOCAL_SIZE
         || xtolong(Local.signature) != LOCALSIG)
    {
      //-- read error or local header not found
      return ZIP_ERR_CORRUPT;
    }

    ((nsZipItem*)aItem)->dataOffset = aItem->headerOffset +
                                      ZIPLOCAL_SIZE +
                                      xtoint(Local.filename_len) +
                                      xtoint(Local.extrafield_len);
    ((nsZipItem*)aItem)->hasDataOffset = PR_TRUE;
  }

  //-- move to start of file in archive
  if (!ZIP_Seek(fd, aItem->dataOffset, PR_SEEK_SET))
    return  ZIP_ERR_CORRUPT;

  return ZIP_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRInt32 nsZipArchive::Test ( const char *  aEntryName,
PRFileDesc aFd 
)

Test the integrity of items in this archive by running a CRC check after extracting each item into a memory buffer.

If an entry name is supplied only the specified item is tested. Else, if null is supplied then all the items in the archive are tested.

Returns:
status code

Definition at line 505 of file nsZipArchive.cpp.

{
  PRInt32 rv = ZIP_OK;
  nsZipItem *currItem = 0;

  if (aEntryName) // only test specified item
  {
    currItem = GetFileItem(aEntryName);
    if(!currItem)
      return ZIP_ERR_FNF;

    rv = TestItem(currItem, aFd);
  }
  else // test all items in archive
  {
    nsZipFind *iterator = FindInit(NULL);
    if (!iterator)
      return ZIP_ERR_GENERAL;

    // iterate over items in list
    while (ZIP_OK == FindNext(iterator, &currItem))
    {
      rv = TestItem(currItem, aFd);

      // check if crc check failed
      if (rv != ZIP_OK)
        break;

#if defined STANDALONE && defined XP_WIN
      ProcessWindowsMessages();
#endif
    }

    FindFree(iterator);
  }

  return rv;
}

Here is the call graph for this function:

PRInt32 nsZipArchive::TestItem ( const nsZipItem aItem,
PRFileDesc aFd 
) [private]

Definition at line 1580 of file nsZipArchive.cpp.

{
  Bytef inbuf[ZIP_BUFLEN], outbuf[ZIP_BUFLEN], *old_next_out;
  PRUint32 size, chunk=0, inpos, crc;
  PRInt32 status = ZIP_OK;
  int zerr = Z_OK;
  z_stream zs;
  PRBool bInflating = PR_FALSE;
  PRBool bRead;
  PRBool bWrote;

  //-- param checks
  if (!aItem)
    return ZIP_ERR_PARAM;
  if (aItem->compression != STORED && aItem->compression != DEFLATED)
    return ZIP_ERR_UNSUPPORTED;

  //-- move to the start of file's data
  if (SeekToItem(aItem, aFd) != ZIP_OK)
    return ZIP_ERR_CORRUPT;

  //-- set up the inflate if DEFLATED
  if (aItem->compression == DEFLATED)
  {
    memset(&zs, 0, sizeof(zs));
    zerr = inflateInit2(&zs, -MAX_WBITS);
    if (zerr != Z_OK)
    {
      status = ZIP_ERR_GENERAL;
      goto cleanup;
    }
    else
    {
      zs.next_out = outbuf;
      zs.avail_out = ZIP_BUFLEN;
    }
    bInflating = PR_TRUE;
  }

  //-- initialize crc checksum
  crc = crc32(0L, Z_NULL, 0);

  size = aItem->size;
  inpos = 0;

  //-- read in ZIP_BUFLEN-sized chunks of item
  //-- inflating if item is DEFLATED
  while (zerr == Z_OK)
  {
    bRead = PR_FALSE;  // used to check if new data to inflate
    bWrote = PR_FALSE; // used to reset zs.next_out to outbuf
                       //   when outbuf fills up

    //-- read to inbuf
    if (aItem->compression == DEFLATED)
    {
      if (zs.avail_in == 0 && zs.total_in < size)
      {
        //-- no data to inflate yet still more in file:
        //-- read another chunk of compressed data

        inpos = zs.total_in;  // input position
        chunk = (inpos + ZIP_BUFLEN <= size) ? ZIP_BUFLEN : size - inpos;

        if (PR_Read(aFd, inbuf, chunk) != (READTYPE)chunk)
        {
          //-- unexpected end of data
          status = ZIP_ERR_CORRUPT;
          break;
        }

        zs.next_in  = inbuf;
        zs.avail_in = chunk;
        bRead = PR_TRUE;
      }

      if (zs.avail_out == 0)
      {
        //-- reuse output buffer
        zs.next_out = outbuf;
        zs.avail_out = ZIP_BUFLEN;
        bWrote = PR_TRUE; // mimic writing to disk/memory
      }
    }
    else
    {
      if (inpos < size)
      {
        //-- read a chunk in
        chunk = (inpos + ZIP_BUFLEN <= size) ? ZIP_BUFLEN : size - inpos;

        if (PR_Read(aFd, inbuf, chunk) != (READTYPE)chunk)
        {
          //-- unexpected end of data
          status = ZIP_ERR_CORRUPT;
          break;
        }

        inpos += chunk;
      }
      else
      {
        //-- finished reading STORED item
        break;
      }
    }

    //-- inflate if item is DEFLATED
    if (aItem->compression == DEFLATED)
    {
      if (bRead || bWrote)
      {
        old_next_out = zs.next_out;

        zerr = inflate(&zs, Z_PARTIAL_FLUSH);

        //-- incrementally update crc checksum
        crc = crc32(crc, (const unsigned char*)old_next_out, zs.next_out - old_next_out);
      }
      else
        zerr = Z_STREAM_END;
    }
    //-- else just use input buffer containing data from STORED item
    else
    {
      //-- incrementally update crc checksum
      crc = crc32(crc, (const unsigned char*)inbuf, chunk);
    }
  }

  //-- convert zlib error to return value
  if (status == ZIP_OK && zerr != Z_OK && zerr != Z_STREAM_END)
  {
    status = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT;
    goto cleanup;
  }

  //-- verify computed crc checksum against header info crc
  if (status == ZIP_OK && crc != aItem->crc32)
  {
    status = ZIP_ERR_CORRUPT;
  }

cleanup:
  if (bInflating)
  {
    //-- free zlib internal state
    inflateEnd(&zs);
  }

  return status;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Block size by which Arena grows.

Arena used by filelists

Definition at line 172 of file nsZipArchive.h.

cookie used to validate supposed objects passed from C code

Definition at line 169 of file nsZipArchive.h.

Definition at line 289 of file nsZipArchive.h.

Definition at line 287 of file nsZipArchive.h.


The documentation for this class was generated from the following files: