persistentstorage/dbms/ustor/US_REC.CPP
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 1998-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 #include "US_STD.H"
       
    17 
       
    18 // Class CDbStoreRecords::TIteratorC
       
    19 
       
    20 class CDbStoreRecords::TIteratorC
       
    21 	{
       
    22 	friend class CDbStoreRecords;
       
    23 public:
       
    24 	inline TDbRecordId Current() const;
       
    25 private:
       
    26 	TClusterDes iDes;
       
    27 	TDbRecordId iCurrent;
       
    28 	};
       
    29 
       
    30 inline TDbRecordId CDbStoreRecords::TIteratorC::Current() const
       
    31 	{return iCurrent;}
       
    32 
       
    33 
       
    34 // Class CDbStoreRecords::CIter
       
    35 
       
    36 NONSHARABLE_CLASS(CDbStoreRecords::CIter) : public CDbRecordIter
       
    37 	{
       
    38 public:
       
    39 	CIter(CDbStoreRecords& aRecords);
       
    40 private:
       
    41 	inline CDbStoreRecords& Records() const;
       
    42 //
       
    43 	TInt Count() const;
       
    44 	TDbRecordId CurrentL();
       
    45 	TBool GotoL(TDbPosition aPosition);
       
    46 	TBool GotoL(TDbRecordId aRecordId,RDbTableRow& aBuffer);
       
    47 	TBool SeekL(const TDbLookupKey& aKey,RDbTable::TComparison aComparison);
       
    48 	TDeleted DoDeletedL(TDbPosition aPosition,TDbRecordId aRecordId,const RDbTableRow* aRow);
       
    49 private:
       
    50 	CDbStoreRecords::TIteratorC iIter;
       
    51 	};
       
    52 
       
    53 CDbStoreRecords::CIter::CIter(CDbStoreRecords& aRecords)
       
    54 	: CDbRecordIter(aRecords)
       
    55 	{}
       
    56 
       
    57 inline CDbStoreRecords& CDbStoreRecords::CIter::Records() const
       
    58 	{return STATIC_CAST(CDbStoreRecords&,Host());}
       
    59 
       
    60 TInt CDbStoreRecords::CIter::Count() const
       
    61 	{
       
    62 	return Records().Count();
       
    63 	}
       
    64 
       
    65 TDbRecordId CDbStoreRecords::CIter::CurrentL()
       
    66 	{
       
    67 	return iIter.Current();
       
    68 	}
       
    69 
       
    70 TBool CDbStoreRecords::CIter::GotoL(TDbPosition aPosition)
       
    71 	{
       
    72 	return Records().GotoL(aPosition,iIter);
       
    73 	}
       
    74 
       
    75 TBool CDbStoreRecords::CIter::GotoL(TDbRecordId aRecordId,RDbTableRow&)
       
    76 	{
       
    77 	return Records().GotoL(aRecordId,iIter);
       
    78 	}
       
    79 
       
    80 TBool CDbStoreRecords::CIter::SeekL(const TDbLookupKey&,RDbTable::TComparison)
       
    81 //
       
    82 // Cannot do this on a table iterator
       
    83 //
       
    84 	{
       
    85 	Panic(EDbCannotSeek);
       
    86 	return EFalse;
       
    87 	}
       
    88 
       
    89 CDbStoreRecords::CIter::TDeleted CDbStoreRecords::CIter::DoDeletedL(TDbPosition aPosition,TDbRecordId,const RDbTableRow*)
       
    90 //
       
    91 // reposition to next after a record is deleted
       
    92 // Previous only required for reversed (index) iterators
       
    93 //
       
    94 	{
       
    95 	return Records().DeletedL(aPosition,iIter) ? EAtRow : ENoRow;
       
    96 	}
       
    97 
       
    98 
       
    99 // Class CDbStoreRecords::TToken
       
   100 
       
   101 void CDbStoreRecords::TToken::ExternalizeL(RWriteStream& aStream) const
       
   102 	{
       
   103 	aStream<<iHead<<iNext.Value()<<TCardinality(iCount)<<TUint32(iAutoIncrement);
       
   104 	}
       
   105 
       
   106 void CDbStoreRecords::TToken::InternalizeL(RReadStream& aStream)
       
   107 	{
       
   108 	aStream>>iHead;
       
   109 	iNext=aStream.ReadUint32L();
       
   110 	TCardinality card;
       
   111 	aStream>>card;
       
   112 	iCount=card;
       
   113 	iAutoIncrement=aStream.ReadUint32L();
       
   114 	}
       
   115 
       
   116 
       
   117 // Class CDbStoreRecords
       
   118 
       
   119 CDbStoreRecords::CDbStoreRecords(CClusterCache& aCache)
       
   120 	: iCache(aCache)
       
   121 	{}
       
   122 
       
   123 CDbStoreRecords::~CDbStoreRecords()
       
   124 	{
       
   125 	iMap.Close();
       
   126 	}
       
   127 
       
   128 TStreamId CDbStoreRecords::CreateL(CClusterCache& aCache)
       
   129 //
       
   130 // Create a new record space in the store, do not create a records object
       
   131 //
       
   132 	{
       
   133 	TToken token;
       
   134 	token.iHead=ClusterId(aCache.Store().ExtendL());
       
   135 	aCache.ClusterL().Create(token.iHead);
       
   136 	token.iNext=RecordId(token.iHead,0);
       
   137 	token.iCount=0;
       
   138 	token.iAutoIncrement=0;
       
   139 	RStoreWriteStream strm;
       
   140 	TStreamId id=strm.CreateLC(aCache.Store());
       
   141 	strm<<token;
       
   142 	strm.CommitL();
       
   143 	CleanupStack::PopAndDestroy();
       
   144 	return id;
       
   145 	}
       
   146 
       
   147 CDbStoreRecords* CDbStoreRecords::NewL(CClusterCache& aCache,const CDbStoreDef& aDef)
       
   148 //
       
   149 // Create a record space
       
   150 //
       
   151 	{
       
   152 	CDbStoreRecords* self=new(ELeave) CDbStoreRecords(aCache);
       
   153 	CleanupStack::PushL(self);
       
   154 	self->iClustering=aDef.Clustering();
       
   155 	self->iTokenId=aDef.TokenId();
       
   156 	CleanupStack::Pop();
       
   157 	return self;
       
   158 	}
       
   159 
       
   160 TBool CDbStoreRecords::RestoreL()
       
   161 //
       
   162 // Restore an existing record space from the store
       
   163 //
       
   164 	{
       
   165 	RStoreReadStream strm;
       
   166 	strm.OpenLC(iCache.Store(),iTokenId);
       
   167 	strm>>iToken;
       
   168 	CleanupStack::PopAndDestroy();
       
   169 	iLinks.Invalidate();
       
   170 	iMap.ResetL(iToken.iHead);
       
   171 	return EFalse;
       
   172 	}
       
   173 
       
   174 void CDbStoreRecords::DestroyL()
       
   175 //
       
   176 // Destroy the record space
       
   177 //
       
   178 	{
       
   179 	iCache.Store().DeleteL(iTokenId);
       
   180 	}
       
   181 
       
   182 TInt CDbStoreRecords::CardinalityL(CStreamStore& aStore,const CDbStoreDef& aDef)
       
   183 //
       
   184 // Return the record count without constructing the entire table
       
   185 //
       
   186 	{
       
   187 	RStoreReadStream strm;
       
   188 	strm.OpenLC(aStore,aDef.TokenId());
       
   189 	TToken token;
       
   190 	strm>>token;
       
   191 	CleanupStack::PopAndDestroy();
       
   192 	return token.iCount;
       
   193 	}
       
   194 
       
   195 void CDbStoreRecords::SynchL()
       
   196 //
       
   197 // write persistent token to the store
       
   198 //
       
   199 	{
       
   200 	RStoreWriteStream strm;
       
   201 	strm.ReplaceLC(iCache.Store(),iTokenId);
       
   202 	strm<<iToken;
       
   203 	strm.CommitL();
       
   204 	CleanupStack::PopAndDestroy();
       
   205 	}
       
   206 
       
   207 TInt CDbStoreRecords::DiscardL(TClusterId& aCluster)
       
   208 //
       
   209 // discard the cluster as part of the incremental drop
       
   210 // aCluster is updated to the next cluster, the number of records contained is returned
       
   211 //
       
   212 	{
       
   213 	TClusterDes des;
       
   214 	DesL(des,aCluster);
       
   215 	CCluster* cluster=iCache.Cluster(aCluster);
       
   216 	if (cluster)
       
   217 		cluster->Discard();
       
   218 	iCache.Store().DeleteL(aCluster);
       
   219 	aCluster=des.iNext;
       
   220 	TInt records=0;
       
   221 	for (TUint members=des.iMembership;members;members&=members-1)
       
   222 		++records;
       
   223 	return records;
       
   224 	}
       
   225 
       
   226 TClusterId CDbStoreRecords::AlterL(TClusterId aCluster,CCluster::MAlter& aAlterer)
       
   227 	{
       
   228 	CCluster& cluster=iCache.ClusterL(aCluster);
       
   229 	cluster.AlterL(aAlterer);
       
   230 	return cluster.Des().iNext;
       
   231 	}
       
   232 
       
   233 TPtrC8 CDbStoreRecords::ReadL(TDbRecordId aRecordId) const
       
   234 	{
       
   235 	return iCache.ClusterL(ClusterId(aRecordId)).RecordL(RecordIndex(aRecordId));
       
   236 	}
       
   237 
       
   238 TUint CDbStoreRecords::AutoIncrementL()
       
   239 //
       
   240 // Provide the next value for an auto-increment column
       
   241 //
       
   242 	{
       
   243 	return iToken.iAutoIncrement++;
       
   244 	}
       
   245 
       
   246 TUint8* CDbStoreRecords::UpdateRecordL(TDbRecordId aRecordId,TInt aNewSize)
       
   247 //
       
   248 // read the cluster and return a writable descriptor over the new record data
       
   249 //
       
   250 	{
       
   251 	return iCache.ClusterL(ClusterId(aRecordId)).UpdateL(RecordIndex(aRecordId),aNewSize);
       
   252 	}
       
   253 
       
   254 
       
   255 TUint8* CDbStoreRecords::DoNewL(TInt aRecordSize)
       
   256 //
       
   257 // Phase 1 of appending a records
       
   258 //
       
   259 	{
       
   260 	return UpdateRecordL(iToken.iNext,aRecordSize);
       
   261 	}
       
   262 
       
   263 TDbRecordId CDbStoreRecords::AppendL()
       
   264 //
       
   265 // Phase 2 of appending a record
       
   266 //
       
   267 	{
       
   268 	TDbRecordId id=iToken.iNext;
       
   269 	TClusterId clusterId=ClusterId(id);
       
   270 	CCluster* cluster=iCache.Cluster(clusterId);
       
   271 	__ASSERT(cluster);
       
   272 	TInt nextIndex=RecordIndex(id)+1;
       
   273 	if (nextIndex>=iClustering || cluster->IsFull())
       
   274 		{
       
   275 		TClusterId newcluster=ClusterId(iCache.Store().ExtendL());
       
   276 		cluster->Relink(newcluster);
       
   277 		cluster->FlushL();
       
   278 		cluster->Create(newcluster);
       
   279 		iMap.BindL(clusterId,newcluster);
       
   280 		iLinks.Bind(clusterId,newcluster,iMap);
       
   281 		iToken.iNext=RecordId(newcluster,0);
       
   282 		}
       
   283 	else
       
   284 		iToken.iNext=RecordId(clusterId,nextIndex);
       
   285 	++iToken.iCount;
       
   286 	return id;
       
   287 	}
       
   288 
       
   289 TUint8* CDbStoreRecords::DoReplaceL(TDbRecordId aRecordId,TInt aRecordSize)
       
   290 	{
       
   291 	return UpdateRecordL(aRecordId,aRecordSize);
       
   292 	}
       
   293 
       
   294 void CDbStoreRecords::DoEraseL(TDbRecordId aRecordId)
       
   295 	{
       
   296 	TClusterId clusterId=ClusterId(aRecordId);
       
   297 	CCluster& cluster=iCache.ClusterL(clusterId);
       
   298 	if (!cluster.DeleteL(RecordIndex(aRecordId)) && clusterId!=ClusterId(iToken.iNext))
       
   299 		{	// cluster is now empty, but don't drop the last cluster, coz it hasn't all been used!
       
   300 		TClusterDes des;
       
   301 		TClusterId prev=PreviousClusterL(des,clusterId);
       
   302 		TClusterId next=cluster.Des().iNext;	// next cluster
       
   303 		cluster.Discard();						// discard the cluster
       
   304 		iCache.Store().DeleteL(clusterId);
       
   305 		if (prev!=KNullClusterId)
       
   306 			iCache.ClusterL(prev).Relink(next);
       
   307 		else
       
   308 			iToken.iHead=next;
       
   309 		iLinks.Drop(clusterId,next);
       
   310 		iMap.DropL(clusterId,next);
       
   311 		}
       
   312 	--iToken.iCount;
       
   313 	}
       
   314 
       
   315 CDbRecordIter* CDbStoreRecords::IteratorL()
       
   316 	{
       
   317 	return new(ELeave) CIter(*this);
       
   318 	}
       
   319 
       
   320 void CDbStoreRecords::CompleteMapL()
       
   321 	{
       
   322 	TClusterId cluster=iMap.LastBound();
       
   323 	TClusterDes des;
       
   324 	DesL(des,cluster);
       
   325 	do cluster=NextClusterL(des,cluster); while (cluster!=KNullClusterId);
       
   326 	}
       
   327 
       
   328 void CDbStoreRecords::DesL(TClusterDes& aDes,TClusterId aCluster)
       
   329 //
       
   330 // Read just the cluster descriptor
       
   331 //
       
   332 	{
       
   333 	CCluster* cluster=iCache.Cluster(aCluster);
       
   334 	if (cluster)
       
   335 		aDes=cluster->Des();
       
   336 	else
       
   337 		{
       
   338 		RStoreReadStream stream;
       
   339 		stream.OpenLC(iCache.Store(),aCluster);
       
   340 		stream>>aDes;
       
   341 		CleanupStack::PopAndDestroy();
       
   342 		}
       
   343 	}
       
   344 
       
   345 TClusterId CDbStoreRecords::NextClusterL(TClusterDes& aDes,TClusterId aCluster)
       
   346 	{
       
   347 	TClusterId next=aDes.iNext;
       
   348 	if (next==KNullClusterId)
       
   349 		iMap.Complete(aCluster);
       
   350 	else
       
   351 		{
       
   352 		iMap.BindL(aCluster,next);
       
   353 		iLinks.Bind(aCluster,next,iMap);
       
   354 		DesL(aDes,next);
       
   355 		}
       
   356 	return next;
       
   357 	}
       
   358 
       
   359 TBool CDbStoreRecords::LocateL(TClusterId aCluster)
       
   360 //
       
   361 // Locate the cluster in the table. If not present return EFalse
       
   362 // If present fill up the cluster link cache with the loop
       
   363 // containing the predecessor to aCluster
       
   364 // aDes will have the previous cluster des
       
   365 //
       
   366 	{
       
   367 	TClusterId cluster=aCluster;
       
   368 	__ASSERT(aCluster!=iToken.iHead);
       
   369 	__ASSERT(!iLinks.At(aCluster,cluster));
       
   370 //
       
   371 	if (!iMap.IsComplete())
       
   372 		CompleteMapL();
       
   373 //
       
   374 	TClusterDes des;
       
   375 	TClusterId links[RClusterMap::ESeparation];
       
   376 	TClusterId* p=links;
       
   377 	for (TInt n=RClusterMap::ESeparation;n>0;--n)
       
   378 		{
       
   379 		*p++=cluster;
       
   380 		TBool r=iMap.At(cluster,cluster);
       
   381 		DesL(des,cluster);
       
   382 		if (r)
       
   383 			{
       
   384 			__ASSERT(cluster!=KNullClusterId);	// only iHead->Null
       
   385 			iLinks.Reset(cluster);
       
   386 			while (aCluster!=des.iNext)
       
   387 				cluster=NextClusterL(des,cluster);
       
   388 			iLinks.Add(links,p);
       
   389 			return ETrue;
       
   390 			}
       
   391 		cluster=des.iNext;
       
   392 		}
       
   393 	return EFalse;	// not in this table!
       
   394 	}
       
   395 
       
   396 TClusterId CDbStoreRecords::PreviousClusterL(TClusterDes& aDes,TClusterId aCluster)
       
   397 	{
       
   398 	if (aCluster==iToken.iHead)
       
   399 		return KNullClusterId;
       
   400 	if (!iLinks.At(aCluster,aCluster))
       
   401 		{
       
   402 		__DEBUG(TBool dbgchk=) LocateL(aCluster);
       
   403 		__ASSERT(dbgchk);
       
   404 		__DEBUG(dbgchk=) iLinks.At(aCluster,aCluster);
       
   405 		__ASSERT(dbgchk);
       
   406 		}
       
   407 	DesL(aDes,aCluster);
       
   408 	return aCluster;
       
   409 	}
       
   410 
       
   411 TBool CDbStoreRecords::GotoL(TDbPosition aPosition,TIteratorC& anIterator)
       
   412 	{
       
   413 	TClusterId cluster=ClusterId(anIterator.iCurrent);
       
   414 	TInt index=RecordIndex(anIterator.iCurrent);
       
   415 	switch (aPosition)
       
   416 		{
       
   417 	default:
       
   418 		__ASSERT(0);
       
   419 	case EDbFirst:
       
   420 		DesL(anIterator.iDes,cluster=iToken.iHead);
       
   421 		iLinks.Reset(cluster);
       
   422 		index=-1;
       
   423 		// drop through to next
       
   424 	case EDbNext:
       
   425 		for (;;)
       
   426 			{
       
   427 			TUint membership=anIterator.iDes.iMembership;
       
   428 			while (++index<KMaxClustering)
       
   429 				{
       
   430 				if ((membership>>index)&1)
       
   431 					{
       
   432 					__ASSERT(cluster!=ClusterId(iToken.iNext)||index<RecordIndex(iToken.iNext));
       
   433 					anIterator.iCurrent=RecordId(cluster,index);
       
   434 					return ETrue;
       
   435 					}
       
   436 				}
       
   437 			cluster=NextClusterL(anIterator.iDes,cluster);
       
   438 			if (cluster==KNullClusterId)
       
   439 				return EFalse;	// ran out of data
       
   440 			index=-1;
       
   441 			}
       
   442 	case EDbLast:
       
   443 		DesL(anIterator.iDes,cluster=ClusterId(iToken.iNext));
       
   444 		index=KMaxClustering;
       
   445 		// drop through to previous
       
   446 	case EDbPrevious:
       
   447 		for (;;)
       
   448 			{
       
   449 			TUint membership=anIterator.iDes.iMembership;
       
   450 			while (--index>=0)
       
   451 				{
       
   452 				if ((membership>>index)&1)
       
   453 					{
       
   454 					anIterator.iCurrent=RecordId(cluster,index);
       
   455 					return ETrue;
       
   456 					}
       
   457 				}
       
   458 			__ASSERT(index==-1);
       
   459 			cluster=PreviousClusterL(anIterator.iDes,cluster);
       
   460 			if (cluster==KNullClusterId)
       
   461 				return EFalse;	// ran out of data
       
   462 			index=KMaxClustering;
       
   463 			}
       
   464 		}
       
   465 	}
       
   466 
       
   467 TBool CDbStoreRecords::DeletedL(TDbPosition aPosition,TIteratorC& anIterator)
       
   468 //
       
   469 // Record has been deleted
       
   470 //
       
   471 	{
       
   472 	anIterator.iDes.iMembership&=~(1<<RecordIndex(anIterator.iCurrent));
       
   473 	return GotoL(aPosition,anIterator);
       
   474 	}
       
   475 
       
   476 TBool CDbStoreRecords::GotoL(TDbRecordId aRecordId,TIteratorC& anIterator)
       
   477 //
       
   478 // Set the iterator to the record id, return false if the record is not present
       
   479 //
       
   480 	{
       
   481 	TClusterId cluster=ClusterId(aRecordId);
       
   482 	if (cluster!=iToken.iHead && !iLinks.Has(cluster) && !LocateL(cluster))
       
   483 		return EFalse;
       
   484 	anIterator.iCurrent=aRecordId;
       
   485 	DesL(anIterator.iDes,cluster);
       
   486 	return (anIterator.iDes.iMembership>>RecordIndex(aRecordId))&1;
       
   487 	}
       
   488 
       
   489 TBool CDbStoreRecords::ExistsL(TDbRecordId aRecordId)
       
   490 //
       
   491 // Ensure that the record is in this table
       
   492 //
       
   493 	{
       
   494 	TIteratorC iter;
       
   495 	return GotoL(aRecordId,iter);
       
   496 	}
       
   497 
       
   498 // Class HUnicodeCompressor
       
   499 
       
   500 NONSHARABLE_CLASS(HUnicodeCompressor) : public TStreamFilter
       
   501 	{
       
   502 public:
       
   503 	HUnicodeCompressor(MStreamBuf* aSink);
       
   504 private:
       
   505 	void DoRelease();
       
   506 	void DoSynchL();
       
   507 	TInt Capacity(TInt aMaxLength);
       
   508 	TInt FilterL(TAny* aPtr,TInt aMaxLength,const TUint8*& aFrom,const TUint8* anEnd);
       
   509 private:
       
   510 	enum {EFlushBufferSize=16};
       
   511 private:
       
   512 	TUnicodeCompressor iCompressor;
       
   513 	};
       
   514 
       
   515 HUnicodeCompressor::HUnicodeCompressor(MStreamBuf* aSink)
       
   516 	{
       
   517 	Set(aSink,EAttached|EWrite);
       
   518 	}
       
   519 
       
   520 void HUnicodeCompressor::DoRelease()
       
   521 	{
       
   522 	TStreamFilter::DoRelease();
       
   523 	delete this;
       
   524 	}
       
   525 
       
   526 TInt HUnicodeCompressor::Capacity(TInt aMaxLength)
       
   527 //
       
   528 // Return the maximum guaranteed input used for aMaxLength output.
       
   529 // SUC at worst expands n chars to 3n bytes
       
   530 //
       
   531 	{
       
   532 	aMaxLength=(aMaxLength+2)/3;	// # chars input guaranteed
       
   533 	return aMaxLength*2;			// # bytes
       
   534 	}
       
   535 
       
   536 TInt HUnicodeCompressor::FilterL(TAny* aPtr,TInt aMaxLength,const TUint8*& aFrom,const TUint8* aEnd)
       
   537 	{
       
   538 	TMemoryUnicodeSource source(reinterpret_cast<const TUint16*>(aFrom));
       
   539 	TInt used;
       
   540 	iCompressor.CompressL(reinterpret_cast<TUint8*>(aPtr),source,aMaxLength,(aEnd-aFrom)>>1,&aMaxLength,&used);
       
   541 	aFrom+=used<<1;
       
   542 	return aMaxLength;
       
   543 	}
       
   544 
       
   545 void HUnicodeCompressor::DoSynchL()
       
   546 	{
       
   547 	if (IsCommitted())
       
   548 		return;
       
   549 //
       
   550 	TUint8 buf[EFlushBufferSize];
       
   551 	TInt emit;
       
   552 	iCompressor.FlushL(buf,EFlushBufferSize,emit);
       
   553 	if (emit)
       
   554 		EmitL(buf,emit);
       
   555 //
       
   556 	TStreamFilter::DoSynchL();
       
   557 	Committed();
       
   558 	}
       
   559 
       
   560 // Class HUnicodeExander
       
   561 
       
   562 NONSHARABLE_CLASS(HUnicodeExpander) : public TStreamFilter
       
   563 	{
       
   564 public:
       
   565 	HUnicodeExpander(MStreamBuf* aSource);
       
   566 private:
       
   567 	void DoRelease();
       
   568 //	void DoSynchL();
       
   569 	TInt Capacity(TInt aMaxLength);
       
   570 	TInt FilterL(TAny* aPtr,TInt aMaxLength,const TUint8*& aFrom,const TUint8* anEnd);
       
   571 private:
       
   572 	enum {EFlushBufferSize=16};
       
   573 private:
       
   574 	TUnicodeExpander iExpander;
       
   575 	};
       
   576 
       
   577 HUnicodeExpander::HUnicodeExpander(MStreamBuf* aSource)
       
   578 	{
       
   579 	Set(aSource,EAttached|ERead);
       
   580 	}
       
   581 
       
   582 void HUnicodeExpander::DoRelease()
       
   583 	{
       
   584 	TStreamFilter::DoRelease();
       
   585 	delete this;
       
   586 	}
       
   587 
       
   588 TInt HUnicodeExpander::Capacity(TInt aMaxLength)
       
   589 //
       
   590 // Return the maximum guaranteed input used for aMaxLength output.
       
   591 // SUC at worst expands n chars to 3n bytes
       
   592 //
       
   593 	{
       
   594 	return aMaxLength>>1;			// best expansion from ASCII chars
       
   595 	}
       
   596 
       
   597 TInt HUnicodeExpander::FilterL(TAny* aPtr,TInt aMaxLength,const TUint8*& aFrom,const TUint8* aEnd)
       
   598 	{
       
   599 	TMemoryUnicodeSink sink(reinterpret_cast<TUint16*>(aPtr));
       
   600 	TInt used;
       
   601 	iExpander.ExpandL(sink,aFrom,aMaxLength>>1,aEnd-aFrom,&aMaxLength,&used);
       
   602 	aFrom+=used;
       
   603 	return aMaxLength<<1;
       
   604 	}
       
   605 
       
   606 /*
       
   607 void HUnicodeExpander::DoSynchL()
       
   608 	{
       
   609 	if (IsCommitted())
       
   610 		return;
       
   611 //
       
   612 //	TUint8 buf[EFlushBufferSize];
       
   613 //	TInt emit;
       
   614 //	iCompressor.FlushL(buf,EFlushBufferSize,&emit);
       
   615 //	if (emit)
       
   616 //		EmitL(buf,emit);
       
   617 //
       
   618 	TStreamFilter::DoSynchL();
       
   619 	Committed();
       
   620 	}
       
   621 */
       
   622 
       
   623 // Class CDbStoreBlobs
       
   624 
       
   625 CDbStoreBlobs::CDbStoreBlobs(CDbStoreDatabase& aDatabase,TInt aInlineLimit)
       
   626 	: iDatabase(aDatabase)
       
   627 	{
       
   628 	SetInlineLimit(aInlineLimit);
       
   629 	}
       
   630 
       
   631 MStreamBuf* CDbStoreBlobs::DoCreateL(TDbBlobId& aBlobId,TDbColType aType)
       
   632 	{
       
   633 	__ASSERT(TDbCol::IsLong(aType));
       
   634 //
       
   635 	RDbStoreWriteStream strm(iDatabase);
       
   636 	aBlobId=strm.CreateLC(iDatabase.Store()).Value();
       
   637 	strm.FilterL(aType!=EDbColLongBinary?strm.EText:strm.EBinary,aBlobId);
       
   638 	MStreamBuf* blob=strm.Sink();
       
   639 	if (aType==EDbColLongText16)
       
   640 		blob=new(ELeave) HUnicodeCompressor(blob);
       
   641 	CleanupStack::Pop();
       
   642 	return blob;
       
   643 	}
       
   644 
       
   645 MStreamBuf* CDbStoreBlobs::ReadL(TDbBlobId aBlobId,TDbColType aType) const
       
   646 	{
       
   647 	__ASSERT(TDbCol::IsLong(aType));
       
   648 //
       
   649 	RDbStoreReadStream strm(iDatabase);
       
   650 	strm.OpenLC(iDatabase.Store(),aBlobId);
       
   651 	strm.FilterL(aType!=EDbColLongBinary?strm.EText:strm.EBinary,aBlobId);
       
   652 	MStreamBuf* blob=strm.Source();
       
   653 	if (aType==EDbColLongText16)
       
   654 		blob=new(ELeave) HUnicodeExpander(blob);
       
   655 	CleanupStack::Pop();
       
   656 	return blob;
       
   657 	}
       
   658 
       
   659 void CDbStoreBlobs::DoDeleteL(TDbBlobId aBlobId)
       
   660 	{
       
   661 	iDatabase.Store().DeleteL(TStreamId(aBlobId));
       
   662 	}