phonebookengines_old/contactsmodel/cntmodel/src/CCntPackager.cpp
changeset 40 b46a585f6909
equal deleted inserted replaced
37:fd64c38c277d 40:b46a585f6909
       
     1 // Copyright (c) 2005-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  @file
       
    18  @internalComponent
       
    19  @released
       
    20 */
       
    21 
       
    22 
       
    23 #include <cntitem.h>
       
    24 #include <cntfilt.h>
       
    25 #include <s32mem.h>
       
    26 #include "CCntPackager.h"
       
    27 #include <cntviewbase.h>
       
    28 
       
    29 
       
    30 const TInt KGranularityRank = 8; //2^8 = 256 bytes
       
    31 const TInt KDefaultPackagerSize = 3514; //Observed Techview Golden template size.
       
    32 
       
    33 
       
    34 /**
       
    35 First phase constructor.
       
    36 */ 
       
    37 CCntPackager::CCntPackager()
       
    38 	: transPtr(NULL,NULL,NULL), recPtr(NULL,NULL,NULL)
       
    39  	{
       
    40  	}
       
    41 
       
    42 
       
    43 /**
       
    44 Second phase constructor.
       
    45 
       
    46 Allocate buffer used to hold packed objects.  Initializes iMaxBufferSize and
       
    47 iBuffer, setting the latter's granularity.
       
    48 */
       
    49 void CCntPackager::ConstructL()
       
    50 	{	
       
    51 	iBuffer = CBufFlat::NewL(1 << KGranularityRank);
       
    52 	iMaxBufferSize = KDefaultPackagerSize;
       
    53 	} 	
       
    54 
       
    55 
       
    56 /**
       
    57 The destructor frees all resources owned by the packager, prior to its
       
    58 destruction. 
       
    59 */
       
    60 EXPORT_C CCntPackager::~CCntPackager()
       
    61 	{
       
    62 	delete iBuffer;	
       
    63 	}
       
    64 
       
    65 	
       
    66 /**
       
    67 Allocates and constructs a new Packager. 
       
    68 
       
    69 @return Pointer to the new CCntPackager object. 
       
    70 */
       
    71 EXPORT_C CCntPackager* CCntPackager::NewL()
       
    72 	{
       
    73 	CCntPackager* packager=new(ELeave) CCntPackager;	
       
    74 	CleanupStack::PushL(packager);
       
    75 	packager->ConstructL();
       
    76 	CleanupStack::Pop(packager);
       
    77 	return packager;
       
    78 	}
       
    79 
       
    80 
       
    81 /** 
       
    82 Clears iBuffer.  Calls CBufFlat's Reset(), deletes data and compresses the
       
    83 buffer. 
       
    84 */
       
    85 EXPORT_C void CCntPackager::Clear()
       
    86 	{ 
       
    87 	iBuffer->Reset();	
       
    88 	}
       
    89 
       
    90 	
       
    91 /**
       
    92 Clears iBuffer and resets pointer.  Does not free any memory.
       
    93 */
       
    94 void CCntPackager::ResetPointer()
       
    95 	{
       
    96 	TInt bufferSize = iBuffer->Size();
       
    97 	if(bufferSize)
       
    98 		{
       
    99 		iBuffer->Delete(0,bufferSize);
       
   100 		}
       
   101 	}			
       
   102 
       
   103 	
       
   104 /**
       
   105 Checks if iBuffer is large enough to read the descriptor held in the message,
       
   106 expanding it if necessary.  The data contained in the descriptor is then from
       
   107 the message into the Packager's internal buffer.
       
   108 
       
   109 @param aMessage The message containing descriptor to read. 
       
   110 @param aMessageSlot The message slot containing the descriptor.
       
   111 */
       
   112 EXPORT_C void CCntPackager::SetBufferFromMessageL(const RMessage2& aMessage, TUint aMessageSlot)
       
   113 	{ 
       
   114 	TInt bufflen = aMessage.GetDesLengthL(aMessageSlot);
       
   115 	if (iBuffer->Size() < bufflen)
       
   116 		{
       
   117 		iBuffer->ExpandL(0,bufflen - iBuffer->Size());	
       
   118 		}
       
   119 	
       
   120 	TPtr8 bufferPtr = iBuffer->Ptr(0);
       
   121 	aMessage.ReadL(aMessageSlot, bufferPtr);
       
   122 	}				
       
   123 
       
   124 
       
   125 /** 
       
   126 Returns descriptor pointing to the buffer with serialised object.  This
       
   127 descriptor should be used as one of the IPC arguments when making an IPC call.
       
   128 
       
   129 @return Descriptor pointing to the buffer with serialised object.
       
   130 */
       
   131 EXPORT_C const TDesC8& CCntPackager::GetTransmittingBuffer() const
       
   132 	{
       
   133 	transPtr.Set(iBuffer->Ptr(0));
       
   134 	return transPtr;	
       
   135 	}
       
   136 
       
   137 
       
   138 /** 
       
   139 Returns descriptor pointing to the buffer allocated in order to receive a binary
       
   140 object from the Server. 
       
   141 
       
   142 The aSize parameter specifies the size of the receiving buffer.  If this
       
   143 parameter is ommited then the Packager's buffer will be initialised to the
       
   144 stored default size (kept in the iMaxBufferSize member variable).
       
   145 
       
   146 @param aSize The desired size of the receiving buffer.
       
   147 
       
   148 @return Descriptor pointing to the buffer receiving an object from the Server.
       
   149 */
       
   150 EXPORT_C TDes8& CCntPackager::GetReceivingBufferL(TInt aSize)
       
   151 	{
       
   152 	if(aSize > iBuffer->Size())
       
   153 		{
       
   154 		// Find next divisable by granularity size value.
       
   155 		(aSize >>= KGranularityRank)++;
       
   156 		iMaxBufferSize = aSize <<= 8;
       
   157 
       
   158 		iBuffer->ResizeL(iMaxBufferSize);
       
   159 		}
       
   160 	else if(!aSize && iBuffer->Size() < iMaxBufferSize)
       
   161 		{
       
   162 		// Use the stored default size.
       
   163 		iBuffer->ResizeL(iMaxBufferSize);
       
   164 		}
       
   165 	
       
   166 	// The location of the whole buffer may have changed, because reallocation
       
   167 	// may have taken place.  Update both buffer pointers.
       
   168 	transPtr.Set(iBuffer->Ptr(0)); 
       
   169 	recPtr.Set(iBuffer->Ptr(0));
       
   170 
       
   171 	return recPtr;	
       
   172 	}
       
   173 
       
   174 
       
   175 /** 
       
   176 Packs a CContactItem object. 
       
   177 
       
   178 @param aItem The contact item to be packed.
       
   179 
       
   180 @return Pointer to iBuffer. 
       
   181 */
       
   182 EXPORT_C TPtr8 CCntPackager::PackL(const CContactItem& aItem)
       
   183 	{ 	
       
   184 	ResetPointer();
       
   185 	RBufWriteStream writeStream;
       
   186 	writeStream.Open(*iBuffer);
       
   187 
       
   188 	aItem.ExternalizeL(writeStream);	
       
   189 
       
   190 	writeStream.CommitL();
       
   191 	writeStream.Close();
       
   192 
       
   193 	return iBuffer->Ptr(0);
       
   194 	}
       
   195 
       
   196 
       
   197 /**
       
   198 Packs a CContactItem object. 
       
   199 
       
   200 @param aItem The contact item to be packed.
       
   201 @param aSize The size of the packed contact item.
       
   202 
       
   203 @return Pointer to iBuffer. 
       
   204 */	
       
   205 EXPORT_C TPtr8 CCntPackager::PackL(const CContactItem& aItem, TInt& aSize) 
       
   206 	{ 	
       
   207 	TPtr8 packaged = PackL(aItem);
       
   208 	aSize = iBuffer->Ptr(0).Size();
       
   209 	return packaged;
       
   210 	}	
       
   211 
       
   212 
       
   213 /**
       
   214 Packs a CContentType object. 
       
   215 
       
   216 @param aItem The content type to be packed.
       
   217 
       
   218 @return Pointer to iBuffer. 
       
   219 */	
       
   220 EXPORT_C TPtr8 CCntPackager::PackL(const CContentType& aItem) 
       
   221 	{ 	
       
   222 	ResetPointer();
       
   223 	RBufWriteStream writeStream;
       
   224 	writeStream.Open(*iBuffer);
       
   225 
       
   226 	aItem.ExternalizeL(writeStream);
       
   227 
       
   228 	writeStream.CommitL();
       
   229 	writeStream.Close(); 
       
   230 
       
   231 	return iBuffer->Ptr(0);
       
   232 	}
       
   233 
       
   234 	
       
   235 /**
       
   236 Packs a CContactTextDef object. 
       
   237 
       
   238 @param aItem The contact textdef to be packed.
       
   239 
       
   240 @return Pointer to iBuffer. 
       
   241 */
       
   242 EXPORT_C TPtr8 CCntPackager::PackL(const CContactTextDef& aItem)
       
   243 	{
       
   244 	ResetPointer();
       
   245 	RBufWriteStream writeStream;
       
   246 	writeStream.Open(*iBuffer);
       
   247 
       
   248 	aItem.ExternalizeL(writeStream);
       
   249 
       
   250 	writeStream.CommitL();
       
   251 	writeStream.Close();
       
   252 
       
   253 	return iBuffer->Ptr(0);
       
   254 	}		
       
   255 
       
   256 
       
   257 /**
       
   258 Packs a CContactItemViewDef object. 
       
   259 
       
   260 @param aItem The contact item view def to be packed.
       
   261 
       
   262 @return Pointer to iBuffer. 
       
   263 */
       
   264 EXPORT_C TPtr8 CCntPackager::PackL(const CContactItemViewDef& aItem)
       
   265 	{ 
       
   266 	ResetPointer();
       
   267 	RBufWriteStream writeStream;
       
   268 	writeStream.Open(*iBuffer);
       
   269 	
       
   270 	// Externalize aItem.Use() and aItem.Mode() so we can call the constructor
       
   271 	// for CContactItemViewDef with them as parameters when unpacking/
       
   272 	// internalizing later.
       
   273 	writeStream.WriteInt32L(aItem.Use());
       
   274 	writeStream.WriteInt32L(aItem.Mode());
       
   275 	aItem.ExternalizeL(writeStream);
       
   276 
       
   277 	writeStream.CommitL();
       
   278 	writeStream.Close();
       
   279 
       
   280 	return iBuffer->Ptr(0);
       
   281 	}	
       
   282 
       
   283 	
       
   284 /**
       
   285 Packs a CContactViewDef object. 
       
   286 
       
   287 @param aItem The contact view def to be packed.
       
   288 
       
   289 @return Pointer to iBuffer. 
       
   290 */
       
   291 EXPORT_C TPtr8 CCntPackager::PackL(const CContactViewDef& aItem) 
       
   292 	{ 
       
   293 	ResetPointer();
       
   294 	RBufWriteStream writeStream;
       
   295 	writeStream.Open(*iBuffer);
       
   296 
       
   297 	// Externalize aItem.Use() and aItem.Mode() so we can call the constructor
       
   298 	// for CContactItemViewDef with them as parameters when unpacking/
       
   299 	// internalizing later.
       
   300 	writeStream.WriteInt32L(aItem.ItemDef().Use());
       
   301 	writeStream.WriteInt32L(aItem.ItemDef().Mode());	
       
   302 	aItem.ExternalizeL(writeStream);
       
   303 
       
   304 	writeStream.CommitL();
       
   305 	writeStream.Close();
       
   306 
       
   307 	return iBuffer->Ptr(0);
       
   308 	}	
       
   309 		
       
   310 /**
       
   311 Packs a CContactIdArray object. 
       
   312 
       
   313 @param aItem The contact ID array to be packed.
       
   314 
       
   315 @return Pointer to iBuffer. 
       
   316 */
       
   317 EXPORT_C TPtr8 CCntPackager::PackL(const CContactIdArray& aItem)
       
   318 	{
       
   319 	ResetPointer();
       
   320 	RBufWriteStream writeStream;
       
   321 	writeStream.Open(*iBuffer);
       
   322 
       
   323 	aItem.ExternalizeL(writeStream);
       
   324 
       
   325 	writeStream.CommitL();
       
   326 	writeStream.Close();
       
   327 
       
   328 	return iBuffer->Ptr(0);
       
   329 	}
       
   330 
       
   331 	
       
   332 /**
       
   333 Packs a CCntFilter object. 
       
   334 
       
   335 @param aItem The contact item filter to be packed.
       
   336 
       
   337 @return Pointer to iBuffer. 
       
   338 */
       
   339 EXPORT_C TPtr8 CCntPackager::PackL(const CCntFilter& aItem)
       
   340 	{
       
   341 	ResetPointer();
       
   342 	RBufWriteStream writeStream;
       
   343 	writeStream.Open(*iBuffer);
       
   344 
       
   345 	aItem.ExternalizeL(writeStream);
       
   346 
       
   347 	writeStream.CommitL();
       
   348 	writeStream.Close();
       
   349 
       
   350 	return iBuffer->Ptr(0);
       
   351 	}	
       
   352 
       
   353 
       
   354 /**
       
   355 Packs a CViewContact item. 
       
   356 
       
   357 @param aItem The CViewContact to be packed.
       
   358 
       
   359 @return Pointer to iBuffer. 
       
   360 */
       
   361 EXPORT_C TPtr8 CCntPackager::PackL(const CViewContact& aViewContact)
       
   362 	{
       
   363 	ResetPointer();
       
   364 	RBufWriteStream writeStream;
       
   365 	writeStream.Open(*iBuffer);
       
   366 
       
   367 	aViewContact.ExternalizeL(writeStream);
       
   368 
       
   369 	writeStream.CommitL();
       
   370 	writeStream.Close();
       
   371 
       
   372 	return iBuffer->Ptr(0);
       
   373 	}	
       
   374 
       
   375 
       
   376 /**
       
   377 Packs a CDesCArray object. 
       
   378 
       
   379 @param aItem The descriptor array to be packed.
       
   380 
       
   381 @return Pointer to iBuffer. 
       
   382 */
       
   383 EXPORT_C TPtr8 CCntPackager::PackL(const CDesCArray& aItem)
       
   384 	{
       
   385 	ResetPointer();
       
   386 	RBufWriteStream writeStream;
       
   387 	writeStream.Open(*iBuffer);
       
   388 
       
   389 	TInt count = aItem.Count();
       
   390 	writeStream.WriteInt32L(count);
       
   391 	
       
   392 	TInt length = 0;
       
   393 	for(TInt i=0; i<count;++i)
       
   394 		{
       
   395 		length = aItem[i].Length();
       
   396 		writeStream.WriteInt32L(length);		
       
   397 		writeStream.WriteL(aItem[i],length);
       
   398 		}
       
   399 
       
   400 	writeStream.CommitL();
       
   401 	writeStream.Close();
       
   402 	return iBuffer->Ptr(0);
       
   403 
       
   404 	}
       
   405 
       
   406 
       
   407 /**
       
   408 Packs an array of sort preferences.
       
   409 
       
   410 @param aItem The array of sort preferences.
       
   411 
       
   412 @return Pointer to iBuffer. 
       
   413 */
       
   414 EXPORT_C TPtr8 CCntPackager::PackL(const CArrayFix<CContactDatabase::TSortPref>& aItem)
       
   415 	{
       
   416 	ResetPointer();
       
   417 	RBufWriteStream writeStream;
       
   418 	writeStream.Open(*iBuffer);
       
   419 
       
   420 	TInt count = aItem.Count();
       
   421 	writeStream.WriteInt32L(count);
       
   422 
       
   423 	for(TInt i=0; i<count;++i)
       
   424 		{
       
   425 		aItem[i].ExternalizeL(writeStream);
       
   426 		}
       
   427 
       
   428 	writeStream.CommitL();
       
   429 	writeStream.Close();
       
   430 
       
   431 	return iBuffer->Ptr(0);
       
   432 	}
       
   433 
       
   434 
       
   435 /**
       
   436 Packs an array of UIDs.
       
   437 
       
   438 @param aItem The array of TUid objects.
       
   439 
       
   440 @return Pointer to iBuffer. 
       
   441 */
       
   442 EXPORT_C TPtr8 CCntPackager::PackL(const CArrayFixFlat<TUid>& aItem)
       
   443 	{
       
   444 	ResetPointer();
       
   445 	RBufWriteStream writeStream;
       
   446 	writeStream.Open(*iBuffer);
       
   447 	TInt count = aItem.Count();
       
   448 	writeStream.WriteInt32L(count);
       
   449 	//TInt length = 0;
       
   450 	for(TInt i=0; i<count;++i)
       
   451 		{
       
   452 		writeStream.WriteInt32L(aItem[i].iUid);
       
   453 		}
       
   454 	writeStream.CommitL();
       
   455 	writeStream.Close();
       
   456 	return iBuffer->Ptr(0);
       
   457 	}
       
   458 
       
   459 
       
   460 /**
       
   461 Unpacks CContactItem object from the internal buffer. 
       
   462 
       
   463 @return Pointer to the new contact item. 
       
   464 */
       
   465 EXPORT_C CContactItem* CCntPackager::UnpackCntItemLC() const
       
   466 	{
       
   467 	RBufReadStream readStream;
       
   468 	readStream.Open(*iBuffer);	
       
   469 	return CContactItem::NewLC(readStream);
       
   470 	}			
       
   471 
       
   472 	
       
   473 /**
       
   474 Unpacks CContentType object from the internal buffer. 
       
   475 
       
   476 @return Pointer to the new CContentType item. 
       
   477 */
       
   478 EXPORT_C CContentType* CCntPackager::UnpackCntContentTypeLC() const
       
   479 	{
       
   480 	RBufReadStream readStream;
       
   481 	readStream.Open(*iBuffer);
       
   482 	return CContentType::NewLC(readStream);
       
   483 	}	
       
   484 
       
   485 
       
   486 /**
       
   487 Unpacks CContactTextDef object from the internal buffer.
       
   488 
       
   489 @return Pointer to the new CContactTextDef item. 
       
   490 */
       
   491 EXPORT_C CContactTextDef* CCntPackager::UnpackCntTextDefLC() const
       
   492 	{
       
   493 	RBufReadStream readStream;
       
   494 	readStream.Open(*iBuffer);	
       
   495 	return CContactTextDef::NewLC(readStream);	
       
   496 	}
       
   497 
       
   498 
       
   499 /**
       
   500 Unpacks CContactItemViewDef object from the internal buffer.
       
   501 
       
   502 @return Pointer to the new CContactItemViewDef item. 
       
   503 */
       
   504 EXPORT_C CContactItemViewDef* CCntPackager::UnpackCntItemViewDefLC() const
       
   505 	{
       
   506 	RBufReadStream readStream;
       
   507 	readStream.Open(*iBuffer);
       
   508 	return CContactItemViewDef::NewLC(readStream);	
       
   509 	}
       
   510 
       
   511 	
       
   512 /**
       
   513 Unpacks CContactViewDef object from the internal buffer.
       
   514 
       
   515 @return Pointer to the new CContactViewDef item. 
       
   516 */
       
   517 EXPORT_C CContactViewDef* CCntPackager::UnpackCntViewDefLC() const
       
   518 	{
       
   519 	RBufReadStream readStream;
       
   520 	readStream.Open(*iBuffer);	
       
   521 	return CContactViewDef::NewLC(readStream);	
       
   522 	}	
       
   523 
       
   524 	
       
   525 /**
       
   526 Unpacks CContactIdArray object from the internal buffer.
       
   527 
       
   528 @return Pointer to the new CContactIdArray item. 
       
   529 */
       
   530 EXPORT_C CContactIdArray* CCntPackager::UnpackCntIdArrayLC() const
       
   531 	{
       
   532 	RBufReadStream readStream;
       
   533 	readStream.Open(*iBuffer);	
       
   534 	return CContactIdArray::NewLC(readStream);	
       
   535 	}	
       
   536 
       
   537 	
       
   538 /**
       
   539 Unpacks CCntFilter object from the internal buffer.
       
   540 
       
   541 @return Pointer to the new CCntFilter item. 
       
   542 */
       
   543 EXPORT_C CCntFilter* CCntPackager::UnpackCntFilterLC() const
       
   544 	{
       
   545 	RBufReadStream readStream;
       
   546 	readStream.Open(*iBuffer);
       
   547 	return CCntFilter::NewLC(readStream);
       
   548 	}
       
   549 
       
   550 		
       
   551 /**
       
   552 Unpacks CViewContact object from the internal buffer.
       
   553 
       
   554 @return Pointer to the new CViewContact item. 
       
   555 */
       
   556 EXPORT_C CViewContact* CCntPackager::UnpackViewContactLC() const
       
   557 	{
       
   558 	RBufReadStream readStream;
       
   559 	readStream.Open(*iBuffer);
       
   560 	return CViewContact::NewLC(readStream);
       
   561 	}
       
   562 
       
   563 
       
   564 /**
       
   565 Unpacks CDesCArray object from the internal buffer.
       
   566 
       
   567 @return Pointer to the new CDesCArray object. 
       
   568 */
       
   569 EXPORT_C CDesCArray* CCntPackager::UnpackDesCArrayLC() const
       
   570 	{
       
   571 	CDesCArray* unpackedCDesCArray = NULL;
       
   572 	
       
   573 	RBufReadStream readStream;
       
   574 	readStream.Open(*iBuffer);
       
   575 		
       
   576 	TInt count = readStream.ReadInt32L();
       
   577 	if(count!=0)
       
   578 		{
       
   579 		unpackedCDesCArray = new(ELeave) CDesCArrayFlat(count);
       
   580 		CleanupStack::PushL(unpackedCDesCArray);
       
   581 		TInt length = 0;
       
   582 		for (TInt i=0; i<count; ++i)
       
   583 			{
       
   584 			TFileName fileName;
       
   585 			length = readStream.ReadInt32L();		
       
   586 			readStream.ReadL(fileName,length);
       
   587 			unpackedCDesCArray->AppendL(fileName);
       
   588 			}
       
   589 		}	
       
   590 
       
   591 	return unpackedCDesCArray;
       
   592 	}
       
   593 
       
   594 
       
   595 /**
       
   596 Unpacks an array of sort preferences from the internal buffer.
       
   597 
       
   598 @return Pointer to the new array of sort preferences.
       
   599 */
       
   600 EXPORT_C CArrayFix<CContactDatabase::TSortPref>* CCntPackager::UnpackCArrayFixLC() const
       
   601 	{
       
   602 	CArrayFix<CContactDatabase::TSortPref>* unpacked = NULL;
       
   603 	RBufReadStream readStream;
       
   604 	readStream.Open(*iBuffer);
       
   605 		
       
   606 	unpacked = new (ELeave) CArrayFixFlat<CContactDatabase::TSortPref>(2);
       
   607 	CleanupStack::PushL(unpacked);
       
   608 
       
   609 	TInt count = readStream.ReadInt32L();
       
   610 	if(count!=0)
       
   611 		{
       
   612 		for (TInt i=0; i<count; ++i)
       
   613 			{
       
   614 			CContactDatabase::TSortPref pref;
       
   615 			pref.InternalizeL(readStream);
       
   616 			unpacked->AppendL(pref);
       
   617 			}
       
   618 		}
       
   619 
       
   620 	return unpacked;
       
   621 	}
       
   622 
       
   623 
       
   624 /**
       
   625 Unpacks an array of TUid objects from the internal buffer.
       
   626 
       
   627 @return Pointer to the new array of TUid objects.
       
   628 */
       
   629 EXPORT_C CArrayFixFlat<TUid>* CCntPackager::UnpackTUidArrayLC() const
       
   630 	{
       
   631 	CArrayFixFlat<TUid>* unpacked = NULL;
       
   632 	RBufReadStream readStream;
       
   633 	readStream.Open(*iBuffer);
       
   634 		
       
   635 	unpacked = new (ELeave) CArrayFixFlat<TUid>(2);
       
   636 	CleanupStack::PushL(unpacked);
       
   637 
       
   638 	TInt count = readStream.ReadInt32L();
       
   639 	if(count!=0)
       
   640 		{
       
   641 		for (TInt i=0; i<count; ++i)
       
   642 			{
       
   643 			TUid id;
       
   644 			id.iUid = readStream.ReadInt32L();
       
   645 			unpacked->AppendL(id);
       
   646 			}
       
   647 		}
       
   648 
       
   649 	return unpacked;
       
   650 	}