/** Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).* All rights reserved.* This component and the accompanying materials are made available* under the terms of "Eclipse Public License v1.0"* which accompanies this distribution, and is available* at the URL "http://www.eclipse.org/legal/epl-v10.html".** Initial Contributors:* Nokia Corporation - initial contribution.** Contributors:** Description: Implements the definition of CICalValue.**/// Class include.#include "ICalValue.h" // CICalValue//debug#include "calendarengines_debug.h"// User includes.#include "ICalKeyWords.h" // Literals#include "ICalRuleSegment.h" // CICalRuleSegment// Constants.// Maximum number of characters to use for storing TInt.// (The maximum number of characters for storing a decimal representation of// KMaxTInt, KMinTInt or even KMaxTUint is 10 on current implementations.// The maximum number of characters for storing a decimal representation of // KMaxTUint64 is 20, so using this for future proofing.)const TInt KICalTIntWidth = 20;// Width of "HHMMSS"const TInt KICalTimeWidth = 6;// Width of "YYYYMMDD"const TInt KICalDateWidth = 8;// Width of "YYYYMMDDTHHMMSS" (note the 'T' in the middle)const TInt KICalDateTimeWidth = KICalDateWidth + KICalTimeWidth + 1;// Width of a duration.const TInt KICalDurationWidth = 25;// Width of a short format UTC offset.const TInt KShortFormatUtcOffsetWidth = 5; // The width of (e.g.) +1000.// Width of a long format UTC offset.const TInt KLongFormatUtcOffsetWidth = 7; // The width of (e.g.) -013045.// Time constants. const TInt KICalSecondsPerMinute = 60;const TInt KICalSecondsPerHour = 3600; // That is: 60*60;const TInt KICalSecondsPerDay = 86400; // That is: 24*60*60;const TInt KICalSecondsPerWeek = 604800; // That is: 7*24*60*60;// Time charactersconst TUint KICalUtcChar('Z'); // UTC time.const TUint KICalTimeChar('T'); // Date/time separator.const TUint KICalPeriodChar('/'); // Period separator.const TUint KICalMicroChar('.'); // Second/microsecond separator.const TUint KICalDurationChar('P'); // Duration.const TUint KICalWeekChar('W'); // Week.const TUint KICalDayChar('D'); // Day.const TUint KICalHourChar('H'); // Hour.const TUint KICalMinuteChar('M'); // Minute.const TUint KICalSecondChar('S'); // Second.const TUint KICalPositiveChar('+'); // Positive values.const TUint KICalNegativeChar('-'); // Negative values.// Date format._LIT(KICalDateFormat, "%F%Y%M%D");/**Static factory construction.@return A new CICalValue.@publishedPartner*/EXPORT_C CICalValue* CICalValue::NewL() { TRACE_ENTRY_POINT; CICalValue* self = CICalValue::NewLC(); CleanupStack::Pop(self); TRACE_EXIT_POINT; return self; }/**Static factory construction.@return A new CICalValue.@publishedPartner*/EXPORT_C CICalValue* CICalValue::NewLC() { TRACE_ENTRY_POINT; CICalValue* self = new (ELeave) CICalValue; CleanupStack::PushL(self); self->ConstructL(); TRACE_EXIT_POINT; return self; }/**Destructor.@publishedPartner*/CICalValue::~CICalValue() { TRACE_ENTRY_POINT; TRACE_EXIT_POINT; delete iValue; }/**Returns a copy of the value as an 8-bit string. User takes ownership of thereturned descriptor, which is also left on the Cleanup Stack. Note that each16-bit word in the value is copied into a single 8-bit word in the returneddescriptor and any values greater than 256 are set to the value '1'. This willnot occur if the value was set using SetBinaryL().@return An 8-bit copy of the value.@publishedPartner*/EXPORT_C HBufC8* CICalValue::BinaryLC() const { TRACE_ENTRY_POINT; CheckNullValueL(); HBufC8* buf = HBufC8::NewLC(iValue->Length()); buf->Des().Copy(*iValue); TRACE_EXIT_POINT; return buf; }/**Stores an 8-bit buffer in the CICalValue. Each 8-bit value is stored within a16-bit value internally.@param aBuffer The 8-bit buffer to be stored.@publishedPartner*/EXPORT_C void CICalValue::SetBinaryL(const TDesC8& aBuffer) { TRACE_ENTRY_POINT; PrepareValuePointer(); iValue = HBufC::NewL(aBuffer.Length()); iValue->Des().Copy(aBuffer); }/**Returns the CICalValue as a TBool. Leaves if the value cannot be read as a TBool.@return TBool stored in the value.@leave KErrCorrupt if value is not a valid Boolean value.@publishedPartner*/EXPORT_C TBool CICalValue::BooleanL() const { TRACE_ENTRY_POINT; CheckNullValueL(); if (iValue->Des() == KICalTrue) { TRACE_EXIT_POINT; return ETrue; } else if (iValue->Des() == KICalFalse) { TRACE_EXIT_POINT; return EFalse; } // Else... User::Leave(KErrCorrupt); TRACE_EXIT_POINT; return EFalse; // Never reached. }/**Stores a TBool in the CICalValue.@param aBool TBool to be stored.@publishedPartner*/EXPORT_C void CICalValue::SetBooleanL(TBool aBool) { TRACE_ENTRY_POINT; PrepareValuePointer(); if (aBool) // ETrue { iValue = KICalTrue().AllocL(); } else // EFalse { iValue = KICalFalse().AllocL(); } TRACE_EXIT_POINT; }/**Returns the CICalValue as a date (TTime).@param aDate TTime to store the date in.@publishedPartner*/EXPORT_C void CICalValue::GetDateL(TTime& aDate) const { TRACE_ENTRY_POINT; CheckNullValueL(); GetDateFromValueL(aDate); TRACE_EXIT_POINT; }/**Stores a date (TTime) as the value.@param aDate TTime to be stored.@publishedPartner*/EXPORT_C void CICalValue::SetDateL(const TTime& aDate) { TRACE_ENTRY_POINT; PrepareValuePointer(); iValue = HBufC::NewL(KICalDateWidth); AppendDateToValueL(aDate); TRACE_EXIT_POINT; }/**Returns the CICalValue as a time (TTime).@param aTime TTime to store the time in.@param aTzType Enumeration showing whether the time represents local time (notsupported), UTC or a custom time zone.@publishedPartner*/EXPORT_C void CICalValue::GetTimeL(TTime& aTime, TTimeZoneType& aTzType) const { TRACE_ENTRY_POINT; CheckNullValueL(); GetTimeFromValueL(aTime, aTzType); TRACE_EXIT_POINT; }/**Stores a time (TTime) as the value.@param aTime TTime to be stored.@param aTzType Enumeration showing whether the time represents local time (notsupported), UTC or a custom time zone.@publishedPartner*/EXPORT_C void CICalValue::SetTimeL(const TTime& aTime, TTimeZoneType aTzType) { TRACE_ENTRY_POINT; PrepareValuePointer(); if (aTzType == EUtcTime) { iValue = HBufC::NewL(KICalTimeWidth + 1); AppendTimeToValueL(aTime); iValue->Des().Append(KICalUtcChar); // Append a 'Z' to signify UTC. } else if (aTzType == ESpecifiedTimeZone || aTzType == EFloatingTime) { iValue = HBufC::NewL(KICalTimeWidth); AppendTimeToValueL(aTime); } TRACE_EXIT_POINT; }/**Returns the CICalValue as a date/time (TTime).@param aDateTime TTime to store the date/time in.@param aTzType Enumeration showing whether the time represents local time (notsupported), UTC or a custom time zone.@param aFirstCharacterNum Skip this many characters of the internal buffer@leave Leaves with KErrCorrupt if the value is not a valid date/time.@publishedPartner*/EXPORT_C void CICalValue::GetDateTimeL(TTime& aDateTime, TTimeZoneType& aTzType, TInt aFirstCharacterNum) const { TRACE_ENTRY_POINT; CheckNullValueL(); // The GetTimeFromValueL() function explicitly sets the TTime passed // in, so create a new TTime for the date and merge with the time later. TTime theDate; GetDateFromValueL(theDate, aFirstCharacterNum); // Only start looking for the time at character position KICalDateWidth // plus one for the 'T' separator. if (iValue->Length() > aFirstCharacterNum + KICalDateWidth + 1) { TTime theTime; if ((*iValue)[aFirstCharacterNum + KICalDateWidth] != KICalDateTimeSeparator) { User::Leave(KErrCorrupt); } GetTimeFromValueL(theTime, aTzType, aFirstCharacterNum + KICalDateWidth + 1); // Set the time component. TDateTime dateValues(theDate.DateTime()); TDateTime combinedValues(theTime.DateTime()); // Set the date component. combinedValues.SetYear(dateValues.Year()); combinedValues.SetMonth(dateValues.Month()); combinedValues.SetDay(dateValues.Day()); // Set the value to return. aDateTime = TTime(combinedValues); } else { // There is no time component specified. For compatibility with MS Outlook, // which can export RECURRENCE-ID fields with no time component, we use // a default time of '00:00' aDateTime = theDate; } TRACE_EXIT_POINT; }/**Stores a date/time (TTime) as the value.@param aDateTime TTime to be stored.@param aTzType Enumeration showing whether the time represents floating time,UTC or a custom time zone.@publishedPartner*/EXPORT_C void CICalValue::SetDateTimeL(const TTime& aDateTime, TTimeZoneType aTzType) { TRACE_ENTRY_POINT; PrepareValuePointer(); if (aTzType == EUtcTime) { iValue = HBufC::NewL(KICalDateTimeWidth + 1); AppendDateToValueL(aDateTime); iValue->Des().Append(KICalTimeChar); AppendTimeToValueL(aDateTime); iValue->Des().Append(KICalUtcChar); // For UTC Time. } else if (aTzType == ESpecifiedTimeZone || aTzType == EFloatingTime) { iValue = HBufC::NewL(KICalDateTimeWidth); AppendDateToValueL(aDateTime); iValue->Des().Append(KICalTimeChar); AppendTimeToValueL(aDateTime); } TRACE_EXIT_POINT; }/**Returns the CICalValue as a Duration (TTimeIntervalSeconds).@return TTimeInterval containing the value's duration.@publishedPartner*/EXPORT_C TTimeIntervalSeconds CICalValue::DurationL() const { TRACE_ENTRY_POINT; CheckNullValueL(); TTimeIntervalSeconds theTis; GetTimeIntervalFromValueL(theTis); TRACE_EXIT_POINT; return theTis; }/**Stores a Duration (TTimeIntervalSeconds) as the value.@param aDuration TTimeIntervalSeconds to be stored.@publishedPartner*/EXPORT_C void CICalValue::SetDurationL(TTimeIntervalSeconds aDuration) { TRACE_ENTRY_POINT; // e.g. P15DT5H0M20S PrepareValuePointer(); iValue = HBufC::NewL(KICalDurationWidth); TInt durInt(aDuration.Int()); if (durInt < 0) { // First character is a '-' for negative values iValue->Des().Append(KICalNegativeChar); // Now we've set the sign, change the durInt to +ve durInt =- durInt; } iValue->Des().Append(KICalDurationChar); // Add day portion. TInt numDays(durInt / KICalSecondsPerDay); durInt -= (numDays * KICalSecondsPerDay); iValue->Des().AppendNum(numDays); iValue->Des().Append(KICalDayChar); iValue->Des().Append(KICalTimeChar); // Add hour portion. TInt numHours(durInt / KICalSecondsPerHour); durInt -= (numHours * KICalSecondsPerHour); iValue->Des().AppendNum(numHours); iValue->Des().Append(KICalHourChar); // Add minute portion. TInt numMinutes(durInt / KICalSecondsPerMinute); durInt -= (numMinutes * KICalSecondsPerMinute); iValue->Des().AppendNum(numMinutes); iValue->Des().Append(KICalMinuteChar); // Add second portion. TInt numSeconds(durInt); iValue->Des().AppendNum(numSeconds); iValue->Des().Append(KICalSecondChar); TRACE_EXIT_POINT; }/**Returns the CICalValue as a Float (TReal).@param aFloat The value to return.@leave Leaves if there is an error reading a float.@publishedPartner*/EXPORT_C void CICalValue::GetFloatL(TReal& aFloat) const { TRACE_ENTRY_POINT; CheckNullValueL(); TLex stringLex(iValue->Des()); User::LeaveIfError(stringLex.Val(aFloat)); TRACE_EXIT_POINT; }/**Stores a float (TReal) as the value.@param aFloat The value to store.@publishedPartner*/EXPORT_C void CICalValue::SetFloatL(const TReal& aFloat) { TRACE_ENTRY_POINT; PrepareValuePointer(); iValue = HBufC::NewL(KDefaultRealWidth); TRealFormat format; iValue->Des().Num(aFloat, format); TRACE_EXIT_POINT; }/**Returns the CICalValue as an Integer.@return The integer requested.@publishedPartner*/EXPORT_C TInt CICalValue::IntegerL() const { TRACE_ENTRY_POINT; CheckNullValueL(); TRACE_EXIT_POINT; return ReadIntL(iValue->Des()); }/**Stores an Integer as the value.@param aInt The integer to be stored.@publishedPartner*/EXPORT_C void CICalValue::SetIntegerL(TInt aInt) { TRACE_ENTRY_POINT; PrepareValuePointer(); iValue = HBufC::NewL(KICalTIntWidth); iValue->Des().Num(aInt); TRACE_EXIT_POINT; }/**Returns the CICalValue as a Period (two TTimes).@param aStartTime TTime marking the beginning of the period.@param aStartTzType Enumeration showing whether the start time represents localtime (not supported), UTC or a custom time zone.@param aEndTime TTime marking the end of the period.@param aEndTzType Enumeration showing whether the end time represents localtime (not supported), UTC or a custom time zone.@publishedPartner*/EXPORT_C void CICalValue::GetPeriodL( TTime& aStartTime, TTimeZoneType& aStartTzType, TTime& aEndTime, TTimeZoneType& aEndTzType) const { TRACE_ENTRY_POINT; // Example : 19970101T180000Z/19970102T070000Z // that is : yyyymmddThhmmss[Z]/yyyymmddThhmmss[Z] // Example2: 19970101T180000Z/PT5H30M // that is2: yyyymmddThhmmss[Z]/[+/-]P[lots of stuff] // As the first part is always a date-time, get this out to start off with GetDateTimeL(aStartTime, aStartTzType, 0); // Next we need to get the position of the separator. TInt charNumber(iValue->Des().Locate(KICalPeriodChar)); User::LeaveIfError(charNumber); // If the character after the separator is a 'P', '+' or '-' the second part is a duration. ++charNumber; if (charNumber >= iValue->Length()) { User::Leave(KErrCorrupt); } TChar theChar(iValue->Des()[charNumber]); if ((theChar == KICalDurationChar) || (theChar == KICalPositiveChar) || (theChar == KICalNegativeChar)) { // Call a function to change the duration into a TTime (date + time) TTimeIntervalSeconds interval; GetTimeIntervalFromValueL(interval, charNumber); // Convert from this TimeInterval to a TTime aEndTime = aStartTime; aEndTime += interval; // The timezone will be the same as the first. aEndTzType = aStartTzType; } else // Presume it's a date-time { GetDateTimeL(aEndTime, aEndTzType, charNumber); } TRACE_EXIT_POINT; }/**Stores a Period (two TTimes) as the value.@param aStartTime TTime to be stored containing the beginning of the period.@param aStartTzType Enumeration showing whether the start time represents localtime (not supported), UTC or a custom time zone.@param aEndTime TTime to be stored containing the end of the period.@param aEndTzType Enumeration showing whether the end time represents localtime (not supported), UTC or a custom time zone.@publishedPartner*/EXPORT_C void CICalValue::SetPeriodL( const TTime& aStartTime, TTimeZoneType aStartTzType, const TTime& aEndTime, TTimeZoneType aEndTzType) { TRACE_ENTRY_POINT; // Example: 19970101T180000Z/19970102T070000Z // that is: yyyymmddThhmmss[Z]/yyyymmddThhmmss[Z] PrepareValuePointer(); SetDateTimeL(aStartTime, aStartTzType); if (aEndTzType == EUtcTime) { iValue->ReAllocL(iValue->Length() + 2 + KICalDateTimeWidth); iValue->Des().Append(KICalPeriodChar); AppendDateToValueL(aEndTime); iValue->Des().Append(KICalTimeChar); AppendTimeToValueL(aEndTime); iValue->Des().Append(KICalUtcChar); } else if (aEndTzType == ESpecifiedTimeZone || aEndTzType == EFloatingTime) { iValue->ReAllocL(iValue->Length() + 1 + KICalDateTimeWidth); iValue->Des().Append(KICalPeriodChar); AppendDateToValueL(aEndTime); iValue->Des().Append(KICalTimeChar); AppendTimeToValueL(aEndTime); } TRACE_EXIT_POINT; }/**Returns the value as an enumerated day and position.@param aDay A modifiable reference to an enumerated day.@param aPos A modifiable reference to a position.@leave KErrCorrupt if the day part is invalid.@publishedPartner*/EXPORT_C void CICalValue::GetDayL(TDay& aDay, TInt& aPos) const { TRACE_ENTRY_POINT; CheckNullValueL(); // Find the end of the numeric part. _LIT(KICalDayNumeric, "-+0123456789"); TInt endNumeric(0); while (endNumeric < iValue->Length()) { if (KICalDayNumeric().Locate((*iValue)[endNumeric]) == KErrNotFound) { break; } ++endNumeric; } // Set the numeric part. if (endNumeric != 0) { aPos = ReadIntL(iValue->Left(endNumeric)); } else { aPos = 0; } // Set the day part. TPtrC dayStr(iValue->Mid(endNumeric)); if (dayStr.CompareF(KICalMonday) == 0) { aDay = EMonday; } else if (dayStr.CompareF(KICalTuesday) == 0) { aDay = ETuesday; } else if (dayStr.CompareF(KICalWednesday) == 0) { aDay = EWednesday; } else if (dayStr.CompareF(KICalThursday) == 0) { aDay = EThursday; } else if (dayStr.CompareF(KICalFriday) == 0) { aDay = EFriday; } else if (dayStr.CompareF(KICalSaturday) == 0) { aDay = ESaturday; } else if (dayStr.CompareF(KICalSunday) == 0) { aDay = ESunday; } else { User::Leave(KErrCorrupt); // Invalid day. } TRACE_EXIT_POINT; }/**Sets the value from an enumerated date and position.@param aDay The day to set.@param aPos The position to set.@leave Leaves with KErrUnknown if the value of aDay is not known.@publishedPartner*/EXPORT_C void CICalValue::SetDayL(TDay aDay, TInt aPos) { TRACE_ENTRY_POINT; PrepareValuePointer(); // Get the day as a descriptor. TPtrC dayName; switch (aDay) { case EMonday: dayName.Set(KICalMonday()); break; case ETuesday: dayName.Set(KICalTuesday()); break; case EWednesday: dayName.Set(KICalWednesday()); break; case EThursday: dayName.Set(KICalThursday()); break; case EFriday: dayName.Set(KICalFriday()); break; case ESaturday: dayName.Set(KICalSaturday()); break; case ESunday: dayName.Set(KICalSunday()); break; default: User::Leave(KErrUnknown); break; } // We need space for a number and a day name. iValue = HBufC::NewL(KICalTIntWidth + dayName.Length()); iValue->Des().AppendNum(aPos); iValue->Des().Append(dayName); TRACE_EXIT_POINT; }/**Gets the value as a month.@return The month set in the value.@leave Leaves with KErrCorrupt if the value is not a valid month.@publishedPartner*/EXPORT_C TMonth CICalValue::MonthL() const { TRACE_ENTRY_POINT; CheckNullValueL(); TInt num(IntegerL()); if ((num < 1) || (num > 12)) { User::Leave(KErrCorrupt); } TRACE_EXIT_POINT; return static_cast<TMonth>(num - 1); }/**Sets a month as the value.@param aMonth The month to set.@publishedPartner*/EXPORT_C void CICalValue::SetMonthL(TMonth aMonth) { TRACE_ENTRY_POINT; PrepareValuePointer(); SetIntegerL(aMonth + 1); TRACE_EXIT_POINT; }/**Returns the value as an array of CICalRuleSegments. Assumes that all escapinghas been previously removed.@param aRuleSegmentArray The array that the segments are appended to.@leave Leaves if there is an error adding a rule segment to the array.@publishedPartner*/EXPORT_C void CICalValue::GetRecurrenceRuleL(RPointerArray<CICalRuleSegment>& aRuleSegmentArray) const { TRACE_ENTRY_POINT; CheckNullValueL(); // Find the first semicolon: TInt nextSemiColon(iValue->Locate(KICalSemiColonChar)); if (nextSemiColon == KErrNotFound) { // This means there is only one segment, pretend the semicolon exists at the end of the buffer nextSemiColon = iValue->Length(); } TUint charNum(0); do { // Create a rule segment from characters charNum to nextSemiColon CICalRuleSegment* theRule = CICalRuleSegment::NewLC(iValue->Mid(charNum, nextSemiColon - charNum)); User::LeaveIfError(aRuleSegmentArray.Append(theRule)); // Takes ownership. CleanupStack::Pop(theRule); // Put the character marker past the current semicolon charNum = nextSemiColon + 1; // We only want to check for any more semicolons in the area to the right of charNum. // First check if there are ANY characters to the right of charNum if (charNum < iValue->Length()) { // Find the location of the next semi colon in this area. nextSemiColon = iValue->Right(iValue->Length() - charNum).Locate(KICalSemiColonChar); if (nextSemiColon != KErrNotFound) { // Set the semicolon to be in it's correct position, shifted to take into account the fact // that we were only looking in the right part of the original descriptor. nextSemiColon += charNum; } else { // There are no more semicolons, read in the last value and then exit the loop nextSemiColon = iValue->Length(); } } } while (charNum < iValue->Length()); TRACE_EXIT_POINT; }/**Sets a complete RRULE as a descriptor value. Note that this is no differentthan setting as text and is only supplied for symmetry.@param aRuleValue The descriptor containing the complete RRULE.@publishedPartner*/EXPORT_C void CICalValue::SetRecurrenceRuleL(const TDesC& aRuleValue) { TRACE_ENTRY_POINT; PrepareValuePointer(); iValue = aRuleValue.AllocL(); TRACE_EXIT_POINT; }/**Returns the CICalValue as text.@return The value as text.@publishedPartner*/EXPORT_C const TDesC& CICalValue::TextL() const { TRACE_ENTRY_POINT; CheckNullValueL(); TRACE_EXIT_POINT; return *iValue; }/**Stores text as the value.@param aText The text to be stored.@publishedPartner*/EXPORT_C void CICalValue::SetTextL(const TDesC& aText) { TRACE_ENTRY_POINT; PrepareValuePointer(); iValue = aText.AllocL(); TRACE_EXIT_POINT; }/**Returns the CICalValue as a UTC Offset (TTimeIntervalSeconds).@return TTimeIntervalSeconds containing the offset.@leave Leaves with KErrCorrupt if the value is invalid.@publishedPartner*/EXPORT_C TTimeIntervalSeconds CICalValue::UtcOffsetL() const { TRACE_ENTRY_POINT; // Format is (e.g.) +1000 (10 hours ahead) or -013045 (1.5 hours and 45 seconds behind). CheckNullValueL(); const TInt length = iValue->Length(); if ((length != KLongFormatUtcOffsetWidth) && (length != KShortFormatUtcOffsetWidth)) { // Invalid UTC Offset - we can't really test more than this, so the output may be garbage! User::Leave(KErrCorrupt); } // Get the value of the hour component. TInt hours(ReadIntL(iValue->Des().Left(3))); // '+' or '-' plus the hours component. // Get the value of the minute component. TInt minutes(ReadIntL(iValue->Des().Mid(3, 2))); // The minutes component. // Get the value of the (optional) second component. TInt seconds(0); if (length == KLongFormatUtcOffsetWidth) // Long format. { seconds = ReadIntL(iValue->Des().Mid(5, 2)); // The second component. } // Convert to TTimeIntervalSeconds. TRACE_EXIT_POINT; return TTimeIntervalSeconds((hours * KICalSecondsPerHour) + (minutes * KICalSecondsPerMinute) + seconds); }/**Stores a UTC Offset (TTimeIntervalSeconds) as the value.@param aOffset TTimeInterval to set as the offset.@publishedPartner*/EXPORT_C void CICalValue::SetUtcOffsetL(TTimeIntervalSeconds aOffset) { TRACE_ENTRY_POINT; // Format is (e.g.) +1000 (10 hours ahead) or -013045 (1.5 hours and 45 seconds behind). PrepareValuePointer(); // Create a buffer long enough to hold the widest format. iValue = HBufC::NewL(KLongFormatUtcOffsetWidth); // Get the offset as an integer. TInt offset(aOffset.Int()); // Set the sign. if (offset < 0) { iValue->Des().Append(KICalNegativeChar); // Set offset to positive for calculations. offset =- offset; } else { iValue->Des().Append(KICalPositiveChar); } // Add hour portion. TInt numHours(offset / KICalSecondsPerHour); offset -= (numHours * KICalSecondsPerHour); iValue->Des().AppendNumFixedWidth(numHours, EDecimal, 2); // Add minute portion. TInt numMinutes(offset / KICalSecondsPerMinute); offset -= (numMinutes * KICalSecondsPerMinute); iValue->Des().AppendNumFixedWidth(numMinutes, EDecimal, 2); // Add second portion if necessary. if (offset > 0) { iValue->Des().AppendNumFixedWidth(offset, EDecimal, 2); } TRACE_EXIT_POINT; }/**Constructor.@internalTechnology*/CICalValue::CICalValue() { TRACE_ENTRY_POINT; TRACE_EXIT_POINT; }/**Internal construction.@internalTechnology*/void CICalValue::ConstructL() { TRACE_ENTRY_POINT; TRACE_EXIT_POINT; }/**Checks for a NULL value. Should be called before accessing iValue. @leave Leaves with KErrCorrupt if the value is NULL.@internalTechnology*/void CICalValue::CheckNullValueL() const { TRACE_ENTRY_POINT; if (!iValue) { User::Leave(KErrCorrupt); } TRACE_EXIT_POINT; }/**Prepares iValue pointer for writing. Deletes existing pointer if it exists.@internalTechnology*/void CICalValue::PrepareValuePointer() { TRACE_ENTRY_POINT; if (iValue) { delete iValue; iValue = NULL; } TRACE_EXIT_POINT; }/**Reads a TInt from the given descriptor.@param aDes The descriptor to convert@return The integer conversion.@leave Leaves if there is an error reading an integer.@internalTechnology*/TInt CICalValue::ReadIntL(const TDesC& aDes) const { TRACE_ENTRY_POINT; TLex stringLex(aDes); TInt returnValue(0); User::LeaveIfError(stringLex.Val(returnValue)); TRACE_EXIT_POINT; return returnValue; }/**Appends the date to iValue. Member iValue must be initialised before calling.@param aDate TTime to append to the value.@internalTechnology*/void CICalValue::AppendDateToValueL(const TTime& aDate) { TRACE_ENTRY_POINT; TBuf<KICalDateWidth> formattedDate; aDate.FormatL(formattedDate, KICalDateFormat); iValue->Des().Append(formattedDate); TRACE_EXIT_POINT; }/**Gets the date from iValue descriptor. Should be in the format YYYYMMDD@param aDate A modifiable reference returning a date.@param aFirstCharacterNum Skip this many characters at the start of the value.@leave Leaves with KErrCorrupt if the format of the value is not a valid date.@internalTechnology*/void CICalValue::GetDateFromValueL(TTime& aDate, TInt aFirstCharacterNum) const { TRACE_ENTRY_POINT; if (aFirstCharacterNum + KICalDateWidth > iValue->Length()) { User::Leave(KErrCorrupt); } // Get the year as an int. TInt year(ReadIntL(iValue->Des().Mid(aFirstCharacterNum, 4))); // YYYYmmdd if (year < 0) // All positive years are valid! { User::Leave(KErrCorrupt); } // Get the month as an int. TInt month(ReadIntL(iValue->Mid(aFirstCharacterNum + 4, 2))); // yyyMMdd if ((month < 1) || (month > 12)) { User::Leave(KErrCorrupt); } // Get the day as an int. TInt day(ReadIntL(iValue->Mid(aFirstCharacterNum + 6, 2))); // yyyymmDD if ((day < 1) || (day > Time::DaysInMonth(year, static_cast<TMonth>(month - 1)))) // Zero-offset month. { User::Leave(KErrCorrupt); } // Set the date from its component parts. aDate = 0; aDate += TTimeIntervalYears(year); aDate += TTimeIntervalMonths(month - 1); // Zero-offset. aDate += TTimeIntervalDays(day - 1); // Zero-offset. TRACE_EXIT_POINT; }/**Appends the time to iValue. Member iValue must be initialised before calling.@param aTime TTime to append to the value.@internalTechnology*/void CICalValue::AppendTimeToValueL(const TTime& aTime) { TRACE_ENTRY_POINT; // Format is HHMMSS followed optionally by a Z for UTC time. // Note that the 'Z' is not appended here. TDateTime fullTime(aTime.DateTime()); iValue->Des().AppendNumFixedWidth(fullTime.Hour(), EDecimal, 2); iValue->Des().AppendNumFixedWidth(fullTime.Minute(), EDecimal, 2); iValue->Des().AppendNumFixedWidth(fullTime.Second(), EDecimal, 2); TRACE_EXIT_POINT; }/**Gets the time from iValue descriptor, starting from a pre-determined point.Should be in the format HHMMSS[Z]@param aTime TTime to store result of read in@param aTzType Enumeration showing whether the time represents local time (notsupported), UTC or a custom time zone.@param aFirstCharacterNum The character number to start searching from.@leave Leaves with KErrCorrupt if the value does not hold a valid time.@internalTechnology*/void CICalValue::GetTimeFromValueL(TTime& aTime, TTimeZoneType& aTzType, TInt aFirstCharacterNum) const { TRACE_ENTRY_POINT; if (aFirstCharacterNum + KICalTimeWidth > iValue->Length()) { User::Leave(KErrCorrupt); } // Create a new descriptor containing just the first KICalTimeWidth characters of iValue // It's size is one larger as we will need to add a full stop (see below) HBufC* formattedTime = HBufC::NewLC(iValue->Des().Mid(aFirstCharacterNum, KICalTimeWidth).Length() + 1); *formattedTime = iValue->Des().Mid(aFirstCharacterNum, KICalTimeWidth); // The only formatting needed is to append a full stop formattedTime->Des().Append(KICalMicroChar); if (aTime.Set(*formattedTime)) { User::Leave(KErrCorrupt); } if ((iValue->Length() > (KICalTimeWidth + aFirstCharacterNum)) && (iValue->Des()[KICalTimeWidth + aFirstCharacterNum] == KICalUtcChar)) { aTzType = EUtcTime; } else {//DAVIDTODO: // If there is no 'Z' character then assume that there // is a specified time zone - EFloatingTime is not used. aTzType = ESpecifiedTimeZone; } CleanupStack::PopAndDestroy(formattedTime); TRACE_EXIT_POINT; }/**Retrieves a time interval stored as a duration as per the RFC 2445specification.@param aTimeInterval TTimeIntervalSeconds to store the result in.@param aFirstCharacterNum The position in the value containing the firstcharacter of the duration.@leave Leaves with KErrCorrupt if the value does not hold a valid interval.@internalTechnology*/void CICalValue::GetTimeIntervalFromValueL(TTimeIntervalSeconds& aTimeInterval, TInt aFirstCharacterNum) const { TRACE_ENTRY_POINT; // dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week) // dur-date = dur-day [dur-time] // dur-time = "T" (dur-hour / dur-minute / dur-second) // dur-week = 1*DIGIT "W" // dur-hour = 1*DIGIT "H" [dur-minute] // dur-minute = 1*DIGIT "M" [dur-second] // dur-second = 1*DIGIT "S" // dur-day = 1*DIGIT "D" // Example: A duration of 15 days, 5 hours and 20 seconds would be: // P15DT5H0M20S // A duration of 7 weeks would be: // P7W TInt intervalMultiplier(1); // This variable sets the interval to be positive or negative. // Length should be at least two. if ((aFirstCharacterNum >= iValue->Length()) || (iValue->Length() < 2 + aFirstCharacterNum)) { User::Leave(KErrCorrupt); } // Check that the first character is a 'P', '+' or '-' and adjust the interval accordingly. TChar firstCharacter(iValue->Des()[aFirstCharacterNum]); if (firstCharacter == KICalDurationChar) { intervalMultiplier = 1; aFirstCharacterNum += 1; // Skip the "P" } else if (firstCharacter == KICalPositiveChar) { intervalMultiplier = 1; aFirstCharacterNum += 2; // Skip the "+P" } else if (firstCharacter == KICalNegativeChar) { intervalMultiplier = -1; aFirstCharacterNum += 2; // Skip the "-P" } else { User::Leave(KErrCorrupt); } // It can only contain a dur-date, or a dur-time, or a dur-week TInt theInterval(0); if (!GetDurDateL(theInterval, aFirstCharacterNum)) { if (!GetDurTimeL(theInterval, aFirstCharacterNum)) { if (!GetDurWeekL(theInterval, aFirstCharacterNum)) { User::Leave(KErrCorrupt); } } } theInterval *= intervalMultiplier; // Now we've done the multiply we can convert it into a TTimeIntervalSeconds aTimeInterval = theInterval; TRACE_EXIT_POINT; }/**Reads in and converts a dur-day into a number of seconds@param aIntervalSecs Function adds number of seconds to this variable.@param aCurrentCharNumber Character number to start looking in the value.@return ETrue if the value could be interpreted as a dur-date, EFalse otherwise.@internalTechnology*/TBool CICalValue::GetDurDateL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const { TRACE_ENTRY_POINT; // dur-date = dur-day [dur-time] // dur-day = 1*DIGIT "D" if (aCurrentCharNumber >= iValue->Length()) { TRACE_EXIT_POINT; return EFalse; } // Create a new TPtrC containing the data from iValue which we need. TPtrC data(iValue->Mid(aCurrentCharNumber)); // Find the next 'D' in the descriptor. TInt nextDPos(data.Locate(KICalDayChar)); // Check it exists if (nextDPos != KErrNotFound) { // If character found, construct a number from currentCharNumber to nextDPos TInt theNum(ReadIntL(data.Left(nextDPos))); // Convert this time from days to seconds theNum *= KICalSecondsPerDay; aIntervalSecs += theNum; aCurrentCharNumber += nextDPos + 1; // Extra increment to get past the 'D' // Check if a dur-time follows. It's optional // so we can ignore it's return value. GetDurTimeL(aIntervalSecs, aCurrentCharNumber); TRACE_EXIT_POINT; return ETrue; } // If no character found, return EFalse TRACE_EXIT_POINT; return EFalse; }/**Reads in and converts a dur-time into a number of seconds@param aIntervalSecs Function adds number of seconds to this variable.@param aCurrentCharNumber Character number to start looking in the value.@return ETrue if the value could be interpreted as a dur-time, EFalse otherwise.@leave Leaves with KErrCorrupt if the value does not hold a valid time.@internalTechnology*/TBool CICalValue::GetDurTimeL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const { TRACE_ENTRY_POINT; // dur-time = "T" (dur-hour / dur-minute / dur-second) e.g. T5H0M20S if (aCurrentCharNumber >= iValue->Length()) { TRACE_EXIT_POINT; return EFalse; } if (iValue->Des()[aCurrentCharNumber] == KICalTimeChar) { ++aCurrentCharNumber; // Increment to get past 'T' if (!GetDurHourL(aIntervalSecs, aCurrentCharNumber)) { if (!GetDurMinuteL(aIntervalSecs, aCurrentCharNumber)) { if (!GetDurSecondL(aIntervalSecs, aCurrentCharNumber)) { // We should not have read a 'T' and failed to match hour/minute/second User::Leave(KErrCorrupt); } } } } else { // First character is not a 'T', therefore value is not a dur-time TRACE_EXIT_POINT; return EFalse; } TRACE_EXIT_POINT; return ETrue; }/**Reads in and converts a dur-hour into a number of seconds. There is no rangecheck on the number of hours.@param aIntervalSecs Function adds number of seconds to this variable.@param aCurrentCharNumber Character number to start looking in the value.@return ETrue if the value could be interpreted as a dur-hour, EFalse otherwise.@internalTechnology*/TBool CICalValue::GetDurHourL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const { TRACE_ENTRY_POINT; // dur-hour = 1*DIGIT "H" [dur-minute] if (aCurrentCharNumber >= iValue->Length()) { TRACE_EXIT_POINT; return EFalse; } // Create a new TPtrC containing the data from iValue which we need TPtrC data(iValue->Mid(aCurrentCharNumber)); // Find the next 'H' in the descriptor TInt nextHPos(data.Locate(KICalHourChar)); // Check it exists if (nextHPos != KErrNotFound) { // If character found, construct a number from currentCharNumber to nextHPos TInt theNum(ReadIntL(data.Left(nextHPos))); // Convert this time from hours to seconds theNum *= KICalSecondsPerHour; aIntervalSecs += theNum; aCurrentCharNumber += nextHPos + 1; // Extra increment to get past 'H' // Check if a dur-minute follows. It's optional // so we can ignore it's return value. GetDurMinuteL(aIntervalSecs,aCurrentCharNumber); TRACE_EXIT_POINT; return ETrue; } // If no character found, return EFalse TRACE_EXIT_POINT; return EFalse; }/**Reads in and converts a dur-minute into a number of seconds. There is no rangecheck on the number of minutes.@param aIntervalSecs Function adds number of seconds to this variable.@param aCurrentCharNumber Character number to start looking in the value.@return ETrue if the value could be interpreted as a dur-minute, EFalseotherwise.@internalTechnology*/TBool CICalValue::GetDurMinuteL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const { TRACE_ENTRY_POINT; // dur-minute = 1*DIGIT "M" [dur-second] if (aCurrentCharNumber >= iValue->Length()) { TRACE_EXIT_POINT; return EFalse; } // Create a new TPtrC containing the data from iValue which we need TPtrC data(iValue->Mid(aCurrentCharNumber)); // Find the next 'M' in the descriptor TInt nextMPos(data.Locate(KICalMinuteChar)); // Check it exists if (nextMPos != KErrNotFound) { // If character found, construct a number from currentCharNumber to nextMPos TInt theNum(ReadIntL(data.Left(nextMPos))); // Convert this time from minutes to seconds theNum *= KICalSecondsPerMinute; aIntervalSecs += theNum; aCurrentCharNumber += nextMPos + 1; // Extra increment to get past 'M' // Check if a dur-second follows. It's optional // so we can ignore it's return value. GetDurSecondL(aIntervalSecs,aCurrentCharNumber); TRACE_EXIT_POINT; return ETrue; } // If no character found, return EFalse TRACE_EXIT_POINT; return EFalse; }/**Reads in and converts a dur-second into a number of seconds. There is no rangecheck on the number of seconds.@param aIntervalSecs Function adds number of seconds to this variable.@param aCurrentCharNumber Character number to start looking in the value.@return ETrue if the value could be interpreted as a dur-second, EFalseotherwise.@internalTechnology*/TBool CICalValue::GetDurSecondL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const { TRACE_ENTRY_POINT; // dur-second = 1*DIGIT "S" if (aCurrentCharNumber >= iValue->Length()) { TRACE_EXIT_POINT; return EFalse; } // Create a new TPtrC containing the data from iValue which we need TPtrC data(iValue->Mid(aCurrentCharNumber)); // Find the next 'S' in the descriptor TInt nextSPos(data.Locate(KICalSecondChar)); // Check it exists if (nextSPos != KErrNotFound) { // If character found, construct a number from currentCharNumber to nextSPos TInt theNum(ReadIntL(data.Left(nextSPos))); aIntervalSecs += theNum; aCurrentCharNumber += nextSPos; TRACE_EXIT_POINT; return ETrue; } // If no character found, return EFalse TRACE_EXIT_POINT; return EFalse; }/**Reads in and converts a dur-week into a number of seconds@param aIntervalSecs Function adds number of seconds to this variable@param aCurrentCharNumber Character number to start looking in the value.@return ETrue if the value could be interpreted as a dur-week, EFalseotherwise.@internalTechnology*/TBool CICalValue::GetDurWeekL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const { TRACE_ENTRY_POINT; // dur-week = 1*DIGIT "W" if (aCurrentCharNumber >= iValue->Length()) { TRACE_EXIT_POINT; return EFalse; } // Create a new TPtrC containing the data from iValue which we need TPtrC data(iValue->Mid(aCurrentCharNumber)); // Find the next 'W' in the descriptor TInt nextWPos(data.Locate(KICalWeekChar)); // Check it exists if (nextWPos != KErrNotFound) { // If character found, construct a number from currentCharNumber to nextWPos TInt theNum(ReadIntL(data.Left(nextWPos))); // Convert this time from weeks to seconds theNum *= KICalSecondsPerWeek; aIntervalSecs += theNum; aCurrentCharNumber += nextWPos; TRACE_EXIT_POINT; return ETrue; } // If no character found, return EFalse TRACE_EXIT_POINT; return EFalse; }// End of File