calendarengines/versit2/src/ICalValue.cpp
changeset 0 f979ecb2b13e
child 27 55d60436f00b
child 51 0b38fc5b94c6
equal deleted inserted replaced
-1:000000000000 0:f979ecb2b13e
       
     1 /*
       
     2 * Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   Implements the definition of CICalValue.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 // Class include.
       
    21 #include "ICalValue.h"	// CICalValue
       
    22 
       
    23 //debug
       
    24 #include "calendarengines_debug.h"
       
    25 
       
    26 // User includes.
       
    27 #include "ICalKeyWords.h"		// Literals
       
    28 #include "ICalRuleSegment.h"	// CICalRuleSegment
       
    29 
       
    30 // Constants.
       
    31 
       
    32 // Maximum number of characters to use for storing TInt.
       
    33 // (The maximum number of characters for storing a decimal representation of
       
    34 // KMaxTInt, KMinTInt or even KMaxTUint is 10 on current implementations.
       
    35 // The maximum number of characters for storing a decimal representation of 
       
    36 // KMaxTUint64 is 20, so using this for future proofing.)
       
    37 const TInt KICalTIntWidth = 20;
       
    38 
       
    39 // Width of "HHMMSS"
       
    40 const TInt KICalTimeWidth = 6;
       
    41 
       
    42 // Width of "YYYYMMDD"
       
    43 const TInt KICalDateWidth = 8;
       
    44 
       
    45 // Width of "YYYYMMDDTHHMMSS" (note the 'T' in the middle)
       
    46 const TInt KICalDateTimeWidth = KICalDateWidth + KICalTimeWidth + 1;
       
    47 
       
    48 // Width of a duration.
       
    49 const TInt KICalDurationWidth = 25;
       
    50 
       
    51 // Width of a short format UTC offset.
       
    52 const TInt KShortFormatUtcOffsetWidth = 5;	// The width of (e.g.) +1000.
       
    53 
       
    54 // Width of a long format UTC offset.
       
    55 const TInt KLongFormatUtcOffsetWidth = 7;	// The width of (e.g.) -013045.
       
    56 
       
    57 // Time constants.	
       
    58 const TInt KICalSecondsPerMinute =     60;
       
    59 const TInt KICalSecondsPerHour   =   3600; // That is:      60*60;
       
    60 const TInt KICalSecondsPerDay    =  86400; // That is:   24*60*60;
       
    61 const TInt KICalSecondsPerWeek   = 604800; // That is: 7*24*60*60;
       
    62 
       
    63 // Time characters
       
    64 const TUint KICalUtcChar('Z');		// UTC time.
       
    65 const TUint KICalTimeChar('T');		// Date/time separator.
       
    66 const TUint KICalPeriodChar('/');	// Period separator.
       
    67 const TUint KICalMicroChar('.');	// Second/microsecond separator.
       
    68 const TUint KICalDurationChar('P');	// Duration.
       
    69 const TUint KICalWeekChar('W');		// Week.
       
    70 const TUint KICalDayChar('D');		// Day.
       
    71 const TUint KICalHourChar('H');		// Hour.
       
    72 const TUint KICalMinuteChar('M');	// Minute.
       
    73 const TUint KICalSecondChar('S');	// Second.
       
    74 const TUint KICalPositiveChar('+');	// Positive values.
       
    75 const TUint KICalNegativeChar('-');	// Negative values.
       
    76 
       
    77 // Date format.
       
    78 _LIT(KICalDateFormat, "%F%Y%M%D");
       
    79 	
       
    80 /**
       
    81 Static factory construction.
       
    82 @return A new CICalValue.
       
    83 @publishedPartner
       
    84 */
       
    85 EXPORT_C CICalValue* CICalValue::NewL()
       
    86 	{
       
    87 	TRACE_ENTRY_POINT;
       
    88 	
       
    89 	CICalValue* self  = CICalValue::NewLC();
       
    90 	CleanupStack::Pop(self);
       
    91 	
       
    92 	TRACE_EXIT_POINT;
       
    93 	return self;
       
    94 	}
       
    95 
       
    96 /**
       
    97 Static factory construction.
       
    98 @return A new CICalValue.
       
    99 @publishedPartner
       
   100 */
       
   101 EXPORT_C CICalValue* CICalValue::NewLC()
       
   102 	{
       
   103 	TRACE_ENTRY_POINT;
       
   104 	
       
   105 	CICalValue* self  = new (ELeave) CICalValue;
       
   106 	CleanupStack::PushL(self);
       
   107 	self->ConstructL();
       
   108 	
       
   109 	TRACE_EXIT_POINT;
       
   110 	return self;
       
   111 	}
       
   112 
       
   113 /**
       
   114 Destructor.
       
   115 @publishedPartner
       
   116 */
       
   117 CICalValue::~CICalValue()
       
   118 	{
       
   119 	TRACE_ENTRY_POINT;
       
   120 	TRACE_EXIT_POINT;
       
   121 	delete iValue;
       
   122 	}
       
   123 
       
   124 /**
       
   125 Returns a copy of the value as an 8-bit string. User takes ownership of the
       
   126 returned descriptor, which is also left on the Cleanup Stack. Note that each
       
   127 16-bit word in the value is copied into a single 8-bit word in the returned
       
   128 descriptor and any values greater than 256 are set to the value '1'. This will
       
   129 not occur if the value was set using SetBinaryL().
       
   130 @return An 8-bit copy of the value.
       
   131 @publishedPartner
       
   132 */
       
   133 EXPORT_C HBufC8* CICalValue::BinaryLC() const
       
   134 	{
       
   135 	TRACE_ENTRY_POINT;
       
   136 	
       
   137 	CheckNullValueL();
       
   138 	HBufC8* buf = HBufC8::NewLC(iValue->Length());
       
   139 	buf->Des().Copy(*iValue);
       
   140 	
       
   141 	TRACE_EXIT_POINT;
       
   142 	return buf;
       
   143 	}
       
   144 
       
   145 /**
       
   146 Stores an 8-bit buffer in the CICalValue. Each 8-bit value is stored within a
       
   147 16-bit value internally.
       
   148 @param aBuffer The 8-bit buffer to be stored.
       
   149 @publishedPartner
       
   150 */
       
   151 EXPORT_C void CICalValue::SetBinaryL(const TDesC8& aBuffer)
       
   152 	{
       
   153 	TRACE_ENTRY_POINT;
       
   154 	
       
   155 	PrepareValuePointer();
       
   156 	iValue = HBufC::NewL(aBuffer.Length());
       
   157 	iValue->Des().Copy(aBuffer);
       
   158 	}
       
   159 
       
   160 /**
       
   161 Returns the CICalValue as a TBool. Leaves if the value cannot be read as a TBool.
       
   162 @return TBool stored in the value.
       
   163 @leave KErrCorrupt if value is not a valid Boolean value.
       
   164 @publishedPartner
       
   165 */
       
   166 EXPORT_C TBool CICalValue::BooleanL() const
       
   167 	{
       
   168 	TRACE_ENTRY_POINT;
       
   169 	
       
   170 	CheckNullValueL();
       
   171 	
       
   172 	if (iValue->Des() == KICalTrue)
       
   173 		{
       
   174 		TRACE_EXIT_POINT;
       
   175 		return ETrue;
       
   176 		}
       
   177 	else if (iValue->Des() == KICalFalse)
       
   178 		{
       
   179 		TRACE_EXIT_POINT;
       
   180 		return EFalse;
       
   181 		}
       
   182 	
       
   183 	// Else...
       
   184 	User::Leave(KErrCorrupt);
       
   185 	
       
   186 	TRACE_EXIT_POINT;
       
   187 	return EFalse;	// Never reached.
       
   188 	}
       
   189 
       
   190 /**
       
   191 Stores a TBool in the CICalValue.
       
   192 @param aBool TBool to be stored.
       
   193 @publishedPartner
       
   194 */
       
   195 EXPORT_C void CICalValue::SetBooleanL(TBool aBool)
       
   196 	{
       
   197 	TRACE_ENTRY_POINT;
       
   198 	
       
   199 	PrepareValuePointer();
       
   200 	
       
   201 	if (aBool) // ETrue
       
   202 		{
       
   203 		iValue = KICalTrue().AllocL();
       
   204 		}
       
   205 	else	// EFalse
       
   206 		{
       
   207 		iValue = KICalFalse().AllocL();
       
   208 		}
       
   209 		
       
   210 	TRACE_EXIT_POINT;
       
   211 	}
       
   212 
       
   213 /**
       
   214 Returns the CICalValue as a date (TTime).
       
   215 @param aDate TTime to store the date in.
       
   216 @publishedPartner
       
   217 */
       
   218 EXPORT_C void CICalValue::GetDateL(TTime& aDate) const
       
   219 	{
       
   220 	TRACE_ENTRY_POINT;
       
   221 	
       
   222 	CheckNullValueL();
       
   223 	GetDateFromValueL(aDate);
       
   224 	
       
   225 	TRACE_EXIT_POINT;
       
   226 	}
       
   227 
       
   228 /**
       
   229 Stores a date (TTime) as the value.
       
   230 @param aDate TTime to be stored.
       
   231 @publishedPartner
       
   232 */
       
   233 EXPORT_C void CICalValue::SetDateL(const TTime& aDate)
       
   234 	{
       
   235 	TRACE_ENTRY_POINT;
       
   236 	
       
   237 	PrepareValuePointer();
       
   238 	iValue = HBufC::NewL(KICalDateWidth);
       
   239 	AppendDateToValueL(aDate);
       
   240 	
       
   241 	TRACE_EXIT_POINT;
       
   242 	}
       
   243 
       
   244 /**
       
   245 Returns the CICalValue as a time (TTime).
       
   246 @param aTime TTime to store the time in.
       
   247 @param aTzType Enumeration showing whether the time represents local time (not
       
   248 supported), UTC or a custom time zone.
       
   249 @publishedPartner
       
   250 */
       
   251 EXPORT_C void CICalValue::GetTimeL(TTime& aTime, TTimeZoneType& aTzType) const
       
   252 	{
       
   253 	TRACE_ENTRY_POINT;
       
   254 	
       
   255 	CheckNullValueL();
       
   256 	GetTimeFromValueL(aTime, aTzType);
       
   257 	
       
   258 	TRACE_EXIT_POINT;
       
   259 	}
       
   260 
       
   261 /**
       
   262 Stores a time (TTime) as the value.
       
   263 @param aTime TTime to be stored.
       
   264 @param aTzType Enumeration showing whether the time represents local time (not
       
   265 supported), UTC or a custom time zone.
       
   266 @publishedPartner
       
   267 */
       
   268 EXPORT_C void CICalValue::SetTimeL(const TTime& aTime, TTimeZoneType aTzType)
       
   269 	{
       
   270 	TRACE_ENTRY_POINT;
       
   271 	
       
   272 	PrepareValuePointer();
       
   273 	
       
   274 	if (aTzType == EUtcTime)
       
   275 		{
       
   276 		iValue = HBufC::NewL(KICalTimeWidth + 1);
       
   277 		AppendTimeToValueL(aTime);
       
   278 		iValue->Des().Append(KICalUtcChar);	// Append a 'Z' to signify UTC.
       
   279 		}
       
   280 	else if (aTzType == ESpecifiedTimeZone || aTzType == EFloatingTime)
       
   281 		{
       
   282 		iValue = HBufC::NewL(KICalTimeWidth);
       
   283 		AppendTimeToValueL(aTime);
       
   284 		}
       
   285 	
       
   286 	TRACE_EXIT_POINT;
       
   287 	}
       
   288 
       
   289 /**
       
   290 Returns the CICalValue as a date/time (TTime).
       
   291 @param aDateTime TTime to store the date/time in.
       
   292 @param aTzType Enumeration showing whether the time represents local time (not
       
   293 supported), UTC or a custom time zone.
       
   294 @param aFirstCharacterNum Skip this many characters of the internal buffer
       
   295 @leave Leaves with KErrCorrupt if the value is not a valid date/time.
       
   296 @publishedPartner
       
   297 */
       
   298 EXPORT_C void CICalValue::GetDateTimeL(TTime& aDateTime, TTimeZoneType& aTzType, TInt aFirstCharacterNum) const
       
   299 	{
       
   300 	TRACE_ENTRY_POINT;
       
   301 	
       
   302 	CheckNullValueL();
       
   303 	
       
   304 	// The GetTimeFromValueL() function explicitly sets the TTime passed
       
   305 	// in, so create a new TTime for the date and merge with the time later.
       
   306 	TTime theDate;
       
   307 	GetDateFromValueL(theDate, aFirstCharacterNum);
       
   308 	
       
   309 	// Only start looking for the time at character position KICalDateWidth
       
   310 	// plus one for the 'T' separator.
       
   311 	if (iValue->Length() > aFirstCharacterNum + KICalDateWidth + 1)
       
   312 		{
       
   313 		TTime theTime;
       
   314 		if ((*iValue)[aFirstCharacterNum + KICalDateWidth] != KICalDateTimeSeparator)
       
   315 			{
       
   316 			User::Leave(KErrCorrupt);
       
   317 			}
       
   318 
       
   319 		GetTimeFromValueL(theTime, aTzType, aFirstCharacterNum + KICalDateWidth + 1);
       
   320 
       
   321 		// Set the time component.
       
   322 		TDateTime dateValues(theDate.DateTime());
       
   323 		TDateTime combinedValues(theTime.DateTime());
       
   324 		
       
   325 		// Set the date component.
       
   326 		combinedValues.SetYear(dateValues.Year());
       
   327 		combinedValues.SetMonth(dateValues.Month());
       
   328 		combinedValues.SetDay(dateValues.Day());
       
   329 		
       
   330 		// Set the value to return.
       
   331 		aDateTime = TTime(combinedValues);
       
   332 		}
       
   333 	else
       
   334 		{
       
   335 		// There is no time component specified.  For compatibility with MS Outlook,
       
   336 		// which can export RECURRENCE-ID fields with no time component, we use
       
   337 		// a default time of '00:00'
       
   338 		aDateTime = theDate;
       
   339 		}
       
   340 	
       
   341 	TRACE_EXIT_POINT;
       
   342 	}
       
   343 
       
   344 /**
       
   345 Stores a date/time (TTime) as the value.
       
   346 @param aDateTime TTime to be stored.
       
   347 @param aTzType Enumeration showing whether the time represents floating time,
       
   348 UTC or a custom time zone.
       
   349 @publishedPartner
       
   350 */
       
   351 EXPORT_C void CICalValue::SetDateTimeL(const TTime& aDateTime, TTimeZoneType aTzType)
       
   352 	{
       
   353 	TRACE_ENTRY_POINT;
       
   354 	
       
   355 	PrepareValuePointer();
       
   356 	
       
   357 	if (aTzType == EUtcTime)
       
   358 		{
       
   359 		iValue = HBufC::NewL(KICalDateTimeWidth + 1);
       
   360 		AppendDateToValueL(aDateTime);
       
   361 		
       
   362 		iValue->Des().Append(KICalTimeChar);
       
   363 		AppendTimeToValueL(aDateTime);
       
   364 		
       
   365 		iValue->Des().Append(KICalUtcChar);	// For UTC Time.
       
   366 		}
       
   367 	else if (aTzType == ESpecifiedTimeZone || aTzType == EFloatingTime)
       
   368 		{
       
   369 		iValue = HBufC::NewL(KICalDateTimeWidth);
       
   370 		AppendDateToValueL(aDateTime);
       
   371 		
       
   372 		iValue->Des().Append(KICalTimeChar);
       
   373 		AppendTimeToValueL(aDateTime);
       
   374 		}
       
   375 	
       
   376 	TRACE_EXIT_POINT;
       
   377 	}
       
   378 
       
   379 /**
       
   380 Returns the CICalValue as a Duration (TTimeIntervalSeconds).
       
   381 @return TTimeInterval containing the value's duration.
       
   382 @publishedPartner
       
   383 */
       
   384 EXPORT_C TTimeIntervalSeconds CICalValue::DurationL() const
       
   385 	{
       
   386 	TRACE_ENTRY_POINT;
       
   387 	
       
   388 	CheckNullValueL();
       
   389 	TTimeIntervalSeconds theTis;
       
   390 	GetTimeIntervalFromValueL(theTis);
       
   391 	
       
   392     TRACE_EXIT_POINT;
       
   393 	return theTis;
       
   394 	}
       
   395 
       
   396 /**
       
   397 Stores a Duration (TTimeIntervalSeconds) as the value.
       
   398 @param aDuration TTimeIntervalSeconds to be stored.
       
   399 @publishedPartner
       
   400 */
       
   401 EXPORT_C void CICalValue::SetDurationL(TTimeIntervalSeconds aDuration)
       
   402 	{
       
   403 	TRACE_ENTRY_POINT;
       
   404 	
       
   405 	// e.g. P15DT5H0M20S
       
   406 	PrepareValuePointer();
       
   407 	
       
   408 	iValue = HBufC::NewL(KICalDurationWidth);
       
   409 	TInt durInt(aDuration.Int());
       
   410 	
       
   411 	if (durInt < 0)
       
   412 		{
       
   413 		// First character is a '-' for negative values
       
   414 		iValue->Des().Append(KICalNegativeChar);
       
   415 		
       
   416 		// Now we've set the sign, change the durInt to +ve
       
   417 		durInt =- durInt;
       
   418 		}
       
   419 		
       
   420 	iValue->Des().Append(KICalDurationChar);
       
   421 	
       
   422 	// Add day portion.
       
   423 	TInt numDays(durInt / KICalSecondsPerDay);
       
   424 	durInt -= (numDays * KICalSecondsPerDay);
       
   425 	iValue->Des().AppendNum(numDays);
       
   426 	iValue->Des().Append(KICalDayChar);
       
   427 	iValue->Des().Append(KICalTimeChar);
       
   428 	
       
   429 	// Add hour portion.
       
   430 	TInt numHours(durInt / KICalSecondsPerHour);
       
   431 	durInt -= (numHours * KICalSecondsPerHour);
       
   432 	iValue->Des().AppendNum(numHours);
       
   433 	iValue->Des().Append(KICalHourChar);
       
   434 	
       
   435 	// Add minute portion.
       
   436 	TInt numMinutes(durInt / KICalSecondsPerMinute);
       
   437 	durInt -= (numMinutes * KICalSecondsPerMinute);
       
   438 	iValue->Des().AppendNum(numMinutes);
       
   439 	iValue->Des().Append(KICalMinuteChar);
       
   440 	
       
   441 	// Add second portion.
       
   442 	TInt numSeconds(durInt);
       
   443 	iValue->Des().AppendNum(numSeconds);
       
   444 	iValue->Des().Append(KICalSecondChar);
       
   445 	
       
   446     TRACE_EXIT_POINT;
       
   447 	}
       
   448 
       
   449 /**
       
   450 Returns the CICalValue as a Float (TReal).
       
   451 @param aFloat The value to return.
       
   452 @leave Leaves if there is an error reading a float.
       
   453 @publishedPartner
       
   454 */
       
   455 EXPORT_C void CICalValue::GetFloatL(TReal& aFloat) const
       
   456 	{
       
   457     TRACE_ENTRY_POINT;
       
   458 	
       
   459 	CheckNullValueL();
       
   460 	TLex stringLex(iValue->Des());
       
   461 	User::LeaveIfError(stringLex.Val(aFloat));
       
   462 	
       
   463 	TRACE_EXIT_POINT;
       
   464 	}
       
   465 
       
   466 /**
       
   467 Stores a float (TReal) as the value.
       
   468 @param aFloat The value to store.
       
   469 @publishedPartner
       
   470 */
       
   471 EXPORT_C void CICalValue::SetFloatL(const TReal& aFloat)
       
   472 	{
       
   473 	TRACE_ENTRY_POINT;
       
   474 	
       
   475 	PrepareValuePointer();
       
   476 
       
   477 	iValue = HBufC::NewL(KDefaultRealWidth);
       
   478 	TRealFormat format;
       
   479 	iValue->Des().Num(aFloat, format);
       
   480 	
       
   481 	TRACE_EXIT_POINT;
       
   482 	}
       
   483 
       
   484 /**
       
   485 Returns the CICalValue as an Integer.
       
   486 @return The integer requested.
       
   487 @publishedPartner
       
   488 */
       
   489 EXPORT_C TInt CICalValue::IntegerL() const
       
   490 	{
       
   491 	TRACE_ENTRY_POINT;
       
   492 	
       
   493 	CheckNullValueL();
       
   494 	
       
   495 	TRACE_EXIT_POINT;
       
   496 	return ReadIntL(iValue->Des());
       
   497 	}
       
   498 
       
   499 /**
       
   500 Stores an Integer as the value.
       
   501 @param aInt The integer to be stored.
       
   502 @publishedPartner
       
   503 */
       
   504 EXPORT_C void CICalValue::SetIntegerL(TInt aInt)
       
   505 	{
       
   506 	TRACE_ENTRY_POINT;
       
   507 	
       
   508 	PrepareValuePointer();
       
   509 	iValue = HBufC::NewL(KICalTIntWidth);
       
   510 	iValue->Des().Num(aInt);
       
   511 	
       
   512 	TRACE_EXIT_POINT;
       
   513 	}
       
   514 
       
   515 /**
       
   516 Returns the CICalValue as a Period (two TTimes).
       
   517 @param aStartTime TTime marking the beginning of the period.
       
   518 @param aStartTzType Enumeration showing whether the start time represents local
       
   519 time (not supported), UTC or a custom time zone.
       
   520 @param aEndTime TTime marking the end of the period.
       
   521 @param aEndTzType Enumeration showing whether the end time represents local
       
   522 time (not supported), UTC or a custom time zone.
       
   523 @publishedPartner
       
   524 */
       
   525 EXPORT_C void CICalValue::GetPeriodL(
       
   526 	TTime& aStartTime, 
       
   527 	TTimeZoneType& aStartTzType, 
       
   528 	TTime& aEndTime, 
       
   529 	TTimeZoneType& aEndTzType) const
       
   530 	{
       
   531 	TRACE_ENTRY_POINT;
       
   532 	
       
   533 	// Example :   19970101T180000Z/19970102T070000Z
       
   534 	// that is : yyyymmddThhmmss[Z]/yyyymmddThhmmss[Z]
       
   535 	
       
   536 	// Example2:   19970101T180000Z/PT5H30M
       
   537 	// that is2: yyyymmddThhmmss[Z]/[+/-]P[lots of stuff]
       
   538 	
       
   539 	// As the first part is always a date-time, get this out to start off with
       
   540 	GetDateTimeL(aStartTime, aStartTzType, 0);
       
   541 	
       
   542 	// Next we need to get the position of the separator.
       
   543 	TInt charNumber(iValue->Des().Locate(KICalPeriodChar));
       
   544 	User::LeaveIfError(charNumber);
       
   545 	
       
   546 	// If the character after the separator is a 'P', '+' or '-' the second part is a duration.
       
   547 	++charNumber;
       
   548 	if (charNumber >= iValue->Length())
       
   549 		{
       
   550 		User::Leave(KErrCorrupt);
       
   551 		}
       
   552 		
       
   553 	TChar theChar(iValue->Des()[charNumber]);
       
   554 	
       
   555 	if ((theChar == KICalDurationChar) || 
       
   556 		(theChar == KICalPositiveChar) || 
       
   557 		(theChar == KICalNegativeChar))
       
   558 		{
       
   559 		// Call a function to change the duration into a TTime (date + time)
       
   560 		TTimeIntervalSeconds interval;
       
   561 		GetTimeIntervalFromValueL(interval, charNumber);
       
   562 		
       
   563 		// Convert from this TimeInterval to a TTime
       
   564 		aEndTime = aStartTime;
       
   565 		aEndTime += interval;
       
   566 		
       
   567 		// The timezone will be the same as the first.
       
   568 		aEndTzType = aStartTzType;
       
   569 		}
       
   570 	else // Presume it's a date-time
       
   571 		{
       
   572 		GetDateTimeL(aEndTime, aEndTzType, charNumber);
       
   573 		}
       
   574 	
       
   575 	TRACE_EXIT_POINT;
       
   576 	}
       
   577 
       
   578 /**
       
   579 Stores a Period (two TTimes) as the value.
       
   580 @param aStartTime TTime to be stored containing the beginning of the period.
       
   581 @param aStartTzType Enumeration showing whether the start time represents local
       
   582 time (not supported), UTC or a custom time zone.
       
   583 @param aEndTime TTime to be stored containing the end of the period.
       
   584 @param aEndTzType Enumeration showing whether the end time represents local
       
   585 time (not supported), UTC or a custom time zone.
       
   586 @publishedPartner
       
   587 */
       
   588 EXPORT_C void CICalValue::SetPeriodL(
       
   589 	const TTime& aStartTime, 
       
   590 	TTimeZoneType aStartTzType, 
       
   591 	const TTime& aEndTime, 
       
   592 	TTimeZoneType aEndTzType)
       
   593 	{
       
   594 	TRACE_ENTRY_POINT;
       
   595 	
       
   596 	// Example:   19970101T180000Z/19970102T070000Z
       
   597 	// that is: yyyymmddThhmmss[Z]/yyyymmddThhmmss[Z]
       
   598 	
       
   599 	PrepareValuePointer();
       
   600 
       
   601 	SetDateTimeL(aStartTime, aStartTzType);
       
   602 	
       
   603 	if (aEndTzType == EUtcTime)
       
   604 		{
       
   605 		iValue->ReAllocL(iValue->Length() + 2 + KICalDateTimeWidth);
       
   606 		iValue->Des().Append(KICalPeriodChar);
       
   607 		
       
   608 		AppendDateToValueL(aEndTime);
       
   609 		iValue->Des().Append(KICalTimeChar);
       
   610 		
       
   611 		AppendTimeToValueL(aEndTime);
       
   612 		iValue->Des().Append(KICalUtcChar);
       
   613 		}
       
   614 	else if (aEndTzType == ESpecifiedTimeZone || aEndTzType == EFloatingTime)
       
   615 		{
       
   616 		iValue->ReAllocL(iValue->Length() + 1 + KICalDateTimeWidth);
       
   617 		
       
   618 		iValue->Des().Append(KICalPeriodChar);
       
   619 		AppendDateToValueL(aEndTime);
       
   620 		
       
   621 		iValue->Des().Append(KICalTimeChar);
       
   622 		AppendTimeToValueL(aEndTime);
       
   623 		}
       
   624 	
       
   625 	TRACE_EXIT_POINT;
       
   626 	}
       
   627 
       
   628 /**
       
   629 Returns the value as an enumerated day and position.
       
   630 @param aDay A modifiable reference to an enumerated day.
       
   631 @param aPos A modifiable reference to a position.
       
   632 @leave KErrCorrupt if the day part is invalid.
       
   633 @publishedPartner
       
   634 */
       
   635 EXPORT_C void CICalValue::GetDayL(TDay& aDay, TInt& aPos) const
       
   636 	{
       
   637 	TRACE_ENTRY_POINT;
       
   638 	
       
   639 	CheckNullValueL();
       
   640 	
       
   641 	// Find the end of the numeric part.
       
   642 	_LIT(KICalDayNumeric, "-+0123456789");
       
   643 	TInt endNumeric(0);
       
   644 	
       
   645 	while (endNumeric < iValue->Length())
       
   646 		{
       
   647 		if (KICalDayNumeric().Locate((*iValue)[endNumeric]) == KErrNotFound)
       
   648 			{
       
   649 			break;
       
   650 			}
       
   651 			
       
   652 		++endNumeric;
       
   653 		}
       
   654 	
       
   655 	// Set the numeric part.	
       
   656 	if (endNumeric != 0)
       
   657 		{
       
   658 		aPos = ReadIntL(iValue->Left(endNumeric));
       
   659 		}
       
   660 	else
       
   661 		{
       
   662 		aPos = 0;
       
   663 		}
       
   664 	
       
   665 	// Set the day part.
       
   666 	TPtrC dayStr(iValue->Mid(endNumeric));
       
   667 			
       
   668 	if (dayStr.CompareF(KICalMonday) == 0)
       
   669 		{
       
   670 		aDay = EMonday;
       
   671 		}
       
   672 	else if (dayStr.CompareF(KICalTuesday) == 0)
       
   673 		{
       
   674 		aDay = ETuesday;
       
   675 		}
       
   676 	else if (dayStr.CompareF(KICalWednesday) == 0)
       
   677 		{
       
   678 		aDay = EWednesday;
       
   679 		}
       
   680 	else if (dayStr.CompareF(KICalThursday) == 0)
       
   681 		{
       
   682 		aDay = EThursday;
       
   683 		}
       
   684 	else if (dayStr.CompareF(KICalFriday) == 0)
       
   685 		{
       
   686 		aDay = EFriday;
       
   687 		}
       
   688 	else if (dayStr.CompareF(KICalSaturday) == 0)
       
   689 		{
       
   690 		aDay = ESaturday;
       
   691 		}
       
   692 	else if (dayStr.CompareF(KICalSunday) == 0)
       
   693 		{
       
   694 		aDay = ESunday;
       
   695 		}
       
   696 	else
       
   697 		{
       
   698 		User::Leave(KErrCorrupt);	// Invalid day.
       
   699 		}
       
   700 		
       
   701 	TRACE_EXIT_POINT;
       
   702 	}
       
   703 	
       
   704 /**
       
   705 Sets the value from an enumerated date and position.
       
   706 @param aDay The day to set.
       
   707 @param aPos The position to set.
       
   708 @leave Leaves with KErrUnknown if the value of aDay is not known.
       
   709 @publishedPartner
       
   710 */
       
   711 EXPORT_C void CICalValue::SetDayL(TDay aDay, TInt aPos)
       
   712 	{
       
   713 	TRACE_ENTRY_POINT;
       
   714 	
       
   715 	PrepareValuePointer();
       
   716 	
       
   717 	// Get the day as a descriptor.
       
   718 	TPtrC dayName;
       
   719 	
       
   720 	switch (aDay)
       
   721 		{
       
   722 		case EMonday:
       
   723 			dayName.Set(KICalMonday());
       
   724 			break;
       
   725 		case ETuesday:
       
   726 			dayName.Set(KICalTuesday());
       
   727 			break;
       
   728 		case EWednesday:
       
   729 			dayName.Set(KICalWednesday());
       
   730 			break;
       
   731 		case EThursday:
       
   732 			dayName.Set(KICalThursday());
       
   733 			break;
       
   734 		case EFriday:
       
   735 			dayName.Set(KICalFriday());
       
   736 			break;
       
   737 		case ESaturday:
       
   738 			dayName.Set(KICalSaturday());
       
   739 			break;
       
   740 		case ESunday:
       
   741 			dayName.Set(KICalSunday());
       
   742 			break;
       
   743 		default:
       
   744 			User::Leave(KErrUnknown);
       
   745 			break;
       
   746 		}
       
   747 		
       
   748 	// We need space for a number and a day name.
       
   749 	iValue = HBufC::NewL(KICalTIntWidth + dayName.Length());
       
   750 	iValue->Des().AppendNum(aPos);
       
   751 	iValue->Des().Append(dayName);
       
   752 	
       
   753 	TRACE_EXIT_POINT;
       
   754 	}
       
   755 
       
   756 /**
       
   757 Gets the value as a month.
       
   758 @return The month set in the value.
       
   759 @leave Leaves with KErrCorrupt if the value is not a valid month.
       
   760 @publishedPartner
       
   761 */
       
   762 EXPORT_C TMonth CICalValue::MonthL() const
       
   763 	{
       
   764 	TRACE_ENTRY_POINT;
       
   765 	
       
   766 	CheckNullValueL();
       
   767 	
       
   768 	TInt num(IntegerL());
       
   769 	
       
   770 	if ((num < 1) || (num > 12))
       
   771 		{
       
   772 		User::Leave(KErrCorrupt);
       
   773 		}
       
   774 
       
   775     TRACE_EXIT_POINT;
       
   776 	return static_cast<TMonth>(num - 1);
       
   777 	}
       
   778 
       
   779 /**
       
   780 Sets a month as the value.
       
   781 @param aMonth The month to set.
       
   782 @publishedPartner
       
   783 */
       
   784 EXPORT_C void CICalValue::SetMonthL(TMonth aMonth)
       
   785 	{
       
   786 	TRACE_ENTRY_POINT;
       
   787 	
       
   788 	PrepareValuePointer();
       
   789 	SetIntegerL(aMonth + 1);
       
   790 	
       
   791     TRACE_EXIT_POINT;
       
   792 	}
       
   793 	
       
   794 /**
       
   795 Returns the value as an array of CICalRuleSegments. Assumes that all escaping
       
   796 has been previously removed.
       
   797 @param aRuleSegmentArray The array that the segments are appended to.
       
   798 @leave Leaves if there is an error adding a rule segment to the array.
       
   799 @publishedPartner
       
   800 */
       
   801 EXPORT_C void CICalValue::GetRecurrenceRuleL(RPointerArray<CICalRuleSegment>& aRuleSegmentArray) const
       
   802 	{
       
   803 	TRACE_ENTRY_POINT;
       
   804 	
       
   805 	CheckNullValueL();
       
   806 	
       
   807 	// Find the first semicolon:
       
   808 	TInt nextSemiColon(iValue->Locate(KICalSemiColonChar));
       
   809 
       
   810 	if (nextSemiColon == KErrNotFound)
       
   811 		{
       
   812 		// This means there is only one segment, pretend the semicolon exists at the end of the buffer
       
   813 		nextSemiColon = iValue->Length();
       
   814 		}
       
   815 		
       
   816 	TUint charNum(0);
       
   817 	
       
   818 	do
       
   819 		{
       
   820 		// Create a rule segment from characters charNum to nextSemiColon
       
   821 		CICalRuleSegment* theRule = CICalRuleSegment::NewLC(iValue->Mid(charNum, nextSemiColon - charNum));
       
   822 		User::LeaveIfError(aRuleSegmentArray.Append(theRule));	// Takes ownership.
       
   823 		CleanupStack::Pop(theRule);
       
   824 		
       
   825 		// Put the character marker past the current semicolon
       
   826 		charNum = nextSemiColon + 1;
       
   827 		
       
   828 		// We only want to check for any more semicolons in the area to the right of charNum.
       
   829 		// First check if there are ANY characters to the right of charNum
       
   830 		if (charNum < iValue->Length())
       
   831 			{
       
   832 			// Find the location of the next semi colon in this area.
       
   833 			nextSemiColon = iValue->Right(iValue->Length() - charNum).Locate(KICalSemiColonChar);
       
   834 			
       
   835 			if (nextSemiColon != KErrNotFound)
       
   836 				{
       
   837 				// Set the semicolon to be in it's correct position, shifted to take into account the fact
       
   838 				// that we were only looking in the right part of the original descriptor.
       
   839 				nextSemiColon += charNum;
       
   840 				}
       
   841 			else
       
   842 				{
       
   843 				// There are no more semicolons, read in the last value and then exit the loop
       
   844 				nextSemiColon = iValue->Length();
       
   845 				}
       
   846 			}
       
   847 		}
       
   848 	while (charNum < iValue->Length());
       
   849 	
       
   850 	TRACE_EXIT_POINT;
       
   851 	}
       
   852 
       
   853 /**
       
   854 Sets a complete RRULE as a descriptor value. Note that this is no different
       
   855 than setting as text and is only supplied for symmetry.
       
   856 @param aRuleValue The descriptor containing the complete RRULE.
       
   857 @publishedPartner
       
   858 */
       
   859 EXPORT_C void CICalValue::SetRecurrenceRuleL(const TDesC& aRuleValue)
       
   860 	{
       
   861 	TRACE_ENTRY_POINT;
       
   862 	
       
   863 	PrepareValuePointer();
       
   864 	iValue = aRuleValue.AllocL();
       
   865 	
       
   866 	TRACE_EXIT_POINT;
       
   867 	}
       
   868 
       
   869 /**
       
   870 Returns the CICalValue as text.
       
   871 @return The value as text.
       
   872 @publishedPartner
       
   873 */
       
   874 EXPORT_C const TDesC& CICalValue::TextL() const
       
   875 	{
       
   876 	TRACE_ENTRY_POINT;
       
   877 	
       
   878 	CheckNullValueL();
       
   879 	
       
   880 	TRACE_EXIT_POINT;
       
   881 	return *iValue;
       
   882 	}
       
   883 
       
   884 /**
       
   885 Stores text as the value.
       
   886 @param aText The text to be stored.
       
   887 @publishedPartner
       
   888 */
       
   889 EXPORT_C void CICalValue::SetTextL(const TDesC& aText)
       
   890 	{
       
   891 	TRACE_ENTRY_POINT;
       
   892 	
       
   893 	PrepareValuePointer();
       
   894 	iValue = aText.AllocL();
       
   895 	
       
   896 	TRACE_EXIT_POINT;
       
   897 	}
       
   898 
       
   899 /**
       
   900 Returns the CICalValue as a UTC Offset (TTimeIntervalSeconds).
       
   901 @return TTimeIntervalSeconds containing the offset.
       
   902 @leave Leaves with KErrCorrupt if the value is invalid.
       
   903 @publishedPartner
       
   904 */
       
   905 EXPORT_C TTimeIntervalSeconds CICalValue::UtcOffsetL() const
       
   906 	{
       
   907 	TRACE_ENTRY_POINT;
       
   908 	
       
   909 	// Format is (e.g.) +1000 (10 hours ahead) or -013045 (1.5 hours and 45 seconds behind).
       
   910 	CheckNullValueL();
       
   911 
       
   912 	const TInt length = iValue->Length();
       
   913 	
       
   914 	if ((length != KLongFormatUtcOffsetWidth) && (length != KShortFormatUtcOffsetWidth))
       
   915 		{
       
   916 		// Invalid UTC Offset - we can't really test more than this, so the output may be garbage!
       
   917 		User::Leave(KErrCorrupt);
       
   918 		}
       
   919 		
       
   920 	// Get the value of the hour component.
       
   921 	TInt hours(ReadIntL(iValue->Des().Left(3)));	// '+' or '-' plus the hours component.
       
   922 
       
   923 	// Get the value of the minute component.
       
   924 	TInt minutes(ReadIntL(iValue->Des().Mid(3, 2)));	// The minutes component.
       
   925 	
       
   926 	// Get the value of the (optional) second component.
       
   927 	TInt seconds(0);
       
   928 	
       
   929 	if (length == KLongFormatUtcOffsetWidth)	// Long format.
       
   930 		{
       
   931 		seconds = ReadIntL(iValue->Des().Mid(5, 2));	// The second component.
       
   932 		}
       
   933 		
       
   934 	// Convert to TTimeIntervalSeconds.
       
   935 	TRACE_EXIT_POINT;
       
   936 	return TTimeIntervalSeconds((hours * KICalSecondsPerHour) + (minutes * KICalSecondsPerMinute) + seconds);
       
   937 	}
       
   938 
       
   939 /**
       
   940 Stores a UTC Offset (TTimeIntervalSeconds) as the value.
       
   941 @param aOffset TTimeInterval to set as the offset.
       
   942 @publishedPartner
       
   943 */
       
   944 EXPORT_C void CICalValue::SetUtcOffsetL(TTimeIntervalSeconds aOffset)
       
   945 	{
       
   946 	TRACE_ENTRY_POINT;
       
   947 	
       
   948 	// Format is (e.g.) +1000 (10 hours ahead) or -013045 (1.5 hours and 45 seconds behind).
       
   949 	PrepareValuePointer();
       
   950 	
       
   951 	// Create a buffer long enough to hold the widest format.
       
   952 	iValue = HBufC::NewL(KLongFormatUtcOffsetWidth);
       
   953 
       
   954 	// Get the offset as an integer.
       
   955 	TInt offset(aOffset.Int());
       
   956 
       
   957 	// Set the sign.	
       
   958 	if (offset < 0)
       
   959 		{
       
   960 		iValue->Des().Append(KICalNegativeChar);
       
   961 		
       
   962 		// Set offset to positive for calculations.
       
   963 		offset =- offset;
       
   964 		}
       
   965 	else
       
   966 		{
       
   967 		iValue->Des().Append(KICalPositiveChar);
       
   968 		}
       
   969 		
       
   970 	// Add hour portion.
       
   971 	TInt numHours(offset / KICalSecondsPerHour);
       
   972 	offset -= (numHours * KICalSecondsPerHour);
       
   973 	iValue->Des().AppendNumFixedWidth(numHours, EDecimal, 2);
       
   974 	
       
   975 	// Add minute portion.
       
   976 	TInt numMinutes(offset / KICalSecondsPerMinute);
       
   977 	offset -= (numMinutes * KICalSecondsPerMinute);
       
   978 	iValue->Des().AppendNumFixedWidth(numMinutes, EDecimal, 2);
       
   979 	
       
   980 	// Add second portion if necessary.
       
   981 	if (offset > 0)
       
   982 		{
       
   983 		iValue->Des().AppendNumFixedWidth(offset, EDecimal, 2);
       
   984 		}
       
   985 		
       
   986 	TRACE_EXIT_POINT;
       
   987 	}
       
   988 
       
   989 /**
       
   990 Constructor.
       
   991 @internalTechnology
       
   992 */
       
   993 CICalValue::CICalValue()
       
   994 	{
       
   995 	TRACE_ENTRY_POINT;
       
   996 	TRACE_EXIT_POINT;
       
   997 	}
       
   998 	
       
   999 /**
       
  1000 Internal construction.
       
  1001 @internalTechnology
       
  1002 */
       
  1003 void CICalValue::ConstructL()
       
  1004 	{
       
  1005 	TRACE_ENTRY_POINT;
       
  1006 	TRACE_EXIT_POINT;
       
  1007 	}
       
  1008 
       
  1009 /**
       
  1010 Checks for a NULL value. Should be called before accessing iValue. 
       
  1011 @leave Leaves with KErrCorrupt if the value is NULL.
       
  1012 @internalTechnology
       
  1013 */
       
  1014 void CICalValue::CheckNullValueL() const
       
  1015 	{
       
  1016 	TRACE_ENTRY_POINT;
       
  1017 	
       
  1018 	if (!iValue)
       
  1019 		{
       
  1020 		User::Leave(KErrCorrupt);
       
  1021 		}
       
  1022 	
       
  1023 	TRACE_EXIT_POINT;
       
  1024 	}
       
  1025 
       
  1026 /**
       
  1027 Prepares iValue pointer for writing. Deletes existing pointer if it exists.
       
  1028 @internalTechnology
       
  1029 */
       
  1030 void CICalValue::PrepareValuePointer()
       
  1031 	{
       
  1032 	TRACE_ENTRY_POINT;
       
  1033 	
       
  1034 	if (iValue)
       
  1035 		{
       
  1036 		delete iValue;
       
  1037 		iValue = NULL;
       
  1038 		}
       
  1039 		
       
  1040 	TRACE_EXIT_POINT;
       
  1041 	}
       
  1042 	
       
  1043 /**
       
  1044 Reads a TInt from the given descriptor.
       
  1045 @param aDes The descriptor to convert
       
  1046 @return The integer conversion.
       
  1047 @leave Leaves if there is an error reading an integer.
       
  1048 @internalTechnology
       
  1049 */
       
  1050 TInt CICalValue::ReadIntL(const TDesC& aDes) const
       
  1051 	{
       
  1052 	TRACE_ENTRY_POINT;
       
  1053 	
       
  1054 	TLex stringLex(aDes);
       
  1055 	TInt returnValue(0);
       
  1056 	User::LeaveIfError(stringLex.Val(returnValue));
       
  1057 	
       
  1058 	TRACE_EXIT_POINT;
       
  1059 	return returnValue;
       
  1060 	}
       
  1061 	
       
  1062 /**
       
  1063 Appends the date to iValue. Member iValue must be initialised before calling.
       
  1064 @param aDate TTime to append to the value.
       
  1065 @internalTechnology
       
  1066 */
       
  1067 void CICalValue::AppendDateToValueL(const TTime& aDate)
       
  1068 	{
       
  1069 	TRACE_ENTRY_POINT;
       
  1070 	
       
  1071 	TBuf<KICalDateWidth> formattedDate;
       
  1072 	aDate.FormatL(formattedDate, KICalDateFormat);
       
  1073 	iValue->Des().Append(formattedDate);
       
  1074 	
       
  1075 	TRACE_EXIT_POINT;
       
  1076 	}
       
  1077 
       
  1078 /**
       
  1079 Gets the date from iValue descriptor. Should be in the format YYYYMMDD
       
  1080 @param aDate A modifiable reference returning a date.
       
  1081 @param aFirstCharacterNum Skip this many characters at the start of the value.
       
  1082 @leave Leaves with KErrCorrupt if the format of the value is not a valid date.
       
  1083 @internalTechnology
       
  1084 */
       
  1085 void CICalValue::GetDateFromValueL(TTime& aDate, TInt aFirstCharacterNum) const
       
  1086 	{
       
  1087 	TRACE_ENTRY_POINT;
       
  1088 	
       
  1089 	if (aFirstCharacterNum + KICalDateWidth > iValue->Length())
       
  1090 		{
       
  1091 		User::Leave(KErrCorrupt);
       
  1092 		}
       
  1093 	
       
  1094 	// Get the year as an int.
       
  1095 	TInt year(ReadIntL(iValue->Des().Mid(aFirstCharacterNum, 4)));	// YYYYmmdd
       
  1096 	
       
  1097 	if (year < 0)	// All positive years are valid!
       
  1098 		{
       
  1099 		User::Leave(KErrCorrupt);
       
  1100 		}
       
  1101 
       
  1102 	// Get the month as an int.
       
  1103 	TInt month(ReadIntL(iValue->Mid(aFirstCharacterNum + 4, 2)));	// yyyMMdd
       
  1104 	
       
  1105 	if ((month < 1) || (month > 12))
       
  1106 		{
       
  1107 		User::Leave(KErrCorrupt);
       
  1108 		}
       
  1109 		
       
  1110 	// Get the day as an int.
       
  1111 	TInt day(ReadIntL(iValue->Mid(aFirstCharacterNum + 6, 2)));	// yyyymmDD
       
  1112 
       
  1113 	if ((day < 1) || (day > Time::DaysInMonth(year, static_cast<TMonth>(month - 1))))	// Zero-offset month.
       
  1114 		{
       
  1115 		User::Leave(KErrCorrupt);
       
  1116 		}
       
  1117 		
       
  1118 	// Set the date from its component parts.
       
  1119 	aDate = 0;
       
  1120 	aDate += TTimeIntervalYears(year);
       
  1121 	aDate += TTimeIntervalMonths(month - 1);	// Zero-offset.
       
  1122 	aDate += TTimeIntervalDays(day - 1);		// Zero-offset.
       
  1123 	
       
  1124 	TRACE_EXIT_POINT;
       
  1125 	}
       
  1126 
       
  1127 /**
       
  1128 Appends the time to iValue. Member iValue must be initialised before calling.
       
  1129 @param aTime TTime to append to the value.
       
  1130 @internalTechnology
       
  1131 */
       
  1132 void CICalValue::AppendTimeToValueL(const TTime& aTime)
       
  1133 	{
       
  1134 	TRACE_ENTRY_POINT;
       
  1135 	
       
  1136 	// Format is HHMMSS followed optionally by a Z for UTC time.
       
  1137 	// Note that the 'Z' is not appended here.
       
  1138 	TDateTime fullTime(aTime.DateTime());
       
  1139 	
       
  1140 	iValue->Des().AppendNumFixedWidth(fullTime.Hour(), EDecimal, 2);
       
  1141 	iValue->Des().AppendNumFixedWidth(fullTime.Minute(), EDecimal, 2);
       
  1142 	iValue->Des().AppendNumFixedWidth(fullTime.Second(), EDecimal, 2);
       
  1143 	
       
  1144 	TRACE_EXIT_POINT;
       
  1145 	}
       
  1146 	
       
  1147 /**
       
  1148 Gets the time from iValue descriptor, starting from a pre-determined point.
       
  1149 Should be in the format HHMMSS[Z]
       
  1150 @param aTime TTime to store result of read in
       
  1151 @param aTzType Enumeration showing whether the time represents local time (not
       
  1152 supported), UTC or a custom time zone.
       
  1153 @param aFirstCharacterNum The character number to start searching from.
       
  1154 @leave Leaves with KErrCorrupt if the value does not hold a valid time.
       
  1155 @internalTechnology
       
  1156 */
       
  1157 void CICalValue::GetTimeFromValueL(TTime& aTime, TTimeZoneType& aTzType, TInt aFirstCharacterNum) const
       
  1158 	{
       
  1159 	TRACE_ENTRY_POINT;
       
  1160 	
       
  1161 	if (aFirstCharacterNum + KICalTimeWidth > iValue->Length())
       
  1162 		{
       
  1163 		User::Leave(KErrCorrupt);
       
  1164 		}
       
  1165 
       
  1166 	// Create a new descriptor containing just the first KICalTimeWidth characters of iValue
       
  1167 	// It's size is one larger as we will need to add a full stop (see below)
       
  1168 	HBufC* formattedTime = HBufC::NewLC(iValue->Des().Mid(aFirstCharacterNum, KICalTimeWidth).Length() + 1);
       
  1169 	*formattedTime = iValue->Des().Mid(aFirstCharacterNum, KICalTimeWidth);
       
  1170 	
       
  1171 	// The only formatting needed is to append a full stop
       
  1172 	formattedTime->Des().Append(KICalMicroChar);
       
  1173 	
       
  1174 	if (aTime.Set(*formattedTime))
       
  1175 		{
       
  1176 		User::Leave(KErrCorrupt);
       
  1177 		}
       
  1178 	
       
  1179 	if ((iValue->Length() > (KICalTimeWidth + aFirstCharacterNum)) && 
       
  1180 		(iValue->Des()[KICalTimeWidth + aFirstCharacterNum] == KICalUtcChar))
       
  1181 		{
       
  1182 		aTzType = EUtcTime;
       
  1183 		}
       
  1184 	else
       
  1185 		{//DAVIDTODO:
       
  1186 		// If there is no 'Z' character then assume that there
       
  1187 		// is a specified time zone - EFloatingTime is not used.
       
  1188 		aTzType = ESpecifiedTimeZone;
       
  1189 		}
       
  1190 	
       
  1191 	CleanupStack::PopAndDestroy(formattedTime);
       
  1192 	
       
  1193 	TRACE_EXIT_POINT;
       
  1194 	}
       
  1195 
       
  1196 /**
       
  1197 Retrieves a time interval stored as a duration as per the RFC 2445
       
  1198 specification.
       
  1199 @param aTimeInterval TTimeIntervalSeconds to store the result in.
       
  1200 @param aFirstCharacterNum The position in the value containing the first
       
  1201 character of the duration.
       
  1202 @leave Leaves with KErrCorrupt if the value does not hold a valid interval.
       
  1203 @internalTechnology
       
  1204 */
       
  1205 void CICalValue::GetTimeIntervalFromValueL(TTimeIntervalSeconds& aTimeInterval, TInt aFirstCharacterNum) const
       
  1206 	{
       
  1207 	TRACE_ENTRY_POINT;
       
  1208 	
       
  1209 	//     dur-value  = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
       
  1210 	//     dur-date   = dur-day [dur-time]
       
  1211 	//     dur-time   = "T" (dur-hour / dur-minute / dur-second)
       
  1212 	//     dur-week   = 1*DIGIT "W"
       
  1213 	//     dur-hour   = 1*DIGIT "H" [dur-minute]
       
  1214 	//     dur-minute = 1*DIGIT "M" [dur-second]
       
  1215 	//     dur-second = 1*DIGIT "S"
       
  1216 	//     dur-day    = 1*DIGIT "D"
       
  1217 
       
  1218 	// Example: A duration of 15 days, 5 hours and 20 seconds would be:
       
  1219 	//     P15DT5H0M20S
       
  1220 	// A duration of 7 weeks would be:
       
  1221 	//     P7W
       
  1222 	
       
  1223 	TInt intervalMultiplier(1); // This variable sets the interval to be positive or negative.
       
  1224 
       
  1225 	// Length should be at least two.
       
  1226 	if ((aFirstCharacterNum >= iValue->Length()) || (iValue->Length() < 2 + aFirstCharacterNum))
       
  1227 		{
       
  1228 		User::Leave(KErrCorrupt);
       
  1229 		}
       
  1230 
       
  1231 	// Check that the first character is a 'P', '+' or '-' and adjust the interval accordingly.
       
  1232 	TChar firstCharacter(iValue->Des()[aFirstCharacterNum]);
       
  1233 	
       
  1234 	if (firstCharacter == KICalDurationChar)
       
  1235 		{
       
  1236 		intervalMultiplier = 1;
       
  1237 		aFirstCharacterNum += 1; // Skip the "P"
       
  1238 		}
       
  1239 	else if (firstCharacter == KICalPositiveChar)
       
  1240 		{
       
  1241 		intervalMultiplier = 1;
       
  1242 		aFirstCharacterNum += 2; // Skip the "+P"
       
  1243 		}
       
  1244 	else if (firstCharacter == KICalNegativeChar)
       
  1245 		{
       
  1246 		intervalMultiplier = -1;
       
  1247 		aFirstCharacterNum += 2; // Skip the "-P"
       
  1248 		}
       
  1249 	else
       
  1250 		{
       
  1251 		User::Leave(KErrCorrupt);
       
  1252 		}
       
  1253 	
       
  1254 	// It can only contain a dur-date, or a dur-time, or a dur-week
       
  1255 	TInt theInterval(0);
       
  1256 	if (!GetDurDateL(theInterval, aFirstCharacterNum))
       
  1257 		{
       
  1258 		if (!GetDurTimeL(theInterval, aFirstCharacterNum))
       
  1259 			{
       
  1260 			if (!GetDurWeekL(theInterval, aFirstCharacterNum))
       
  1261 				{
       
  1262 				User::Leave(KErrCorrupt);
       
  1263 				}
       
  1264 			}
       
  1265 		}
       
  1266 		
       
  1267 	theInterval *= intervalMultiplier;
       
  1268 	
       
  1269 	// Now we've done the multiply we can convert it into a TTimeIntervalSeconds
       
  1270 	aTimeInterval = theInterval;
       
  1271 	TRACE_EXIT_POINT;
       
  1272 	}
       
  1273 
       
  1274 /**
       
  1275 Reads in and converts a dur-day into a number of seconds
       
  1276 @param aIntervalSecs Function adds number of seconds to this variable.
       
  1277 @param aCurrentCharNumber Character number to start looking in the value.
       
  1278 @return ETrue if the value could be interpreted as a dur-date, EFalse otherwise.
       
  1279 @internalTechnology
       
  1280 */
       
  1281 TBool CICalValue::GetDurDateL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
       
  1282 	{
       
  1283 	TRACE_ENTRY_POINT;
       
  1284 	
       
  1285 	//	dur-date   = dur-day [dur-time]
       
  1286 	//	dur-day    = 1*DIGIT "D"
       
  1287 	
       
  1288 	if (aCurrentCharNumber >= iValue->Length())
       
  1289 		{
       
  1290 		TRACE_EXIT_POINT;
       
  1291 		return EFalse;
       
  1292 		}
       
  1293 		
       
  1294 	// Create a new TPtrC containing the data from iValue which we need.
       
  1295 	TPtrC data(iValue->Mid(aCurrentCharNumber));
       
  1296 	
       
  1297 	// Find the next 'D' in the descriptor.
       
  1298 	TInt nextDPos(data.Locate(KICalDayChar));
       
  1299 	
       
  1300 	// Check it exists
       
  1301 	if (nextDPos != KErrNotFound)
       
  1302 		{
       
  1303 		// If character found, construct a number from currentCharNumber to nextDPos
       
  1304 		TInt theNum(ReadIntL(data.Left(nextDPos)));
       
  1305 
       
  1306 		// Convert this time from days to seconds
       
  1307 		theNum *= KICalSecondsPerDay;
       
  1308 		aIntervalSecs += theNum;
       
  1309 		aCurrentCharNumber += nextDPos + 1; // Extra increment to get past the 'D'
       
  1310 		
       
  1311 		// Check if a dur-time follows. It's optional
       
  1312 		// so we can ignore it's return value.
       
  1313 		GetDurTimeL(aIntervalSecs, aCurrentCharNumber);
       
  1314 		TRACE_EXIT_POINT;
       
  1315 		return ETrue;
       
  1316 		}
       
  1317 
       
  1318 	// If no character found, return EFalse
       
  1319 	TRACE_EXIT_POINT;
       
  1320 	return EFalse;
       
  1321 	}
       
  1322 
       
  1323 /**
       
  1324 Reads in and converts a dur-time into a number of seconds
       
  1325 @param aIntervalSecs Function adds number of seconds to this variable.
       
  1326 @param aCurrentCharNumber Character number to start looking in the value.
       
  1327 @return ETrue if the value could be interpreted as a dur-time, EFalse otherwise.
       
  1328 @leave Leaves with KErrCorrupt if the value does not hold a valid time.
       
  1329 @internalTechnology
       
  1330 */
       
  1331 TBool CICalValue::GetDurTimeL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
       
  1332 	{
       
  1333 	TRACE_ENTRY_POINT;
       
  1334 	
       
  1335 	//	dur-time   = "T" (dur-hour / dur-minute / dur-second) e.g. T5H0M20S
       
  1336 
       
  1337 	if (aCurrentCharNumber >= iValue->Length())
       
  1338 		{
       
  1339 		TRACE_EXIT_POINT;
       
  1340 		return EFalse;
       
  1341 		}
       
  1342 
       
  1343 	if (iValue->Des()[aCurrentCharNumber] == KICalTimeChar)
       
  1344 		{
       
  1345 		++aCurrentCharNumber; // Increment to get past 'T'
       
  1346 		
       
  1347 		if (!GetDurHourL(aIntervalSecs, aCurrentCharNumber))
       
  1348 			{
       
  1349 			if (!GetDurMinuteL(aIntervalSecs, aCurrentCharNumber))
       
  1350 				{
       
  1351 				if (!GetDurSecondL(aIntervalSecs, aCurrentCharNumber))
       
  1352 					{
       
  1353 					// We should not have read a 'T' and failed to match hour/minute/second
       
  1354 					User::Leave(KErrCorrupt);
       
  1355 					}
       
  1356 				}
       
  1357 			}
       
  1358 		}
       
  1359 	else
       
  1360 		{
       
  1361 		// First character is not a 'T', therefore value is not a dur-time
       
  1362 		TRACE_EXIT_POINT;
       
  1363 		return EFalse;
       
  1364 		}
       
  1365 		
       
  1366 	TRACE_EXIT_POINT;
       
  1367 	return ETrue;
       
  1368 	}
       
  1369 	
       
  1370 /**
       
  1371 Reads in and converts a dur-hour into a number of seconds. There is no range
       
  1372 check on the number of hours.
       
  1373 @param aIntervalSecs Function adds number of seconds to this variable.
       
  1374 @param aCurrentCharNumber Character number to start looking in the value.
       
  1375 @return ETrue if the value could be interpreted as a dur-hour, EFalse otherwise.
       
  1376 @internalTechnology
       
  1377 */
       
  1378 TBool CICalValue::GetDurHourL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
       
  1379 	{
       
  1380 	TRACE_ENTRY_POINT;
       
  1381 	
       
  1382 	//	dur-hour   = 1*DIGIT "H" [dur-minute]
       
  1383 	
       
  1384 	if (aCurrentCharNumber >= iValue->Length())
       
  1385 		{
       
  1386 		TRACE_EXIT_POINT;
       
  1387 		return EFalse;
       
  1388 		}
       
  1389 
       
  1390 	// Create a new TPtrC containing the data from iValue which we need
       
  1391 	TPtrC data(iValue->Mid(aCurrentCharNumber));
       
  1392 	
       
  1393 	// Find the next 'H' in the descriptor
       
  1394 	TInt nextHPos(data.Locate(KICalHourChar));
       
  1395 	
       
  1396 	// Check it exists
       
  1397 	if (nextHPos != KErrNotFound)
       
  1398 		{
       
  1399 		// If character found, construct a number from currentCharNumber to nextHPos
       
  1400 		TInt theNum(ReadIntL(data.Left(nextHPos)));
       
  1401 		
       
  1402 		// Convert this time from hours to seconds
       
  1403 		theNum *= KICalSecondsPerHour;
       
  1404 		
       
  1405 		aIntervalSecs += theNum;
       
  1406 		aCurrentCharNumber += nextHPos + 1; // Extra increment to get past 'H'
       
  1407 		
       
  1408 		// Check if a dur-minute follows. It's optional
       
  1409 		// so we can ignore it's return value.
       
  1410 		GetDurMinuteL(aIntervalSecs,aCurrentCharNumber);
       
  1411 		TRACE_EXIT_POINT;
       
  1412 		return ETrue;
       
  1413 		}
       
  1414 
       
  1415 	// If no character found, return EFalse
       
  1416 	TRACE_EXIT_POINT;
       
  1417 	return EFalse;
       
  1418 	}
       
  1419 
       
  1420 /**
       
  1421 Reads in and converts a dur-minute into a number of seconds. There is no range
       
  1422 check on the number of minutes.
       
  1423 @param aIntervalSecs Function adds number of seconds to this variable.
       
  1424 @param aCurrentCharNumber Character number to start looking in the value.
       
  1425 @return ETrue if the value could be interpreted as a dur-minute, EFalse
       
  1426 otherwise.
       
  1427 @internalTechnology
       
  1428 */
       
  1429 TBool CICalValue::GetDurMinuteL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
       
  1430 	{
       
  1431 	TRACE_ENTRY_POINT;
       
  1432 	
       
  1433 	//	dur-minute = 1*DIGIT "M" [dur-second]
       
  1434 
       
  1435 	if (aCurrentCharNumber >= iValue->Length())
       
  1436 		{
       
  1437 		TRACE_EXIT_POINT;
       
  1438 		return EFalse;
       
  1439 		}
       
  1440 
       
  1441 	// Create a new TPtrC containing the data from iValue which we need
       
  1442 	TPtrC data(iValue->Mid(aCurrentCharNumber));
       
  1443 	
       
  1444 	// Find the next 'M' in the descriptor
       
  1445 	TInt nextMPos(data.Locate(KICalMinuteChar));
       
  1446 	
       
  1447 	// Check it exists
       
  1448 	if (nextMPos != KErrNotFound)
       
  1449 		{
       
  1450 		// If character found, construct a number from currentCharNumber to nextMPos
       
  1451 		TInt theNum(ReadIntL(data.Left(nextMPos)));
       
  1452 
       
  1453 		// Convert this time from minutes to seconds
       
  1454 		theNum *= KICalSecondsPerMinute;
       
  1455 		
       
  1456 		aIntervalSecs += theNum;
       
  1457 		aCurrentCharNumber += nextMPos + 1; // Extra increment to get past 'M'
       
  1458 		
       
  1459 		// Check if a dur-second follows. It's optional
       
  1460 		// so we can ignore it's return value.
       
  1461 		GetDurSecondL(aIntervalSecs,aCurrentCharNumber);
       
  1462 		TRACE_EXIT_POINT;
       
  1463 		return ETrue;
       
  1464 		}
       
  1465 
       
  1466 	// If no character found, return EFalse
       
  1467 	TRACE_EXIT_POINT;
       
  1468 	return EFalse;
       
  1469 	}
       
  1470 		
       
  1471 /**
       
  1472 Reads in and converts a dur-second into a number of seconds. There is no range
       
  1473 check on the number of seconds.
       
  1474 @param aIntervalSecs Function adds number of seconds to this variable.
       
  1475 @param aCurrentCharNumber Character number to start looking in the value.
       
  1476 @return ETrue if the value could be interpreted as a dur-second, EFalse
       
  1477 otherwise.
       
  1478 @internalTechnology
       
  1479 */
       
  1480 TBool CICalValue::GetDurSecondL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
       
  1481 	{
       
  1482 	TRACE_ENTRY_POINT;
       
  1483 	
       
  1484 	//	dur-second = 1*DIGIT "S"
       
  1485 
       
  1486 	if (aCurrentCharNumber >= iValue->Length())
       
  1487 		{
       
  1488 		TRACE_EXIT_POINT;
       
  1489 		return EFalse;
       
  1490 		}
       
  1491 
       
  1492 	// Create a new TPtrC containing the data from iValue which we need
       
  1493 	TPtrC data(iValue->Mid(aCurrentCharNumber));
       
  1494 	
       
  1495 	// Find the next 'S' in the descriptor
       
  1496 	TInt nextSPos(data.Locate(KICalSecondChar));
       
  1497 	
       
  1498 	// Check it exists
       
  1499 	if (nextSPos != KErrNotFound)
       
  1500 		{
       
  1501 		// If character found, construct a number from currentCharNumber to nextSPos
       
  1502 		TInt theNum(ReadIntL(data.Left(nextSPos)));
       
  1503 		
       
  1504 		aIntervalSecs += theNum;
       
  1505 		aCurrentCharNumber += nextSPos;
       
  1506 		
       
  1507 		TRACE_EXIT_POINT;
       
  1508 		return ETrue;
       
  1509 		}
       
  1510 
       
  1511 	// If no character found, return EFalse
       
  1512 	TRACE_EXIT_POINT;
       
  1513 	return EFalse;
       
  1514 	}
       
  1515 
       
  1516 /**
       
  1517 Reads in and converts a dur-week into a number of seconds
       
  1518 @param aIntervalSecs Function adds number of seconds to this variable
       
  1519 @param aCurrentCharNumber Character number to start looking in the value.
       
  1520 @return ETrue if the value could be interpreted as a dur-week, EFalse
       
  1521 otherwise.
       
  1522 @internalTechnology
       
  1523 */
       
  1524 TBool CICalValue::GetDurWeekL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
       
  1525 	{
       
  1526 	TRACE_ENTRY_POINT;
       
  1527 	
       
  1528 	//	dur-week   = 1*DIGIT "W"
       
  1529 	
       
  1530 	if (aCurrentCharNumber >= iValue->Length())
       
  1531 		{
       
  1532 		TRACE_EXIT_POINT;
       
  1533 		return EFalse;
       
  1534 		}
       
  1535 
       
  1536 	// Create a new TPtrC containing the data from iValue which we need
       
  1537 	TPtrC data(iValue->Mid(aCurrentCharNumber));
       
  1538 	
       
  1539 	// Find the next 'W' in the descriptor
       
  1540 	TInt nextWPos(data.Locate(KICalWeekChar));
       
  1541 	
       
  1542 	// Check it exists
       
  1543 	if (nextWPos != KErrNotFound)
       
  1544 		{
       
  1545 		// If character found, construct a number from currentCharNumber to nextWPos
       
  1546 		TInt theNum(ReadIntL(data.Left(nextWPos)));
       
  1547 		
       
  1548 		// Convert this time from weeks to seconds
       
  1549 		theNum *= KICalSecondsPerWeek;
       
  1550 		
       
  1551 		aIntervalSecs += theNum;
       
  1552 		aCurrentCharNumber += nextWPos;
       
  1553 		
       
  1554 		TRACE_EXIT_POINT;
       
  1555 		return ETrue;
       
  1556 		}
       
  1557 
       
  1558 	// If no character found, return EFalse
       
  1559 	TRACE_EXIT_POINT;
       
  1560 	return EFalse;
       
  1561 	}
       
  1562 
       
  1563 
       
  1564 // End of File
       
  1565 
       
  1566 
       
  1567