compressionlibs/ziplib/src/ezip/zipfile.cpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 
       
    17 #include <caf/content.h>
       
    18 #include <caf/data.h>
       
    19 #include <zipfile.h>
       
    20 
       
    21 // ====================================================================
       
    22 // CZipFile public exported interface
       
    23 // ====================================================================
       
    24 
       
    25 /**
       
    26 Creates a new CZipFile object using the supplied file server session and 
       
    27 a valid file handle. The caller must have sufficient rights to 
       
    28 access the content of the zipfile, if encrypted/protected.
       
    29 
       
    30 @param aFs File server session used for opening the zipfile
       
    31 @param aFile File handle to be used for accessing the zipfile
       
    32 @return CZipFile object associated with the zipfile if it succeeded
       
    33 @leave KZipArchiveError If file cannot be accessed(invalid handle, corrupt file header, etc.)
       
    34 @leave KZipFileIOError If file cannot be read
       
    35 @leave KCentralDirectoryTrailerNotFound If zip file header doesn't contain information about files inside the archive
       
    36 @leave KCentralDirectoryTrailerInvalid If the information about files inside the archive is corrupt
       
    37 @leave KMultiDiskArchivesNotSupported If zipfile is a multi disk archive
       
    38 @leave ... Any one of the system-wide error codes for other errors.
       
    39 */
       
    40 EXPORT_C CZipFile* CZipFile::NewL(RFs& aFs, RFile& aFile)
       
    41 	{
       
    42 	TFileName file;
       
    43 	aFile.Name(file);
       
    44 	CZipFile* zipFile = new(ELeave) CZipFile(aFs, file);
       
    45 	CleanupStack::PushL(zipFile);
       
    46 	zipFile->ConstructL(aFile);
       
    47 	CleanupStack::Pop(zipFile);
       
    48 	return zipFile;
       
    49 	}
       
    50 	
       
    51 /**
       
    52 Creates a new CZipFile object using the supplied file server session and 
       
    53 file name. The caller must have sufficient capabilities to access the directory. 
       
    54 The caller must also have sufficient rights to access the content of the 
       
    55 zipfile, if encrypted/protected.
       
    56 
       
    57 @param aFs File server session used for opening the zipfile
       
    58 @param aFileName Name of the zipfile 
       
    59 @return CZipFile object associated with the zipfile if it succeeded
       
    60 @leave KZipArchiveError If file cannot be accessed(invalid handle, corrupt file header, etc.)
       
    61 @leave KZipFileIOError If file cannot be read
       
    62 @leave KCentralDirectoryTrailerNotFound If zip file header doesn't contain information about files inside the archive
       
    63 @leave KCentralDirectoryTrailerInvalid If the information about files inside the archive is corrupt
       
    64 @leave KMultiDiskArchivesNotSupported If zipfile is a multi disk archive. 
       
    65 @leave ... Any one of the system-wide error codes for other errors.
       
    66 */
       
    67 EXPORT_C CZipFile* CZipFile::NewL(RFs& aFs, const TDesC& aFileName)
       
    68 	{
       
    69 	CZipFile* zipFile = new(ELeave) CZipFile(aFs, aFileName);
       
    70 	CleanupStack::PushL(zipFile);
       
    71 	zipFile->ConstructL(aFileName);
       
    72 	CleanupStack::Pop(zipFile);
       
    73 	return zipFile;
       
    74 	}
       
    75 
       
    76 /**
       
    77 Destructor
       
    78 */
       
    79 EXPORT_C CZipFile::~CZipFile()
       
    80 	{
       
    81 	DeleteMemberPointers();
       
    82 	}
       
    83 
       
    84 /** 
       
    85 @deprecated in 7.0 
       
    86 */
       
    87 EXPORT_C CZipFile::CZipFile(RFs& aFs, const TDesC& aFileName)
       
    88 	: iFileName(aFileName), iFs(aFs)
       
    89 	{
       
    90 	}
       
    91  
       
    92 /** 
       
    93 @deprecated in 7.0 
       
    94 */	
       
    95 EXPORT_C TInt CZipFile::OpenL(void)
       
    96 	{
       
    97 	if (!iMemberPointers)
       
    98 		{
       
    99 		ConstructL(iFileName);
       
   100 		}
       
   101 	return KErrNone;
       
   102 	}
       
   103 	
       
   104 /** 
       
   105 @deprecated in 7.0 
       
   106 */
       
   107 EXPORT_C void CZipFile::Close(void)
       
   108 	{
       
   109 	DeleteMemberPointers();
       
   110 	}
       
   111 
       
   112 /**
       
   113 Second phase of construction. Used by Rfile using NewL overload.
       
   114 
       
   115 @leave ... Any one of the system-wide error codes for other errors.
       
   116 */
       
   117 EXPORT_C void CZipFile::ConstructL(RFile& aFile)
       
   118 	{
       
   119 	// Use the full name derived from the session path
       
   120 	ContentAccess::CContent* content = 
       
   121 		ContentAccess::CContent::NewL(aFile);
       
   122 	CleanupStack::PushL(content);
       
   123 	iData = content->OpenContentL(ContentAccess::EPeek);
       
   124 
       
   125 	// Parent content object no longer needed because we only need data
       
   126 	CleanupStack::PopAndDestroy(content);
       
   127 
       
   128 	// Seek to the end
       
   129 	TInt length = 0;
       
   130 	User::LeaveIfError(iData->Seek(ESeekEnd, length));
       
   131 	iFileLength = length;
       
   132 
       
   133 	TInt status;
       
   134 	TUint32 offset;
       
   135 
       
   136 	if ((status = FindCentralDirectoryTrailer(offset)) != KErrNone) 
       
   137 		{
       
   138 		DeleteMemberPointers();
       
   139 		User::Leave(status);
       
   140 		}
       
   141 
       
   142 	if ((status = ReadCentralDirectoryTrailer(offset, iTrailer)) != KErrNone) 
       
   143 		{
       
   144 		DeleteMemberPointers();
       
   145 		User::Leave(status);
       
   146 		}
       
   147 
       
   148 	if (iTrailer.iStartDiskNumber != iTrailer.iDiskNumber) 
       
   149 		{
       
   150 		DeleteMemberPointers();
       
   151 		User::Leave(KMultiDiskArchivesNotSupported);
       
   152 		}
       
   153 
       
   154 	if ((iTrailer.iOffset + iTrailer.iSize) > iFileLength)
       
   155 		{
       
   156 		DeleteMemberPointers();
       
   157 	    User::Leave(KCentralDirectoryTrailerInvalid);
       
   158 		}
       
   159 
       
   160 	if (LoadMemberPointersL() != KErrNone)
       
   161 		{
       
   162 		User::Leave(KZipFileIOError);
       
   163 		}	
       
   164 	}
       
   165 
       
   166 /**
       
   167 Second phase of construction. Used by filename using NewL overload
       
   168 
       
   169 @leave ... Any one of the system-wide error codes for other errors.
       
   170 */
       
   171 EXPORT_C void CZipFile::ConstructL(const TDesC& aFileName)
       
   172 	{
       
   173 	TInt status;
       
   174 	TUint32 offset;
       
   175 	
       
   176 	TRAP(status, OpenFileL(aFileName));
       
   177 	if (status)
       
   178 		{
       
   179 		User::Leave(KZipArchiveError);
       
   180 		}
       
   181 	else
       
   182 	if ((status = FindCentralDirectoryTrailer(offset)) != KErrNone) 
       
   183 		{
       
   184 		DeleteMemberPointers();
       
   185 		User::Leave(status);
       
   186 		}
       
   187 	else 
       
   188 	if ((status = ReadCentralDirectoryTrailer(offset, iTrailer)) != KErrNone) 
       
   189 		{
       
   190 		DeleteMemberPointers();
       
   191 		User::Leave(status);
       
   192 		}
       
   193 	else 
       
   194 	if (iTrailer.iStartDiskNumber != iTrailer.iDiskNumber) 
       
   195 		{
       
   196 		DeleteMemberPointers();
       
   197 		User::Leave(KMultiDiskArchivesNotSupported);
       
   198 		}
       
   199 	else
       
   200 	if ((iTrailer.iOffset > iFileLength) ||
       
   201 	    ((iTrailer.iOffset + iTrailer.iSize) > iFileLength)) 
       
   202 		{
       
   203 		DeleteMemberPointers();
       
   204 	    User::Leave(KCentralDirectoryTrailerInvalid);
       
   205 		}
       
   206 	else
       
   207 	if (LoadMemberPointersL() != KErrNone)
       
   208 		{
       
   209 		User::Leave(KZipFileIOError);
       
   210 		}	
       
   211 	}
       
   212 
       
   213 /**
       
   214 Gets the size of the compressed data contained in the zip file in bytes
       
   215 Each CZipFile object has a compressed and uncompressed size. This method will 
       
   216 return the compressed size of a zip file.
       
   217 
       
   218 @param aSize On return, the size of the compressed data in bytes
       
   219 @return KErrNotReady If object hasn't been properly constructed
       
   220 @return KErrCASizeNotDetermined	If size could not be determined 
       
   221 @return ... Any one of the system-wide error codes for other errors.
       
   222 */
       
   223 EXPORT_C TInt CZipFile::Size(TInt& aSize) const
       
   224 {
       
   225 	TInt err = KErrNotReady;
       
   226 	if (iData)
       
   227 		{
       
   228 		TRAP(err, iData->DataSizeL(aSize));
       
   229 		}
       
   230 	return err;
       
   231 }
       
   232 
       
   233 /**
       
   234 Constructs and returns a CZipFileMember object which is used to access 
       
   235 information about a compressed file contained in the CZipFile archive. 
       
   236 The name of the file to be searched for in the zipfile is case-sensitive. 
       
   237 
       
   238 @param aName The name of the file to be searched in the zipfile 
       
   239 @return the pointer to CZipFileMember object
       
   240 @return NULL if the file doesn't exist in the zipfile
       
   241 @leave ... Any one of the system-wide error codes for other errors.
       
   242 */
       
   243 EXPORT_C CZipFileMember* CZipFile::MemberL(const TDesC& aName)
       
   244 	{
       
   245 	TLocalHeader		  header;
       
   246 	const TMemberPointer* memberPointer;
       
   247 	HBufC* localName = aName.AllocL();
       
   248 	TInt loop = 0;
       
   249 	while (loop < localName->Length())
       
   250 		{
       
   251 		if ((*localName)[loop] == '\\')
       
   252 			{
       
   253 			(localName->Des())[loop] = '/';
       
   254 			}
       
   255 		loop++;
       
   256 		}
       
   257 	
       
   258 	memberPointer = FindMemberPointer(*localName, EFalse);
       
   259 	if (memberPointer == NULL)
       
   260 		{
       
   261 		delete localName;
       
   262 		return NULL;
       
   263 		}
       
   264 	else
       
   265 	if (ReadLocalHeader(memberPointer->iLocalHeaderOffset, header) != KErrNone)
       
   266 		{
       
   267 		delete localName;
       
   268 		return NULL;
       
   269 		}
       
   270 	else
       
   271 		{
       
   272 		CleanupStack::PushL(localName);
       
   273 		CZipFileMember* thisMember = MakeMemberL(*memberPointer, header);
       
   274 		CleanupStack::PopAndDestroy();		// localName
       
   275 		return thisMember;
       
   276 		}
       
   277 	}
       
   278 
       
   279 /**
       
   280 Constructs and returns a CZipFileMember object which is used to access 
       
   281 information about a compressed file contained in the CZipFile archive. 
       
   282 The name of the file to be searched for in the zipfile is case-insensitive.
       
   283 
       
   284 @param aName The name of the file to be searched in the zipfile 
       
   285 @return A pointer to a member object of zip file
       
   286 @return NULL If the file doesn't exist in the zipfile
       
   287 @leave ... Any one of the system-wide error codes for other errors.
       
   288 */
       
   289 EXPORT_C CZipFileMember* CZipFile::CaseInsensitiveMemberL(const TDesC& aName)
       
   290 {
       
   291 	TLocalHeader		  header;
       
   292 	const TMemberPointer* memberPointer;
       
   293 	HBufC* localName = aName.AllocL();
       
   294 	TInt loop=0;
       
   295 	while (loop < localName->Length())
       
   296 		{
       
   297 		if ((*localName)[loop] == '\\')
       
   298 			{
       
   299 			(localName->Des())[loop] = '/';
       
   300 			}
       
   301 		loop++;
       
   302 		}
       
   303 	
       
   304 	memberPointer = FindMemberPointer(*localName, ETrue);
       
   305 	if (memberPointer == NULL)
       
   306 		{
       
   307 		delete localName;
       
   308 		return NULL;
       
   309 		}
       
   310 	else
       
   311 	if (ReadLocalHeader(memberPointer->iLocalHeaderOffset, header) != KErrNone)
       
   312 		{
       
   313 		delete localName;
       
   314 		return NULL;
       
   315 		}
       
   316 	else
       
   317 		{
       
   318 		CleanupStack::PushL(localName);
       
   319 		CZipFileMember* thisMember = MakeMemberL(*memberPointer, header);
       
   320 		CleanupStack::PopAndDestroy();
       
   321 		return thisMember;
       
   322 		}
       
   323 
       
   324 	}
       
   325 
       
   326 /**
       
   327 Constructs and returns a CZipFileMember object which is used to access 
       
   328 information about a compressed file contained in the CZipFile archive. 
       
   329 An exact match for the filename is searched for first. If a match is not found, 
       
   330 a case-insensitive search is performed. If both filenames exist in the archive, 
       
   331 the case-sensitive match will be returned.
       
   332  
       
   333 @param aName The name of the file to be searched in the zipfile 
       
   334 @return A pointer to a member object of zip file
       
   335 @return NULL If the file doesn't exist in the zipfile
       
   336 @leave ... Any one of the system-wide error codes for other errors.
       
   337 */
       
   338 EXPORT_C CZipFileMember* CZipFile::CaseSensitiveOrCaseInsensitiveMemberL(const TDesC& aName)
       
   339 {
       
   340 	CZipFileMember* member;
       
   341 	member = MemberL(aName);
       
   342 	if (member)
       
   343 		{
       
   344 		return member;
       
   345 		}
       
   346 	else
       
   347 		{
       
   348 		return CaseInsensitiveMemberL(aName);
       
   349 		}
       
   350 }
       
   351 
       
   352 /**
       
   353 Creates and returns the input stream for a file in the archive. Only files 
       
   354 compressed with Stored or Deflated compression methods are supported.
       
   355 
       
   356 @param aMember The compressed file in the archive
       
   357 @param aStream On return, the stream to be used for reading the contents of the compressed file.  The caller owns this object and is responsible for deleting it.
       
   358 @return KErrNone if successful
       
   359 @return KCompressionMethodNotSupported if compression format unsupported 
       
   360 @return ... Any one of the system-wide error codes for other errors.
       
   361 @leave ... Any one of the system-wide error codes for other errors.
       
   362 */
       
   363 EXPORT_C TInt CZipFile::GetInputStreamL(const CZipFileMember* aMember, RZipFileMemberReaderStream*& aStream)
       
   364 	{
       
   365 	TUint32 compressionMethod;
       
   366 	
       
   367 	compressionMethod = aMember->iCompressionMethod;
       
   368 	if ((compressionMethod != EStored) && (compressionMethod != EDeflated)) 
       
   369 	    {
       
   370 	    return KCompressionMethodNotSupported;
       
   371 	    }
       
   372 	aStream = RZipFileMemberReaderStream::NewL(
       
   373 								*this,
       
   374 							   aMember->iDataOffset,
       
   375 							   aMember->iCompressedSize,
       
   376 							   aMember->iUncompressedSize,
       
   377 							   compressionMethod);
       
   378 	return KErrNone;
       
   379 	}
       
   380 	
       
   381 
       
   382 
       
   383 /**
       
   384 Gets the iterator used for iterating through the files contained in the ZIP 
       
   385 file. It is the caller's responsibility to release the iterator when finsihed.
       
   386  
       
   387 @return Pointer to a newly allocated CZipFileMemberIterator object
       
   388 @leave ... Any one of the system-wide error codes for other errors.
       
   389 */
       
   390 EXPORT_C CZipFileMemberIterator* CZipFile::GetMembersL()
       
   391 	{
       
   392 	return new (ELeave) CZipFileMemberIterator(this);
       
   393 	}
       
   394 	
       
   395 
       
   396 
       
   397 // Implementation
       
   398 
       
   399 /*
       
   400  * Find the 'end of central directory record'. This is at the 'end' of
       
   401  * the file, but since it is not a fixed length structure, we have to
       
   402  * hunt for it.
       
   403  *
       
   404  * We try assuming that the variable length section of the record is
       
   405  * empty, which usually appears to be the case.
       
   406  *
       
   407  * If this does not work we resort to 'walking backwards' through the
       
   408  * file looking for the signature bytes.
       
   409  *
       
   410  */
       
   411  
       
   412 TInt CZipFile::FindCentralDirectoryTrailer(TUint32& offset)
       
   413 {
       
   414 	TBuf8<KSignatureLength> signature;
       
   415 		
       
   416     if (iFileLength <= KCentralDirectoryTrailerFixedLength) 
       
   417 		{
       
   418     	return KZipArchiveError;
       
   419 		}
       
   420     // Try the obvious place first.Assuming that the comment (variable 
       
   421     // length section) is empty,try to find the signature at the offset.
       
   422     offset = iFileLength - KCentralDirectoryTrailerFixedLength;
       
   423 	if (Seek(offset) != KErrNone) 
       
   424 		{
       
   425     	return KZipFileIOError;
       
   426 		}
       
   427 	TInt err = iData->Read(signature);
       
   428 
       
   429 	if ( err != KErrNone) 
       
   430 		{
       
   431 		return KZipFileIOError;
       
   432 		}
       
   433 
       
   434 	if ((signature[0] == 0x50) && 
       
   435 		(signature[1] == 0x4b) &&
       
   436 		(signature[2] == 0x05) &&
       
   437 		(signature[3] == 0x06)) 
       
   438 		{
       
   439 		return KErrNone;
       
   440 		}
       
   441 	else 
       
   442 		{
       
   443 		// There must be some comments, hence the central directory 
       
   444 		// record > 22 bytes.
       
   445 		// This is a slow but fairly obvious way of searching 
       
   446 		// backwards through the file starting from the offset.
       
   447 		TUint EndOfTrailerSearch = 0; //Upto beginning of File
       
   448 
       
   449 		if(iFileLength > KMaxTrailerSearchLength+KCentralDirectoryTrailerFixedLength)
       
   450 			EndOfTrailerSearch = offset - KMaxTrailerSearchLength; //Upto Last 64K+22 bytes
       
   451 
       
   452 		while (offset >= EndOfTrailerSearch) 
       
   453 			{
       
   454 			if (Seek(offset) != KErrNone)
       
   455 				{
       
   456 				return KZipFileIOError;
       
   457 				}
       
   458 			if (iData->Read(signature) != KErrNone)
       
   459 				{
       
   460 				return KZipFileIOError;
       
   461 				}
       
   462 			if ((signature[0] == 0x50) && 
       
   463 				(signature[1] == 0x4b) &&
       
   464 				(signature[2] == 0x05) &&
       
   465 				(signature[3] == 0x06)) 
       
   466 				{			
       
   467 				return KErrNone;
       
   468 				}
       
   469 			--offset;
       
   470 			}
       
   471 		return KCentralDirectoryTrailerNotFound;
       
   472 		}	
       
   473 	}
       
   474 	
       
   475 TInt CZipFile::ReadCentralDirectoryTrailer(TUint32 offset, struct TCentralDirectoryTrailer& r )
       
   476 {
       
   477     // Skip the signature		    
       
   478     if (Seek(offset + KSignatureLength) != KErrNone) 
       
   479     	{
       
   480     	return KZipFileIOError;
       
   481     	} 
       
   482 	else
       
   483 	if (Read(r.iDiskNumber) != KErrNone) 
       
   484 		{
       
   485 		return KZipFileIOError;
       
   486 		}
       
   487 	else
       
   488 	if (Read(r.iStartDiskNumber)!= KErrNone) 
       
   489 		{
       
   490 		return KZipFileIOError;
       
   491 		}
       
   492 	else
       
   493 	if (Read(r.iLocalEntryCount) != KErrNone) 
       
   494 		{
       
   495 		return KZipFileIOError;
       
   496 		}
       
   497 	else
       
   498 	if (Read(r.iTotalEntryCount) != KErrNone) 
       
   499 		{
       
   500 		return KZipFileIOError;
       
   501 		}
       
   502 	else
       
   503 	if (Read(r.iSize) != KErrNone) 
       
   504 		{
       
   505 		return KZipFileIOError;
       
   506 		}
       
   507 	else
       
   508 	if (Read(r.iOffset) != KErrNone) 
       
   509 		{
       
   510 		return KZipFileIOError;
       
   511 		}
       
   512 	else
       
   513 		{
       
   514 		return KErrNone;
       
   515 		}
       
   516 }
       
   517 
       
   518 TInt CZipFile::LoadMemberPointersL(void)
       
   519 	{
       
   520 	TCentralDirectoryHeader	header;
       
   521 	TUint32					i;
       
   522 	TUint32					memberPointerCount;
       
   523 		
       
   524 	if (Seek(iTrailer.iOffset) != KErrNone)
       
   525 		{
       
   526 		return KZipFileIOError;
       
   527 		}
       
   528 	memberPointerCount = iTrailer.iTotalEntryCount;
       
   529 	iMemberPointers = new (ELeave) TMemberPointer[memberPointerCount];
       
   530 	for (i = 0; i < memberPointerCount; i++)
       
   531 		{
       
   532 		iMemberPointers[i].iName = NULL;
       
   533 		}
       
   534 	CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewL();
       
   535 	CleanupStack::PushL(converter);
       
   536 	TInt converterState = CCnvCharacterSetConverter::KStateDefault;
       
   537 	for (i = 0; i < memberPointerCount; i++)
       
   538 		{
       
   539 		if (ReadCentralDirectoryHeaderL(header, iMemberPointers[i], converter, converterState) != KErrNone)
       
   540 			{
       
   541 			return KZipFileError;
       
   542 			}
       
   543 		}
       
   544 	CleanupStack::PopAndDestroy(converter);
       
   545 	return KErrNone;
       
   546 	}
       
   547 	
       
   548 static void ConvertFileNameToUnicodeL(
       
   549 						TDes16& aUnicode,
       
   550 						const TDesC8& aForeign,
       
   551 						const TUint16& aMadeBy,
       
   552 						CCnvCharacterSetConverter* aConverter,
       
   553 						TInt aConverterState,
       
   554 						RFs aFs)
       
   555 // Have to decide whether filename encoding is CP850 or CP1252. According to tec support
       
   556 // at WinZip, if 'madeby' is set to DOS(0) then the encoding is CP850 and if it's set to
       
   557 // NTFS (11) then it's CP1252.  However, if the MS Compressed Folders program was used
       
   558 // to zip, then madeby is always set to NTFS and the encoding is always CP850 - the exact
       
   559 // opposite. Because of this confusion, I have written a very basic decision algorithm
       
   560 // based on the premise that filenames are likely to use alphabet-style extended
       
   561 // characters (rather than box edges or punctuation etc.)
       
   562 	{
       
   563 	TInt len = aForeign.Length();
       
   564 	TInt ANSIpoints = 0;
       
   565 	TInt OEMpoints = 0;
       
   566 	for (TInt i=0; i<len; i++)
       
   567 		{
       
   568 		if (aForeign[i] >= 128 && aForeign[i] <= 165)
       
   569 			OEMpoints ++;
       
   570 		if (aForeign[i] >= 192 && aForeign[i] <= 255)
       
   571 			ANSIpoints ++;
       
   572 		}
       
   573 	if (ANSIpoints == OEMpoints)
       
   574 		{
       
   575 		if (aMadeBy>>8) //only interested in the upper byte
       
   576 			ANSIpoints ++;
       
   577 		else
       
   578 			OEMpoints ++;
       
   579 		}
       
   580 	TInt unconvertibleChars = 0;
       
   581 
       
   582 	CCnvCharacterSetConverter::TAvailability availabilty = CCnvCharacterSetConverter::EAvailable;
       
   583 	if (ANSIpoints > OEMpoints)
       
   584 		{
       
   585 		// It's probably ANSI (CP1252)
       
   586 		availabilty = aConverter->PrepareToConvertToOrFromL(KCharacterSetIdentifierCodePage1252,aFs);
       
   587 		aConverter->ConvertToUnicode(aUnicode, aForeign, aConverterState, unconvertibleChars);
       
   588 		
       
   589 		}
       
   590 	if (OEMpoints > ANSIpoints || unconvertibleChars)
       
   591 		{
       
   592 		// It's definitely OEM (CP850)
       
   593  		availabilty = aConverter->PrepareToConvertToOrFromL(KCharacterSetIdentifierCP850,aFs);
       
   594 		if(availabilty != CCnvCharacterSetConverter::EAvailable )
       
   595 			{
       
   596 			//if cp850 plugin is not available, use cp1252
       
   597 			availabilty = aConverter->PrepareToConvertToOrFromL(KCharacterSetIdentifierCodePage1252, aFs);
       
   598 			if(availabilty != CCnvCharacterSetConverter::EAvailable)
       
   599 				User::Leave (KErrNotSupported);
       
   600 			}
       
   601 		
       
   602 		aConverter->ConvertToUnicode(aUnicode, aForeign, aConverterState);
       
   603 		
       
   604 		}
       
   605 	}
       
   606 
       
   607 TInt CZipFile::ReadCentralDirectoryHeaderL(
       
   608 		 		   TCentralDirectoryHeader& aHeader, 
       
   609 		 		   TMemberPointer&          aMemberPointer,
       
   610 				   CCnvCharacterSetConverter* aConverter,
       
   611 				   TInt aConverterState)
       
   612 /*
       
   613 As this function might be called many times and the request will 
       
   614 eventually be translated to calls to server to read the data, 
       
   615 so performance is the major issue. Try to minimize calls to server.
       
   616 Read data in a chunk rather than member-by-member.
       
   617 */
       
   618 	{
       
   619 	TByte tmpHeader[KCentralDirectoryHeaderFixedLength];
       
   620  
       
   621 	if (Read(tmpHeader,KCentralDirectoryHeaderFixedLength) != KErrNone)
       
   622 		{
       
   623 		return KZipFileIOError;
       
   624 		}
       
   625 
       
   626 	Mem::Copy(&aHeader.iSignature, &tmpHeader[0], 4);
       
   627 
       
   628 	if (aHeader.iSignature != KCentralDirectoryHeaderSignature)
       
   629 		{
       
   630 		return KZipFileIOError;
       
   631 		}
       
   632 
       
   633 	Mem::Copy(&aHeader.iMadeBy, &tmpHeader[4], 2);
       
   634 	Mem::Copy(&aHeader.iRequired, &tmpHeader[6], 2);
       
   635 	Mem::Copy(&aHeader.iFlags, &tmpHeader[8], 2);
       
   636 	Mem::Copy(&aHeader.iCompressionMethod, &tmpHeader[10], 2);
       
   637 	Mem::Copy(&aHeader.iLastModifiedFileTime, &tmpHeader[12], 2);
       
   638 	Mem::Copy(&aHeader.iLastModifiedFileDate, &tmpHeader[14], 2);
       
   639 	Mem::Copy(&aHeader.iCRC32, &tmpHeader[16], 4);
       
   640 	Mem::Copy(&aHeader.iCompressedSize, &tmpHeader[20], 4);
       
   641 	Mem::Copy(&aHeader.iUncompressedSize, &tmpHeader[24], 4);
       
   642 	Mem::Copy(&aHeader.iFileNameLength, &tmpHeader[28], 2);
       
   643 	Mem::Copy(&aHeader.iExtraFieldLength, &tmpHeader[30], 2);
       
   644 	Mem::Copy(&aHeader.iFileCommentLength, &tmpHeader[32], 2);
       
   645 	Mem::Copy(&aHeader.iDiskNumberStart, &tmpHeader[34], 2);
       
   646 	Mem::Copy(&aHeader.iInternalFileAttributes, &tmpHeader[36], 2);
       
   647 	Mem::Copy(&aHeader.iExternalFileAttributes, &tmpHeader[38], 4);
       
   648 	Mem::Copy(&aHeader.iLocalHeaderOffset, &tmpHeader[42], 4);
       
   649 
       
   650 	aMemberPointer.iCRC32             = aHeader.iCRC32;
       
   651 	aMemberPointer.iCompressedSize    = aHeader.iCompressedSize;
       
   652 	aMemberPointer.iUncompressedSize  = aHeader.iUncompressedSize;
       
   653 	aMemberPointer.iLocalHeaderOffset = aHeader.iLocalHeaderOffset;
       
   654     aMemberPointer.iName = new(ELeave) TFileName;
       
   655 	
       
   656 	TBuf8<KMaxFileName> input;
       
   657 	if (iData->Read(input, aHeader.iFileNameLength) != KErrNone)
       
   658 		{
       
   659 		return KZipFileIOError;
       
   660 		}
       
   661 	ConvertFileNameToUnicodeL(*aMemberPointer.iName, input, aHeader.iMadeBy, aConverter, aConverterState, iFs);
       
   662 	
       
   663     // Ignore the remaining fields
       
   664 	TInt pos;
       
   665 
       
   666 	pos = aHeader.iExtraFieldLength;	
       
   667 	if (pos != 0)
       
   668 		{
       
   669 		// Don't pass aHeader.iExtraFieldLength in place of pos
       
   670 		// as the below function will update the content of that variable.
       
   671 		// In this case, the function is used to ignore the data
       
   672 		// by just moving the current file pointer location.
       
   673 		if (iData->Seek(ESeekCurrent, pos) != KErrNone) 
       
   674 			{
       
   675 			return KZipFileIOError;
       
   676 			}
       
   677 		}
       
   678 
       
   679 	pos = aHeader.iFileCommentLength;
       
   680 	if (pos != 0)
       
   681 		{
       
   682 		// Don't pass aHeader.iFileCommentLength in place of pos
       
   683 		// as the below function will update the content of that variable.
       
   684 		// In this case, the function is used to ignore the data
       
   685 		// by just moving the current file pointer location.
       
   686 		if (iData->Seek(ESeekCurrent, pos) != KErrNone) 
       
   687 			{
       
   688 			return KZipFileIOError;
       
   689 			}
       
   690 		}
       
   691 
       
   692   	return  KErrNone;
       
   693 }
       
   694 
       
   695 TInt CZipFile::ReadLocalHeader(TUint32 aOffset, TLocalHeader& aHeader)
       
   696 /*
       
   697 As this function might be called many times and the request will 
       
   698 eventually be translated to calls to server to read the data, 
       
   699 so performance is the major issue. Try to minimize calls to server.
       
   700 Read data in a chunk rather than member-by-member.
       
   701 */
       
   702 	{
       
   703 	TByte tmpHeader[KLocalHeaderFixedLength];
       
   704 
       
   705 	if (Seek(aOffset) != KErrNone)
       
   706 		{
       
   707 		return KZipFileIOError;
       
   708 		}
       
   709 	if (Read(tmpHeader,KLocalHeaderFixedLength) != KErrNone)
       
   710 		{
       
   711 		return KZipFileIOError;
       
   712 		}
       
   713 	Mem::Copy(&aHeader.iSignature, &tmpHeader[0], 4);
       
   714 
       
   715 	if (aHeader.iSignature != KLocalHeaderSignature)
       
   716 		{
       
   717 		return KLocalHeaderSignatureInvalid;
       
   718 		}
       
   719 
       
   720 	Mem::Copy(&aHeader.iVersionNeeded, &tmpHeader[4], 2);
       
   721 	Mem::Copy(&aHeader.iFlags, &tmpHeader[6], 2);
       
   722 	Mem::Copy(&aHeader.iCompressionMethod, &tmpHeader[8], 2);
       
   723 	Mem::Copy(&aHeader.iLastModifiedFileTime, &tmpHeader[10], 2);
       
   724 	Mem::Copy(&aHeader.iLastModifiedFileDate, &tmpHeader[12], 2);
       
   725 	Mem::Copy(&aHeader.iCRC32, &tmpHeader[14], 4);
       
   726 	Mem::Copy(&aHeader.iCompressedSize, &tmpHeader[18], 4);
       
   727 	Mem::Copy(&aHeader.iUncompressedSize, &tmpHeader[22], 4);
       
   728 	Mem::Copy(&aHeader.iFileNameLength, &tmpHeader[26], 2);
       
   729 	Mem::Copy(&aHeader.iExtraFieldLength, &tmpHeader[28], 2);
       
   730 
       
   731 	return  KErrNone;
       
   732 	}
       
   733 	
       
   734 const CZipFile::TMemberPointer* CZipFile::FindMemberPointer(const TDesC& aName, TBool aCaseInsensitive)
       
   735 	{
       
   736 	for (TUint32 i = 0; i < iTrailer.iTotalEntryCount; i++)
       
   737 		{
       
   738 		if (aCaseInsensitive && (!aName.CompareF(*iMemberPointers[i].iName)))
       
   739 			{
       
   740 			return iMemberPointers + i;
       
   741 			}
       
   742 		else if (aName == *iMemberPointers[i].iName)
       
   743 			{
       
   744 			return iMemberPointers + i;
       
   745 			}
       
   746 		}
       
   747 	return NULL;
       
   748 	}
       
   749 
       
   750 RZipFileMemberReaderStream* CZipFile::MakeInputStreamL(
       
   751 							TUint32 aDataOffset, 
       
   752 							TUint32 aCompressedSize, 
       
   753 							TUint32 aUncompressedSize, 
       
   754 							TUint32 aCompressionMethod)
       
   755 	{
       
   756 	return RZipFileMemberReaderStream::NewL(
       
   757 						    *this,
       
   758 							aDataOffset,
       
   759 							aCompressedSize,
       
   760 							aUncompressedSize, 
       
   761 							aCompressionMethod);
       
   762 	}
       
   763 
       
   764 CZipFileMember* CZipFile::MakeMemberL(TInt aMemberIndex)
       
   765 	{
       
   766 	TLocalHeader    header;
       
   767 	TMemberPointer*	memberPointer;
       
   768 	
       
   769 	if (aMemberIndex >= iTrailer.iTotalEntryCount)
       
   770 		{
       
   771 		return NULL;
       
   772 		}
       
   773 	memberPointer = iMemberPointers + aMemberIndex;
       
   774 	if (ReadLocalHeader(memberPointer->iLocalHeaderOffset, header) != KErrNone)
       
   775 		{
       
   776 		return NULL;
       
   777 		}
       
   778 	else
       
   779 		{
       
   780 		return MakeMemberL(*memberPointer, header);
       
   781 		}
       
   782 	}
       
   783 	
       
   784 CZipFileMember* CZipFile::MakeMemberL(
       
   785                               const TMemberPointer& aMemberPointer, 
       
   786 			                  const TLocalHeader&   aHeader)
       
   787 	{
       
   788 	CZipFileMember* member;
       
   789 	
       
   790 	member = new (ELeave) CZipFileMember;
       
   791 	CleanupStack::PushL(member);
       
   792 	member->iCRC32 = aMemberPointer.iCRC32;
       
   793 	member->iCompressedSize = aMemberPointer.iCompressedSize;
       
   794 	member->iCompressionMethod = aHeader.iCompressionMethod;
       
   795 	member->iName = new (ELeave) TFileName(*aMemberPointer.iName);
       
   796 	TInt loop=0;
       
   797 	while (loop < member->iName->Length())
       
   798 		{
       
   799 		if ((*member->iName)[loop] == '/')
       
   800 			{
       
   801 			(*member->iName)[loop] = '\\';
       
   802 			}
       
   803 		loop++;
       
   804 		}
       
   805 	member->iUncompressedSize = aMemberPointer.iUncompressedSize;
       
   806 	member->iDataOffset = aMemberPointer.iLocalHeaderOffset + 
       
   807 		                  KLocalHeaderFixedLength + 
       
   808 						  aHeader.iFileNameLength + 
       
   809 						  aHeader.iExtraFieldLength;
       
   810 	CleanupStack::Pop();
       
   811 	return member;
       
   812 	}
       
   813 
       
   814 void CZipFile::DeleteMemberPointers()
       
   815 	{
       
   816 	if (iMemberPointers)
       
   817 		{
       
   818 		for (TUint32 i = 0; i < iTrailer.iTotalEntryCount; i++)
       
   819 			{
       
   820 			delete iMemberPointers[i].iName;
       
   821 			}
       
   822 		delete[] iMemberPointers;
       
   823 		iMemberPointers = 0;
       
   824 		}
       
   825 
       
   826 	delete iData;
       
   827 	iData = NULL;
       
   828 	return;
       
   829 	}
       
   830 
       
   831 void CZipFile::OpenFileL(const TDesC& aFileName)
       
   832 	{
       
   833 	// We need to look at the session path of the filesystem passed
       
   834 	// in to derive the fullpath of the file to open
       
   835 	HBufC* sessionPath = HBufC::NewLC(KMaxFileName);
       
   836 	TPtr ptr(sessionPath->Des());
       
   837 	User::LeaveIfError(iFs.SessionPath(ptr));
       
   838 	TParse parse;
       
   839 	User::LeaveIfError(parse.Set(aFileName, sessionPath, NULL));
       
   840 	
       
   841 	// Use the full name derived from the session path
       
   842 	ContentAccess::CContent* content = 
       
   843 		ContentAccess::CContent::NewL(parse.FullName());
       
   844 	CleanupStack::PushL(content);
       
   845 	iData = content->OpenContentL(ContentAccess::EPeek);
       
   846 
       
   847 	// Parent content object no longer needed because we only need data
       
   848 	CleanupStack::PopAndDestroy(content);
       
   849 
       
   850 	// Seek to the end
       
   851 	TInt length = 0;
       
   852 	User::LeaveIfError(iData->Seek(ESeekEnd, length));
       
   853 	iFileLength = length;
       
   854 	CleanupStack::PopAndDestroy(sessionPath);
       
   855 	}
       
   856 
       
   857 TInt CZipFile::Read(TUint16& aUs)
       
   858 	{
       
   859 	TPckgBuf<TUint16> temp(aUs);
       
   860 	
       
   861 	if (iData->Read(temp) != KErrNone)
       
   862 		{
       
   863 		return KZipFileIOError;
       
   864 		}
       
   865 	
       
   866 	aUs=temp();
       
   867 	return KErrNone;
       
   868 	}
       
   869 	
       
   870 TInt CZipFile::Read(TUint32& aUl)
       
   871 	{
       
   872 	TPckgBuf<TUint32> temp;
       
   873 	
       
   874 	if (iData->Read(temp) != KErrNone)
       
   875 		{
       
   876 		return KZipFileIOError;
       
   877 		}
       
   878 	aUl=temp();
       
   879 	return KErrNone;
       
   880 	}
       
   881 
       
   882 TInt CZipFile::Read(TByte* aBytes, TUint32 aLength)
       
   883 
       
   884 	{
       
   885 	TPtr8 ptr(aBytes, aLength);
       
   886 	if(iData->Read(ptr, aLength))
       
   887 		{
       
   888 		return KZipFileIOError;
       
   889 		}
       
   890 	else
       
   891 		{
       
   892 		return KErrNone;
       
   893 		}
       
   894 	}
       
   895 	
       
   896 TInt CZipFile::Seek(TInt aOffset)
       
   897 	{
       
   898 	if (iData->Seek(ESeekStart, aOffset) < 0) 
       
   899 		{
       
   900 		return KZipFileIOError;
       
   901 		}
       
   902 	else
       
   903 		{
       
   904 		return KErrNone;
       
   905 		}
       
   906 	}
       
   907