int CachedDateFormat::findMillisecondStart()

in src/main/cpp/cacheddateformat.cpp [155:237]


int CachedDateFormat::findMillisecondStart(
	log4cxx_time_t time, const LogString& formatted,
	const DateFormatPtr& formatter,
	Pool& pool)
{

	apr_time_t slotBegin = (time / 1000000) * 1000000;

	if (slotBegin > time)
	{
		slotBegin -= 1000000;
	}

	int millis = (int) (time - slotBegin) / 1000;

	// the magic numbers are in microseconds
	int magic = magic1;
	LogString magicString(magicString1);

	if (millis == magic1 / 1000)
	{
		magic = magic2;
		magicString = magicString2;
	}

	LogString plusMagic;
	formatter->format(plusMagic, slotBegin + magic, pool);

	/**
	 *   If the string lengths differ then
	 *      we can't use the cache except for duplicate requests.
	 */
	if (plusMagic.length() != formatted.length())
	{
		return UNRECOGNIZED_MILLISECONDS;
	}
	else
	{
		// find first difference between values
		for (LogString::size_type i = 0; i < formatted.length(); i++)
		{
			if (formatted[i] != plusMagic[i])
			{
				//
				//   determine the expected digits for the base time
				const logchar abc[] = { 0x41, 0x42, 0x43, 0 };
				LogString formattedMillis(abc);
				millisecondFormat(millis, formattedMillis, 0);

				LogString plusZero;
				formatter->format(plusZero, slotBegin, pool);

				// Test if the next 1..3 characters match the magic string, main problem is that magic
				// available millis in formatted can overlap. Therefore the current i is not always the
				// index of the first millis char, but may be already within the millis. Besides that
				// the millis can occur everywhere in formatted. See LOGCXX-420 and following.
				size_t  magicLength     = magicString.length();
				size_t  overlapping     = magicString.find(plusMagic[i]);
				int     possibleRetVal  = int(i - overlapping);

				if (plusZero.length() == formatted.length()
					&& regionMatches(magicString,       0, plusMagic,   possibleRetVal, magicLength)
					&& regionMatches(formattedMillis,   0, formatted,   possibleRetVal, magicLength)
					&& regionMatches(zeroString,        0, plusZero,    possibleRetVal, magicLength)
					// The following will and should fail for patterns with more than one SSS because
					// we only seem to be able to change one SSS in e.g. format and need to reformat the
					// whole string in other cases.
					&& (formatted.length() == possibleRetVal + magicLength
						|| plusZero.compare(possibleRetVal + magicLength,
							LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0))
				{
					return possibleRetVal;
				}
				else
				{
					return UNRECOGNIZED_MILLISECONDS;
				}
			}
		}
	}

	return NO_MILLISECONDS;
}