/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
enum EParserSpecial {
eParserSpecial_None, // not parsing a special character
eParserSpecial_Escaped, // awaiting a special character
eParserSpecial_Unicode // parsing a \Uxxx value
};
private: bool ParseValueCharacter(
char16_t aChar, // character that is just being parsed const char16_t* aCur, // pointer to character aChar in the buffer const char16_t*& aTokenStart, // string copying is done in blocks as big // as possible, aTokenStart points to the // beginning of this block
nsAString& aOldValue); // when duplicate property is found, new value // is stored into hashtable and the old one is // placed in this variable
uint32_t mUnicodeValuesRead; // should be 4!
char16_t mUnicodeValue; // currently parsed unicode value bool mHaveMultiLine; // is TRUE when last processed characters form // any of following sequences: // - "\\\r" // - "\\\n" // - "\\\r\n" // - any sequence above followed by any // combination of ' ' and '\t' bool mMultiLineCanSkipN; // TRUE if "\\\r" was detected
EParserState mState; // if we see a '\' then we enter this special state
EParserSpecial mSpecialState;
nsCOMPtr<nsIPersistentProperties> mProps;
};
bool nsPropertiesParser::ParseValueCharacter(char16_t aChar, const char16_t* aCur, const char16_t*& aTokenStart,
nsAString& aOldValue) { switch (mSpecialState) { // the normal state - look for special characters case eParserSpecial_None: switch (aChar) { case'\\': if (mHaveMultiLine) { // there is nothing to append to mValue yet
mHaveMultiLine = false;
} else {
mValue += Substring(aTokenStart, aCur);
}
mSpecialState = eParserSpecial_Escaped; break;
case'\n': // if we detected multiline and got only "\\\r" ignore next "\n" if // any if (mHaveMultiLine && mMultiLineCanSkipN) { // but don't allow another '\n' to be skipped
mMultiLineCanSkipN = false; // Now there is nothing to append to the mValue since we are // skipping whitespaces at the beginning of the new line of the // multiline property. Set aTokenStart properly to ensure that // nothing is appended if we find regular line-end or the end of the // buffer.
aTokenStart = aCur + 1; break;
}
[[fallthrough]];
case'\r': // we're done! We have a key and value
mValue += Substring(aTokenStart, aCur);
FinishValueState(aOldValue);
mHaveMultiLine = false; break;
default: // there is nothing to do with normal characters, // but handle multilines correctly if (mHaveMultiLine) { if (aChar == ' ' || aChar == '\t') { // don't allow another '\n' to be skipped
mMultiLineCanSkipN = false; // Now there is nothing to append to the mValue since we are // skipping whitespaces at the beginning of the new line of the // multiline property. Set aTokenStart properly to ensure that // nothing is appended if we find regular line-end or the end of // the buffer.
aTokenStart = aCur + 1; break;
}
mHaveMultiLine = false;
aTokenStart = aCur;
} break; // from switch on (aChar)
} break; // from switch on (mSpecialState)
// saw a \ character, so parse the character after that case eParserSpecial_Escaped: // probably want to start parsing at the next token // other characters, like 'u' might override this
aTokenStart = aCur + 1;
mSpecialState = eParserSpecial_None;
nsresult nsPropertiesParser::ParseBuffer(const char16_t* aBuffer,
uint32_t aBufferLength) { const char16_t* cur = aBuffer; const char16_t* end = aBuffer + aBufferLength;
// points to the start/end of the current key or value const char16_t* tokenStart = nullptr;
// if we're in the middle of parsing a key or value, make sure // the current token points to the beginning of the current buffer if (mState == eParserState_Key || mState == eParserState_Value) {
tokenStart = aBuffer;
}
nsAutoString oldValue;
while (cur != end) {
char16_t c = *cur;
switch (mState) { case eParserState_AwaitingKey: if (c == '#' || c == '!') {
EnterCommentState();
}
elseif (!IsWhiteSpace(c)) { // not a comment, not whitespace, we must have found a key!
EnterKeyState();
tokenStart = cur;
} break;
case eParserState_Key: if (c == '=' || c == ':') {
mKey += Substring(tokenStart, cur);
WaitForValue();
} break;
case eParserState_AwaitingValue: if (IsEOL(c)) { // no value at all! mimic the normal value-ending
EnterValueState();
FinishValueState(oldValue);
}
// ignore white space leading up to the value elseif (!IsWhiteSpace(c)) {
tokenStart = cur;
EnterValueState();
// make sure to handle this first character if (ParseValueCharacter(c, cur, tokenStart, oldValue)) {
cur++;
} // If the character isn't consumed, don't do cur++ and parse // the character again. This can happen f.e. for char 'X' in sequence // "\u00X". This character can be control character and must be // processed again. continue;
} break;
case eParserState_Value: if (ParseValueCharacter(c, cur, tokenStart, oldValue)) {
cur++;
} // See few lines above for reason of doing this continue;
case eParserState_Comment: // stay in this state till we hit EOL if (c == '\r' || c == '\n') {
WaitForKey();
} break;
}
// finally, advance to the next character
cur++;
}
// if we're still parsing the value and are in eParserSpecial_None, then // append whatever we have.. if (mState == eParserState_Value && tokenStart &&
mSpecialState == eParserSpecial_None) {
mValue += Substring(tokenStart, cur);
} // if we're still parsing the key, then append whatever we have.. elseif (mState == eParserState_Key && tokenStart) {
mKey += Substring(tokenStart, cur);
}
size_t nsPersistentProperties::SizeOfIncludingThis(
mozilla::MallocSizeOf aMallocSizeOf) { // The memory used by mTable is accounted for in mArena.
size_t n = 0;
n += mArena.SizeOfExcludingThis(aMallocSizeOf);
n += mTable.ShallowSizeOfExcludingThis(aMallocSizeOf); return aMallocSizeOf(this) + n;
}
uint32_t nProcessed; // If this 4096 is changed to some other value, make sure to adjust // the bug121341.properties test file accordingly. while (NS_SUCCEEDED(rv = mIn->ReadSegments(nsPropertiesParser::SegmentWriter,
&parser, 4096, &nProcessed)) &&
nProcessed != 0);
mIn = nullptr; if (NS_FAILED(rv)) { return rv;
}
// We may have an unprocessed value at this point // if the last line did not have a proper line ending. if (parser.GetState() == eParserState_Value) {
nsAutoString oldValue;
parser.FinishValueState(oldValue);
}
// We know the necessary size; we can avoid growing it while adding elements
props.SetCapacity(mTable.EntryCount());
// Step through hash entries populating a transient array for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) { auto entry = static_cast<PropertyTableEntry*>(iter.Get());
RefPtr<nsPropertyElement> element = new nsPropertyElement(
nsDependentCString(entry->mKey), nsDependentString(entry->mValue));
if (!props.AppendObject(element)) { return NS_ERROR_OUT_OF_MEMORY;
}
}
//////////////////////////////////////////////////////////////////////////////// // XXX Some day we'll unify the nsIPersistentProperties interface with // nsIProperties, but until now...
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.