mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-01 04:47:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
195
xpcom/ds/IncrementalTokenizer.cpp
Normal file
195
xpcom/ds/IncrementalTokenizer.cpp
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/IncrementalTokenizer.h"
|
||||
|
||||
#include "mozilla/AutoRestore.h"
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
#include "IncrementalTokenizer.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
IncrementalTokenizer::IncrementalTokenizer(Consumer aConsumer,
|
||||
const char * aWhitespaces,
|
||||
const char * aAdditionalWordChars,
|
||||
uint32_t aRawMinBuffered)
|
||||
: TokenizerBase(aWhitespaces, aAdditionalWordChars)
|
||||
#ifdef DEBUG
|
||||
, mConsuming(false)
|
||||
#endif
|
||||
, mNeedMoreInput(false)
|
||||
, mRollback(false)
|
||||
, mInputCursor(0)
|
||||
, mConsumer(aConsumer)
|
||||
{
|
||||
mInputFinished = false;
|
||||
mMinRawDelivery = aRawMinBuffered;
|
||||
}
|
||||
|
||||
nsresult IncrementalTokenizer::FeedInput(const nsACString & aInput)
|
||||
{
|
||||
NS_ENSURE_TRUE(mConsumer, NS_ERROR_NOT_INITIALIZED);
|
||||
MOZ_ASSERT(!mInputFinished);
|
||||
|
||||
mInput.Cut(0, mInputCursor);
|
||||
mInputCursor = 0;
|
||||
|
||||
mInput.Append(aInput);
|
||||
|
||||
return Process();
|
||||
}
|
||||
|
||||
nsresult IncrementalTokenizer::FeedInput(nsIInputStream * aInput, uint32_t aCount)
|
||||
{
|
||||
NS_ENSURE_TRUE(mConsumer, NS_ERROR_NOT_INITIALIZED);
|
||||
MOZ_ASSERT(!mInputFinished);
|
||||
MOZ_ASSERT(!mConsuming);
|
||||
|
||||
mInput.Cut(0, mInputCursor);
|
||||
mInputCursor = 0;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
while (NS_SUCCEEDED(rv) && aCount) {
|
||||
nsCString::index_type remainder = mInput.Length();
|
||||
nsCString::index_type load =
|
||||
std::min<nsCString::index_type>(aCount, PR_UINT32_MAX - remainder);
|
||||
|
||||
if (!load) {
|
||||
// To keep the API simple, we fail if the input data buffer if filled.
|
||||
// It's highly unlikely there will ever be such amout of data cumulated
|
||||
// unless a logic fault in the consumer code.
|
||||
NS_ERROR("IncrementalTokenizer consumer not reading data?");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (!mInput.SetLength(remainder + load, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsCString::char_iterator buffer = mInput.BeginWriting() + remainder;
|
||||
|
||||
uint32_t read;
|
||||
rv = aInput->Read(buffer, load, &read);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// remainder + load fits the uint32_t size, so must remainder + read.
|
||||
mInput.SetLength(remainder + read);
|
||||
aCount -= read;
|
||||
|
||||
rv = Process();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult IncrementalTokenizer::FinishInput()
|
||||
{
|
||||
NS_ENSURE_TRUE(mConsumer, NS_ERROR_NOT_INITIALIZED);
|
||||
MOZ_ASSERT(!mInputFinished);
|
||||
MOZ_ASSERT(!mConsuming);
|
||||
|
||||
mInput.Cut(0, mInputCursor);
|
||||
mInputCursor = 0;
|
||||
|
||||
mInputFinished = true;
|
||||
nsresult rv = Process();
|
||||
mConsumer = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool IncrementalTokenizer::Next(Token & aToken)
|
||||
{
|
||||
// Assert we are called only from the consumer callback
|
||||
MOZ_ASSERT(mConsuming);
|
||||
|
||||
if (mPastEof) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsACString::const_char_iterator next = Parse(aToken);
|
||||
mPastEof = aToken.Type() == TOKEN_EOF;
|
||||
if (next == mCursor && !mPastEof) {
|
||||
// Not enough input to make a deterministic decision.
|
||||
return false;
|
||||
}
|
||||
|
||||
AssignFragment(aToken, mCursor, next);
|
||||
mCursor = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IncrementalTokenizer::NeedMoreInput()
|
||||
{
|
||||
// Assert we are called only from the consumer callback
|
||||
MOZ_ASSERT(mConsuming);
|
||||
|
||||
// When the input has been finished, we can't set the flag to prevent
|
||||
// indefinite wait for more input (that will never come)
|
||||
mNeedMoreInput = !mInputFinished;
|
||||
}
|
||||
|
||||
void IncrementalTokenizer::Rollback()
|
||||
{
|
||||
// Assert we are called only from the consumer callback
|
||||
MOZ_ASSERT(mConsuming);
|
||||
|
||||
mRollback = true;
|
||||
}
|
||||
|
||||
nsresult IncrementalTokenizer::Process()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// Assert we are not re-entered
|
||||
MOZ_ASSERT(!mConsuming);
|
||||
|
||||
AutoRestore<bool> consuming(mConsuming);
|
||||
mConsuming = true;
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(!mPastEof);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
mInput.BeginReading(mCursor);
|
||||
mCursor += mInputCursor;
|
||||
mInput.EndReading(mEnd);
|
||||
|
||||
while (NS_SUCCEEDED(rv) && !mPastEof) {
|
||||
Token token;
|
||||
nsACString::const_char_iterator next = Parse(token);
|
||||
mPastEof = token.Type() == TOKEN_EOF;
|
||||
if (next == mCursor && !mPastEof) {
|
||||
// Not enough input to make a deterministic decision.
|
||||
break;
|
||||
}
|
||||
|
||||
AssignFragment(token, mCursor, next);
|
||||
|
||||
nsACString::const_char_iterator rollback = mCursor;
|
||||
mCursor = next;
|
||||
|
||||
mNeedMoreInput = mRollback = false;
|
||||
|
||||
rv = mConsumer(token, *this);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
if (mNeedMoreInput || mRollback) {
|
||||
mCursor = rollback;
|
||||
mPastEof = false;
|
||||
if (mNeedMoreInput) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mInputCursor = mCursor - mInput.BeginReading();
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // mozilla
|
||||
122
xpcom/ds/IncrementalTokenizer.h
Normal file
122
xpcom/ds/IncrementalTokenizer.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef INCREMENTAL_TOKENIZER_H__
|
||||
#define INCREMENTAL_TOKENIZER_H__
|
||||
|
||||
#include "mozilla/Tokenizer.h"
|
||||
|
||||
#include "nsError.h"
|
||||
#include <functional>
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class IncrementalTokenizer : public TokenizerBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The consumer callback. The function is called for every single token
|
||||
* as found in the input. Failure result returned by this callback stops
|
||||
* the tokenization immediately and bubbles to result of Feed/FinishInput.
|
||||
*
|
||||
* Fragment()s of consumed tokens are ensured to remain valid until next call to
|
||||
* Feed/FinishInput and are pointing to a single linear buffer. Hence, those can
|
||||
* be safely used to accumulate the data for processing after Feed/FinishInput
|
||||
* returned.
|
||||
*/
|
||||
typedef std::function<nsresult(Token const&, IncrementalTokenizer& i)> Consumer;
|
||||
|
||||
/**
|
||||
* For aWhitespaces and aAdditionalWordChars arguments see TokenizerBase.
|
||||
*
|
||||
* @param aConsumer
|
||||
* A mandatory non-null argument, a function that consumes the tokens as they
|
||||
* come when the tokenizer is fed.
|
||||
* @param aRawMinBuffered
|
||||
* When we have buffered at least aRawMinBuffered data, but there was no custom
|
||||
* token found so far because of too small incremental feed chunks, deliver
|
||||
* the raw data to preserve streaming and to save memory. This only has effect
|
||||
* in OnlyCustomTokenizing mode.
|
||||
*/
|
||||
explicit IncrementalTokenizer(Consumer aConsumer,
|
||||
const char* aWhitespaces = nullptr,
|
||||
const char* aAdditionalWordChars = nullptr,
|
||||
uint32_t aRawMinBuffered = 1024);
|
||||
|
||||
/**
|
||||
* Pushes the input to be tokenized. These directly call the Consumer callback
|
||||
* on every found token. Result of the Consumer callback is returned here.
|
||||
*
|
||||
* The tokenizer must be initialized with a valid consumer prior call to these
|
||||
* methods. It's not allowed to call Feed/FinishInput from inside the Consumer
|
||||
* callback.
|
||||
*/
|
||||
nsresult FeedInput(const nsACString& aInput);
|
||||
nsresult FeedInput(nsIInputStream* aInput, uint32_t aCount);
|
||||
nsresult FinishInput();
|
||||
|
||||
/**
|
||||
* Can only be called from inside the consumer callback.
|
||||
*
|
||||
* When there is still anything to read from the input, tokenize it, store
|
||||
* the token type and value to aToken result and shift the cursor past this
|
||||
* just parsed token. Each call to Next() reads another token from
|
||||
* the input and shifts the cursor.
|
||||
*
|
||||
* Returns false if there is not enough data to deterministically recognize
|
||||
* tokens or when the last returned token was EOF.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool Next(Token& aToken);
|
||||
|
||||
/**
|
||||
* Can only be called from inside the consumer callback.
|
||||
*
|
||||
* Tells the tokenizer to revert the cursor and stop the async parsing until
|
||||
* next feed of the input. This is useful when more than one token is needed
|
||||
* to decide on the syntax but there is not enough input to get a next token
|
||||
* (Next() returned false.)
|
||||
*/
|
||||
void NeedMoreInput();
|
||||
|
||||
/**
|
||||
* Can only be called from inside the consumer callback.
|
||||
*
|
||||
* This makes the consumer callback be called again while parsing
|
||||
* the input at the previous cursor position again. This is useful when
|
||||
* the tokenizer state (custom tokens, tokenization mode) has changed and
|
||||
* we want to re-parse the input again.
|
||||
*/
|
||||
void Rollback();
|
||||
|
||||
private:
|
||||
// Loops over the input with TokenizerBase::Parse and calls the Consumer callback.
|
||||
nsresult Process();
|
||||
|
||||
#ifdef DEBUG
|
||||
// True when inside the consumer callback, used only for assertions.
|
||||
bool mConsuming;
|
||||
#endif // DEBUG
|
||||
// Modifyable only from the Consumer callback, tells the parser to break, rollback
|
||||
// and wait for more input.
|
||||
bool mNeedMoreInput;
|
||||
// Modifyable only from the Consumer callback, tells the parser to rollback and
|
||||
// parse the input again, with (if modified) new settings of the tokenizer.
|
||||
bool mRollback;
|
||||
// The input buffer. Updated with each call to Feed/FinishInput.
|
||||
nsCString mInput;
|
||||
// Numerical index pointing at the current cursor position. We don't keep direct
|
||||
// reference to the string buffer since the buffer gets often reallocated.
|
||||
nsCString::index_type mInputCursor;
|
||||
// Refernce to the consumer function.
|
||||
Consumer mConsumer;
|
||||
};
|
||||
|
||||
} // mozilla
|
||||
|
||||
#endif
|
||||
267
xpcom/ds/StickyTimeDuration.h
Normal file
267
xpcom/ds/StickyTimeDuration.h
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_StickyTimeDuration_h
|
||||
#define mozilla_StickyTimeDuration_h
|
||||
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* A ValueCalculator class that performs additional checks before performing
|
||||
* arithmetic operations such that if either operand is Forever (or the
|
||||
* negative equivalent) the result remains Forever (or the negative equivalent
|
||||
* as appropriate).
|
||||
*
|
||||
* Currently this only checks if either argument to each operation is
|
||||
* Forever/-Forever. However, it is possible that, for example,
|
||||
* aA + aB > INT64_MAX (or < INT64_MIN).
|
||||
*
|
||||
* We currently don't check for that case since we don't expect that to
|
||||
* happen often except under test conditions in which case the wrapping
|
||||
* behavior is probably acceptable.
|
||||
*/
|
||||
class StickyTimeDurationValueCalculator
|
||||
{
|
||||
public:
|
||||
static int64_t
|
||||
Add(int64_t aA, int64_t aB)
|
||||
{
|
||||
MOZ_ASSERT((aA != INT64_MAX || aB != INT64_MIN) &&
|
||||
(aA != INT64_MIN || aB != INT64_MAX),
|
||||
"'Infinity + -Infinity' and '-Infinity + Infinity'"
|
||||
" are undefined");
|
||||
|
||||
// Forever + x = Forever
|
||||
// x + Forever = Forever
|
||||
if (aA == INT64_MAX || aB == INT64_MAX) {
|
||||
return INT64_MAX;
|
||||
}
|
||||
// -Forever + x = -Forever
|
||||
// x + -Forever = -Forever
|
||||
if (aA == INT64_MIN || aB == INT64_MIN) {
|
||||
return INT64_MIN;
|
||||
}
|
||||
|
||||
return aA + aB;
|
||||
}
|
||||
|
||||
// Note that we can't just define Add and have BaseTimeDuration call Add with
|
||||
// negative arguments since INT64_MAX != -INT64_MIN so the saturating logic
|
||||
// won't work.
|
||||
static int64_t
|
||||
Subtract(int64_t aA, int64_t aB)
|
||||
{
|
||||
MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) || aA != aB,
|
||||
"'Infinity - Infinity' and '-Infinity - -Infinity'"
|
||||
" are undefined");
|
||||
|
||||
// Forever - x = Forever
|
||||
// x - -Forever = Forever
|
||||
if (aA == INT64_MAX || aB == INT64_MIN) {
|
||||
return INT64_MAX;
|
||||
}
|
||||
// -Forever - x = -Forever
|
||||
// x - Forever = -Forever
|
||||
if (aA == INT64_MIN || aB == INT64_MAX) {
|
||||
return INT64_MIN;
|
||||
}
|
||||
|
||||
return aA - aB;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static int64_t
|
||||
Multiply(int64_t aA, T aB) {
|
||||
// Specializations for double, float, and int64_t are provided following.
|
||||
return Multiply(aA, static_cast<int64_t>(aB));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
Divide(int64_t aA, int64_t aB) {
|
||||
MOZ_ASSERT(aB != 0, "Division by zero");
|
||||
MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
|
||||
(aB != INT64_MAX && aB != INT64_MIN),
|
||||
"Dividing +/-Infinity by +/-Infinity is undefined");
|
||||
|
||||
// Forever / +x = Forever
|
||||
// Forever / -x = -Forever
|
||||
// -Forever / +x = -Forever
|
||||
// -Forever / -x = Forever
|
||||
if (aA == INT64_MAX || aA == INT64_MIN) {
|
||||
return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
|
||||
}
|
||||
// x / Forever = 0
|
||||
// x / -Forever = 0
|
||||
if (aB == INT64_MAX || aB == INT64_MIN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return aA / aB;
|
||||
}
|
||||
|
||||
static double
|
||||
DivideDouble(int64_t aA, int64_t aB)
|
||||
{
|
||||
MOZ_ASSERT(aB != 0, "Division by zero");
|
||||
MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
|
||||
(aB != INT64_MAX && aB != INT64_MIN),
|
||||
"Dividing +/-Infinity by +/-Infinity is undefined");
|
||||
|
||||
// Forever / +x = Forever
|
||||
// Forever / -x = -Forever
|
||||
// -Forever / +x = -Forever
|
||||
// -Forever / -x = Forever
|
||||
if (aA == INT64_MAX || aA == INT64_MIN) {
|
||||
return (aA >= 0) ^ (aB >= 0)
|
||||
? NegativeInfinity<double>()
|
||||
: PositiveInfinity<double>();
|
||||
}
|
||||
// x / Forever = 0
|
||||
// x / -Forever = 0
|
||||
if (aB == INT64_MAX || aB == INT64_MIN) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return static_cast<double>(aA) / aB;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
Modulo(int64_t aA, int64_t aB)
|
||||
{
|
||||
MOZ_ASSERT(aA != INT64_MAX && aA != INT64_MIN,
|
||||
"Infinity modulo x is undefined");
|
||||
|
||||
return aA % aB;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
inline int64_t
|
||||
StickyTimeDurationValueCalculator::Multiply<int64_t>(int64_t aA,
|
||||
int64_t aB)
|
||||
{
|
||||
MOZ_ASSERT((aA != 0 || (aB != INT64_MIN && aB != INT64_MAX)) &&
|
||||
((aA != INT64_MIN && aA != INT64_MAX) || aB != 0),
|
||||
"Multiplication of infinity by zero");
|
||||
|
||||
// Forever * +x = Forever
|
||||
// Forever * -x = -Forever
|
||||
// -Forever * +x = -Forever
|
||||
// -Forever * -x = Forever
|
||||
//
|
||||
// i.e. If one or more of the arguments is +/-Forever, then
|
||||
// return -Forever if the signs differ, or +Forever otherwise.
|
||||
if (aA == INT64_MAX || aA == INT64_MIN ||
|
||||
aB == INT64_MAX || aB == INT64_MIN) {
|
||||
return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
|
||||
}
|
||||
|
||||
return aA * aB;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int64_t
|
||||
StickyTimeDurationValueCalculator::Multiply<double>(int64_t aA, double aB)
|
||||
{
|
||||
MOZ_ASSERT((aA != 0 || (!IsInfinite(aB))) &&
|
||||
((aA != INT64_MIN && aA != INT64_MAX) || aB != 0.0),
|
||||
"Multiplication of infinity by zero");
|
||||
|
||||
// As with Multiply<int64_t>, if one or more of the arguments is
|
||||
// +/-Forever or +/-Infinity, then return -Forever if the signs differ,
|
||||
// or +Forever otherwise.
|
||||
if (aA == INT64_MAX || aA == INT64_MIN || IsInfinite(aB)) {
|
||||
return (aA >= 0) ^ (aB >= 0.0) ? INT64_MIN : INT64_MAX;
|
||||
}
|
||||
|
||||
return aA * aB;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int64_t
|
||||
StickyTimeDurationValueCalculator::Multiply<float>(int64_t aA, float aB)
|
||||
{
|
||||
MOZ_ASSERT(IsInfinite(aB) == IsInfinite(static_cast<double>(aB)),
|
||||
"Casting to float loses infinite-ness");
|
||||
|
||||
return Multiply(aA, static_cast<double>(aB));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of BaseTimeDuration that uses
|
||||
* StickyTimeDurationValueCalculator for arithmetic on the mValue member.
|
||||
*
|
||||
* Use this class when you need a time duration that is expected to hold values
|
||||
* of Forever (or the negative equivalent) *and* when you expect that
|
||||
* time duration to be used in arithmetic operations (and not just value
|
||||
* comparisons).
|
||||
*/
|
||||
typedef BaseTimeDuration<StickyTimeDurationValueCalculator>
|
||||
StickyTimeDuration;
|
||||
|
||||
// Template specializations to allow arithmetic between StickyTimeDuration
|
||||
// and TimeDuration objects by falling back to the safe behavior.
|
||||
inline StickyTimeDuration
|
||||
operator+(const TimeDuration& aA, const StickyTimeDuration& aB)
|
||||
{
|
||||
return StickyTimeDuration(aA) + aB;
|
||||
}
|
||||
inline StickyTimeDuration
|
||||
operator+(const StickyTimeDuration& aA, const TimeDuration& aB)
|
||||
{
|
||||
return aA + StickyTimeDuration(aB);
|
||||
}
|
||||
|
||||
inline StickyTimeDuration
|
||||
operator-(const TimeDuration& aA, const StickyTimeDuration& aB)
|
||||
{
|
||||
return StickyTimeDuration(aA) - aB;
|
||||
}
|
||||
inline StickyTimeDuration
|
||||
operator-(const StickyTimeDuration& aA, const TimeDuration& aB)
|
||||
{
|
||||
return aA - StickyTimeDuration(aB);
|
||||
}
|
||||
|
||||
inline StickyTimeDuration&
|
||||
operator+=(StickyTimeDuration &aA, const TimeDuration& aB)
|
||||
{
|
||||
return aA += StickyTimeDuration(aB);
|
||||
}
|
||||
inline StickyTimeDuration&
|
||||
operator-=(StickyTimeDuration &aA, const TimeDuration& aB)
|
||||
{
|
||||
return aA -= StickyTimeDuration(aB);
|
||||
}
|
||||
|
||||
inline double
|
||||
operator/(const TimeDuration& aA, const StickyTimeDuration& aB)
|
||||
{
|
||||
return StickyTimeDuration(aA) / aB;
|
||||
}
|
||||
inline double
|
||||
operator/(const StickyTimeDuration& aA, const TimeDuration& aB)
|
||||
{
|
||||
return aA / StickyTimeDuration(aB);
|
||||
}
|
||||
|
||||
inline StickyTimeDuration
|
||||
operator%(const TimeDuration& aA, const StickyTimeDuration& aB)
|
||||
{
|
||||
return StickyTimeDuration(aA) % aB;
|
||||
}
|
||||
inline StickyTimeDuration
|
||||
operator%(const StickyTimeDuration& aA, const TimeDuration& aB)
|
||||
{
|
||||
return aA % StickyTimeDuration(aB);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_StickyTimeDuration_h */
|
||||
738
xpcom/ds/Tokenizer.cpp
Normal file
738
xpcom/ds/Tokenizer.cpp
Normal file
|
|
@ -0,0 +1,738 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "Tokenizer.h"
|
||||
|
||||
#include "nsUnicharUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static const char sWhitespaces[] = " \t";
|
||||
|
||||
Tokenizer::Tokenizer(const nsACString& aSource,
|
||||
const char* aWhitespaces,
|
||||
const char* aAdditionalWordChars)
|
||||
: TokenizerBase(aWhitespaces, aAdditionalWordChars)
|
||||
{
|
||||
mInputFinished = true;
|
||||
aSource.BeginReading(mCursor);
|
||||
mRecord = mRollback = mCursor;
|
||||
aSource.EndReading(mEnd);
|
||||
}
|
||||
|
||||
Tokenizer::Tokenizer(const char* aSource,
|
||||
const char* aWhitespaces,
|
||||
const char* aAdditionalWordChars)
|
||||
: Tokenizer(nsDependentCString(aSource), aWhitespaces, aAdditionalWordChars)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::Next(Token& aToken)
|
||||
{
|
||||
if (!HasInput()) {
|
||||
mHasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
mRollback = mCursor;
|
||||
mCursor = Parse(aToken);
|
||||
|
||||
AssignFragment(aToken, mRollback, mCursor);
|
||||
|
||||
mPastEof = aToken.Type() == TOKEN_EOF;
|
||||
mHasFailed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::Check(const TokenType aTokenType, Token& aResult)
|
||||
{
|
||||
if (!HasInput()) {
|
||||
mHasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsACString::const_char_iterator next = Parse(aResult);
|
||||
if (aTokenType != aResult.Type()) {
|
||||
mHasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
mRollback = mCursor;
|
||||
mCursor = next;
|
||||
|
||||
AssignFragment(aResult, mRollback, mCursor);
|
||||
|
||||
mPastEof = aResult.Type() == TOKEN_EOF;
|
||||
mHasFailed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::Check(const Token& aToken)
|
||||
{
|
||||
if (!HasInput()) {
|
||||
mHasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Token parsed;
|
||||
nsACString::const_char_iterator next = Parse(parsed);
|
||||
if (!aToken.Equals(parsed)) {
|
||||
mHasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
mRollback = mCursor;
|
||||
mCursor = next;
|
||||
mPastEof = parsed.Type() == TOKEN_EOF;
|
||||
mHasFailed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Tokenizer::SkipWhites(WhiteSkipping aIncludeNewLines)
|
||||
{
|
||||
if (!CheckWhite() && (aIncludeNewLines == DONT_INCLUDE_NEW_LINE || !CheckEOL())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsACString::const_char_iterator rollback = mRollback;
|
||||
while (CheckWhite() || (aIncludeNewLines == INCLUDE_NEW_LINE && CheckEOL())) {
|
||||
}
|
||||
|
||||
mHasFailed = false;
|
||||
mRollback = rollback;
|
||||
}
|
||||
|
||||
void
|
||||
Tokenizer::SkipUntil(Token const& aToken)
|
||||
{
|
||||
nsACString::const_char_iterator rollback = mCursor;
|
||||
const Token eof = Token::EndOfFile();
|
||||
|
||||
Token t;
|
||||
while (Next(t)) {
|
||||
if (aToken.Equals(t) || eof.Equals(t)) {
|
||||
Rollback();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mRollback = rollback;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::CheckChar(bool (*aClassifier)(const char aChar))
|
||||
{
|
||||
if (!aClassifier) {
|
||||
MOZ_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasInput() || mCursor == mEnd) {
|
||||
mHasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aClassifier(*mCursor)) {
|
||||
mHasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
mRollback = mCursor;
|
||||
++mCursor;
|
||||
mHasFailed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::ReadChar(char* aValue)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aValue);
|
||||
|
||||
Token t;
|
||||
if (!Check(TOKEN_CHAR, t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*aValue = t.AsChar();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::ReadChar(bool (*aClassifier)(const char aChar), char* aValue)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aValue);
|
||||
|
||||
if (!CheckChar(aClassifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*aValue = *mRollback;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::ReadWord(nsACString& aValue)
|
||||
{
|
||||
Token t;
|
||||
if (!Check(TOKEN_WORD, t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aValue.Assign(t.AsString());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::ReadWord(nsDependentCSubstring& aValue)
|
||||
{
|
||||
Token t;
|
||||
if (!Check(TOKEN_WORD, t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aValue.Rebind(t.AsString().BeginReading(), t.AsString().Length());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::ReadUntil(Token const& aToken, nsACString& aResult, ClaimInclusion aInclude)
|
||||
{
|
||||
nsDependentCSubstring substring;
|
||||
bool rv = ReadUntil(aToken, substring, aInclude);
|
||||
aResult.Assign(substring);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
Tokenizer::ReadUntil(Token const& aToken, nsDependentCSubstring& aResult, ClaimInclusion aInclude)
|
||||
{
|
||||
Record();
|
||||
nsACString::const_char_iterator rollback = mCursor;
|
||||
|
||||
bool found = false;
|
||||
Token t;
|
||||
while (Next(t)) {
|
||||
if (aToken.Equals(t)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Claim(aResult, aInclude);
|
||||
mRollback = rollback;
|
||||
return found;
|
||||
}
|
||||
|
||||
void
|
||||
Tokenizer::Rollback()
|
||||
{
|
||||
MOZ_ASSERT(mCursor > mRollback || mPastEof,
|
||||
"Tokenizer::Rollback() cannot use twice or before any parsing");
|
||||
|
||||
mPastEof = false;
|
||||
mHasFailed = false;
|
||||
mCursor = mRollback;
|
||||
}
|
||||
|
||||
void
|
||||
Tokenizer::Record(ClaimInclusion aInclude)
|
||||
{
|
||||
mRecord = aInclude == INCLUDE_LAST
|
||||
? mRollback
|
||||
: mCursor;
|
||||
}
|
||||
|
||||
void
|
||||
Tokenizer::Claim(nsACString& aResult, ClaimInclusion aInclusion)
|
||||
{
|
||||
nsACString::const_char_iterator close = aInclusion == EXCLUDE_LAST
|
||||
? mRollback
|
||||
: mCursor;
|
||||
aResult.Assign(Substring(mRecord, close));
|
||||
}
|
||||
|
||||
void
|
||||
Tokenizer::Claim(nsDependentCSubstring& aResult, ClaimInclusion aInclusion)
|
||||
{
|
||||
nsACString::const_char_iterator close = aInclusion == EXCLUDE_LAST
|
||||
? mRollback
|
||||
: mCursor;
|
||||
aResult.Rebind(mRecord, close - mRecord);
|
||||
}
|
||||
|
||||
// TokenizerBase
|
||||
|
||||
TokenizerBase::TokenizerBase(const char* aWhitespaces,
|
||||
const char* aAdditionalWordChars)
|
||||
: mPastEof(false)
|
||||
, mHasFailed(false)
|
||||
, mInputFinished(true)
|
||||
, mMode(Mode::FULL)
|
||||
, mMinRawDelivery(1024)
|
||||
, mWhitespaces(aWhitespaces ? aWhitespaces : sWhitespaces)
|
||||
, mAdditionalWordChars(aAdditionalWordChars)
|
||||
, mCursor(nullptr)
|
||||
, mEnd(nullptr)
|
||||
, mNextCustomTokenID(TOKEN_CUSTOM0)
|
||||
{
|
||||
}
|
||||
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::AddCustomToken(const nsACString & aValue,
|
||||
ECaseSensitivity aCaseInsensitivity, bool aEnabled)
|
||||
{
|
||||
MOZ_ASSERT(!aValue.IsEmpty());
|
||||
|
||||
UniquePtr<Token>& t = *mCustomTokens.AppendElement();
|
||||
t = MakeUnique<Token>();
|
||||
|
||||
t->mType = static_cast<TokenType>(++mNextCustomTokenID);
|
||||
t->mCustomCaseInsensitivity = aCaseInsensitivity;
|
||||
t->mCustomEnabled = aEnabled;
|
||||
t->mCustom.Assign(aValue);
|
||||
return *t;
|
||||
}
|
||||
|
||||
void
|
||||
TokenizerBase::RemoveCustomToken(Token& aToken)
|
||||
{
|
||||
if (aToken.mType == TOKEN_UNKNOWN) {
|
||||
// Already removed
|
||||
return;
|
||||
}
|
||||
|
||||
for (UniquePtr<Token> const& custom : mCustomTokens) {
|
||||
if (custom->mType == aToken.mType) {
|
||||
mCustomTokens.RemoveElement(custom);
|
||||
aToken.mType = TOKEN_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Token to remove not found");
|
||||
}
|
||||
|
||||
void
|
||||
TokenizerBase::EnableCustomToken(Token const& aToken, bool aEnabled)
|
||||
{
|
||||
if (aToken.mType == TOKEN_UNKNOWN) {
|
||||
// Already removed
|
||||
return;
|
||||
}
|
||||
|
||||
for (UniquePtr<Token> const& custom : mCustomTokens) {
|
||||
if (custom->Type() == aToken.Type()) {
|
||||
// This effectively destroys the token instance.
|
||||
custom->mCustomEnabled = aEnabled;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Token to change not found");
|
||||
}
|
||||
|
||||
void
|
||||
TokenizerBase::SetTokenizingMode(Mode aMode)
|
||||
{
|
||||
mMode = aMode;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::HasFailed() const
|
||||
{
|
||||
return mHasFailed;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::HasInput() const
|
||||
{
|
||||
return !mPastEof;
|
||||
}
|
||||
|
||||
nsACString::const_char_iterator
|
||||
TokenizerBase::Parse(Token& aToken) const
|
||||
{
|
||||
if (mCursor == mEnd) {
|
||||
if (!mInputFinished) {
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
aToken = Token::EndOfFile();
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
nsACString::size_type available = mEnd - mCursor;
|
||||
|
||||
uint32_t longestCustom = 0;
|
||||
for (UniquePtr<Token> const& custom : mCustomTokens) {
|
||||
if (IsCustom(mCursor, *custom, &longestCustom)) {
|
||||
aToken = *custom;
|
||||
return mCursor + custom->mCustom.Length();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mInputFinished && available < longestCustom) {
|
||||
// Not enough data to deterministically decide.
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
nsACString::const_char_iterator next = mCursor;
|
||||
|
||||
if (mMode == Mode::CUSTOM_ONLY) {
|
||||
// We have to do a brute-force search for all of the enabled custom
|
||||
// tokens.
|
||||
while (next < mEnd) {
|
||||
++next;
|
||||
for (UniquePtr<Token> const& custom : mCustomTokens) {
|
||||
if (IsCustom(next, *custom)) {
|
||||
aToken = Token::Raw();
|
||||
return next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mInputFinished) {
|
||||
// End of the data reached.
|
||||
aToken = Token::Raw();
|
||||
return next;
|
||||
}
|
||||
|
||||
if (longestCustom < available && available > mMinRawDelivery) {
|
||||
// We can return some data w/o waiting for either a custom token
|
||||
// or call to FinishData() when we leave the tail where all the
|
||||
// custom tokens potentially fit, so we can't lose only partially
|
||||
// delivered tokens. This preserves reasonable granularity.
|
||||
aToken = Token::Raw();
|
||||
return mEnd - longestCustom + 1;
|
||||
}
|
||||
|
||||
// Not enough data to deterministically decide.
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
enum State {
|
||||
PARSE_INTEGER,
|
||||
PARSE_WORD,
|
||||
PARSE_CRLF,
|
||||
PARSE_LF,
|
||||
PARSE_WS,
|
||||
PARSE_CHAR,
|
||||
} state;
|
||||
|
||||
if (IsWordFirst(*next)) {
|
||||
state = PARSE_WORD;
|
||||
} else if (IsNumber(*next)) {
|
||||
state = PARSE_INTEGER;
|
||||
} else if (strchr(mWhitespaces, *next)) { // not UTF-8 friendly?
|
||||
state = PARSE_WS;
|
||||
} else if (*next == '\r') {
|
||||
state = PARSE_CRLF;
|
||||
} else if (*next == '\n') {
|
||||
state = PARSE_LF;
|
||||
} else {
|
||||
state = PARSE_CHAR;
|
||||
}
|
||||
|
||||
mozilla::CheckedUint64 resultingNumber = 0;
|
||||
|
||||
while (next < mEnd) {
|
||||
switch (state) {
|
||||
case PARSE_INTEGER:
|
||||
// Keep it simple for now
|
||||
resultingNumber *= 10;
|
||||
resultingNumber += static_cast<uint64_t>(*next - '0');
|
||||
|
||||
++next;
|
||||
if (IsPending(next)) {
|
||||
break;
|
||||
}
|
||||
if (IsEnd(next) || !IsNumber(*next)) {
|
||||
if (!resultingNumber.isValid()) {
|
||||
aToken = Token::Error();
|
||||
} else {
|
||||
aToken = Token::Number(resultingNumber.value());
|
||||
}
|
||||
return next;
|
||||
}
|
||||
break;
|
||||
|
||||
case PARSE_WORD:
|
||||
++next;
|
||||
if (IsPending(next)) {
|
||||
break;
|
||||
}
|
||||
if (IsEnd(next) || !IsWord(*next)) {
|
||||
aToken = Token::Word(Substring(mCursor, next));
|
||||
return next;
|
||||
}
|
||||
break;
|
||||
|
||||
case PARSE_CRLF:
|
||||
++next;
|
||||
if (IsPending(next)) {
|
||||
break;
|
||||
}
|
||||
if (!IsEnd(next) && *next == '\n') { // LF is optional
|
||||
++next;
|
||||
}
|
||||
aToken = Token::NewLine();
|
||||
return next;
|
||||
|
||||
case PARSE_LF:
|
||||
++next;
|
||||
aToken = Token::NewLine();
|
||||
return next;
|
||||
|
||||
case PARSE_WS:
|
||||
++next;
|
||||
aToken = Token::Whitespace();
|
||||
return next;
|
||||
|
||||
case PARSE_CHAR:
|
||||
++next;
|
||||
aToken = Token::Char(*mCursor);
|
||||
return next;
|
||||
} // switch (state)
|
||||
} // while (next < end)
|
||||
|
||||
MOZ_ASSERT(!mInputFinished);
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::IsEnd(const nsACString::const_char_iterator& caret) const
|
||||
{
|
||||
return caret == mEnd;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::IsPending(const nsACString::const_char_iterator& caret) const
|
||||
{
|
||||
return IsEnd(caret) && !mInputFinished;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::IsWordFirst(const char aInput) const
|
||||
{
|
||||
// TODO: make this fully work with unicode
|
||||
return (ToLowerCase(static_cast<uint32_t>(aInput)) !=
|
||||
ToUpperCase(static_cast<uint32_t>(aInput))) ||
|
||||
'_' == aInput ||
|
||||
(mAdditionalWordChars ? !!strchr(mAdditionalWordChars, aInput) : false);
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::IsWord(const char aInput) const
|
||||
{
|
||||
return IsWordFirst(aInput) || IsNumber(aInput);
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::IsNumber(const char aInput) const
|
||||
{
|
||||
// TODO: are there unicode numbers?
|
||||
return aInput >= '0' && aInput <= '9';
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::IsCustom(const nsACString::const_char_iterator & caret,
|
||||
const Token & aCustomToken,
|
||||
uint32_t * aLongest) const
|
||||
{
|
||||
MOZ_ASSERT(aCustomToken.mType > TOKEN_CUSTOM0);
|
||||
if (!aCustomToken.mCustomEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aLongest) {
|
||||
*aLongest = std::max(*aLongest, aCustomToken.mCustom.Length());
|
||||
}
|
||||
|
||||
uint32_t inputLength = mEnd - caret;
|
||||
if (aCustomToken.mCustom.Length() > inputLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDependentCSubstring inputFragment(caret, aCustomToken.mCustom.Length());
|
||||
if (aCustomToken.mCustomCaseInsensitivity == CASE_INSENSITIVE) {
|
||||
return inputFragment.Equals(aCustomToken.mCustom, nsCaseInsensitiveUTF8StringComparator());
|
||||
}
|
||||
return inputFragment.Equals(aCustomToken.mCustom);
|
||||
}
|
||||
|
||||
void TokenizerBase::AssignFragment(Token& aToken,
|
||||
nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end)
|
||||
{
|
||||
aToken.AssignFragment(begin, end);
|
||||
}
|
||||
|
||||
// TokenizerBase::Token
|
||||
|
||||
TokenizerBase::Token::Token()
|
||||
: mType(TOKEN_UNKNOWN)
|
||||
, mChar(0)
|
||||
, mInteger(0)
|
||||
, mCustomCaseInsensitivity(CASE_SENSITIVE)
|
||||
, mCustomEnabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
TokenizerBase::Token::Token(const Token& aOther)
|
||||
: mType(aOther.mType)
|
||||
, mCustom(aOther.mCustom)
|
||||
, mChar(aOther.mChar)
|
||||
, mInteger(aOther.mInteger)
|
||||
, mCustomCaseInsensitivity(aOther.mCustomCaseInsensitivity)
|
||||
, mCustomEnabled(aOther.mCustomEnabled)
|
||||
{
|
||||
if (mType == TOKEN_WORD || mType > TOKEN_CUSTOM0) {
|
||||
mWord.Rebind(aOther.mWord.BeginReading(), aOther.mWord.Length());
|
||||
}
|
||||
}
|
||||
|
||||
TokenizerBase::Token&
|
||||
TokenizerBase::Token::operator=(const Token& aOther)
|
||||
{
|
||||
mType = aOther.mType;
|
||||
mCustom = aOther.mCustom;
|
||||
mChar = aOther.mChar;
|
||||
mWord.Rebind(aOther.mWord.BeginReading(), aOther.mWord.Length());
|
||||
mInteger = aOther.mInteger;
|
||||
mCustomCaseInsensitivity = aOther.mCustomCaseInsensitivity;
|
||||
mCustomEnabled = aOther.mCustomEnabled;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
TokenizerBase::Token::AssignFragment(nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end)
|
||||
{
|
||||
mFragment.Rebind(begin, end - begin);
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Raw()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_RAW;
|
||||
return t;
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Word(const nsACString& aValue)
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_WORD;
|
||||
t.mWord.Rebind(aValue.BeginReading(), aValue.Length());
|
||||
return t;
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Char(const char aValue)
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_CHAR;
|
||||
t.mChar = aValue;
|
||||
return t;
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Number(const uint64_t aValue)
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_INTEGER;
|
||||
t.mInteger = aValue;
|
||||
return t;
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Whitespace()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_WS;
|
||||
t.mChar = '\0';
|
||||
return t;
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::NewLine()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_EOL;
|
||||
return t;
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::EndOfFile()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_EOF;
|
||||
return t;
|
||||
}
|
||||
|
||||
// static
|
||||
TokenizerBase::Token
|
||||
TokenizerBase::Token::Error()
|
||||
{
|
||||
Token t;
|
||||
t.mType = TOKEN_ERROR;
|
||||
return t;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenizerBase::Token::Equals(const Token& aOther) const
|
||||
{
|
||||
if (mType != aOther.mType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (mType) {
|
||||
case TOKEN_INTEGER:
|
||||
return AsInteger() == aOther.AsInteger();
|
||||
case TOKEN_WORD:
|
||||
return AsString() == aOther.AsString();
|
||||
case TOKEN_CHAR:
|
||||
return AsChar() == aOther.AsChar();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
char
|
||||
TokenizerBase::Token::AsChar() const
|
||||
{
|
||||
MOZ_ASSERT(mType == TOKEN_CHAR || mType == TOKEN_WS);
|
||||
return mChar;
|
||||
}
|
||||
|
||||
nsDependentCSubstring
|
||||
TokenizerBase::Token::AsString() const
|
||||
{
|
||||
MOZ_ASSERT(mType == TOKEN_WORD);
|
||||
return mWord;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
TokenizerBase::Token::AsInteger() const
|
||||
{
|
||||
MOZ_ASSERT(mType == TOKEN_INTEGER);
|
||||
return mInteger;
|
||||
}
|
||||
|
||||
} // mozilla
|
||||
446
xpcom/ds/Tokenizer.h
Normal file
446
xpcom/ds/Tokenizer.h
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef Tokenizer_h__
|
||||
#define Tokenizer_h__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class TokenizerBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The analyzer works with elements in the input cut to a sequence of token
|
||||
* where each token has an elementary type
|
||||
*/
|
||||
enum TokenType : uint32_t
|
||||
{
|
||||
TOKEN_UNKNOWN,
|
||||
TOKEN_RAW,
|
||||
TOKEN_ERROR,
|
||||
TOKEN_INTEGER,
|
||||
TOKEN_WORD,
|
||||
TOKEN_CHAR,
|
||||
TOKEN_WS,
|
||||
TOKEN_EOL,
|
||||
TOKEN_EOF,
|
||||
TOKEN_CUSTOM0 = 1000
|
||||
};
|
||||
|
||||
enum ECaseSensitivity
|
||||
{
|
||||
CASE_SENSITIVE,
|
||||
CASE_INSENSITIVE
|
||||
};
|
||||
|
||||
/**
|
||||
* Class holding the type and the value of a token. It can be manually created
|
||||
* to allow checks against it via methods of Tokenizer or are results of some of
|
||||
* the Tokenizer's methods.
|
||||
*/
|
||||
class Token
|
||||
{
|
||||
TokenType mType;
|
||||
nsDependentCSubstring mWord;
|
||||
nsCString mCustom;
|
||||
char mChar;
|
||||
uint64_t mInteger;
|
||||
ECaseSensitivity mCustomCaseInsensitivity;
|
||||
bool mCustomEnabled;
|
||||
|
||||
// If this token is a result of the parsing process, this member is referencing
|
||||
// a sub-string in the input buffer. If this is externally created Token this
|
||||
// member is left an empty string.
|
||||
nsDependentCSubstring mFragment;
|
||||
|
||||
friend class TokenizerBase;
|
||||
void AssignFragment(nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end);
|
||||
|
||||
static Token Raw();
|
||||
|
||||
public:
|
||||
Token();
|
||||
Token(const Token& aOther);
|
||||
Token& operator=(const Token& aOther);
|
||||
|
||||
// Static constructors of tokens by type and value
|
||||
static Token Word(const nsACString& aWord);
|
||||
static Token Char(const char aChar);
|
||||
static Token Number(const uint64_t aNumber);
|
||||
static Token Whitespace();
|
||||
static Token NewLine();
|
||||
static Token EndOfFile();
|
||||
static Token Error();
|
||||
|
||||
// Compares the two tokens, type must be identical and value
|
||||
// of one of the tokens must be 'any' or equal.
|
||||
bool Equals(const Token& aOther) const;
|
||||
|
||||
TokenType Type() const { return mType; }
|
||||
char AsChar() const;
|
||||
nsDependentCSubstring AsString() const;
|
||||
uint64_t AsInteger() const;
|
||||
|
||||
nsDependentCSubstring Fragment() const { return mFragment; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Consumers may register a custom string that, when found in the input, is considered
|
||||
* a token and returned by Next*() and accepted by Check*() methods.
|
||||
* AddCustomToken() returns a reference to a token that can then be comapred using
|
||||
* Token::Equals() againts the output from Next*() or be passed to Check*().
|
||||
*/
|
||||
Token AddCustomToken(const nsACString& aValue, ECaseSensitivity aCaseInsensitivity, bool aEnabled = true);
|
||||
template <uint32_t N>
|
||||
Token AddCustomToken(const char(&aValue)[N], ECaseSensitivity aCaseInsensitivity, bool aEnabled = true)
|
||||
{
|
||||
return AddCustomToken(nsDependentCSubstring(aValue, N - 1), aCaseInsensitivity, aEnabled);
|
||||
}
|
||||
void RemoveCustomToken(Token& aToken);
|
||||
/**
|
||||
* Only applies to a custom type of a Token (see AddCustomToken above.)
|
||||
* This turns on and off token recognition. When a custom token is disabled,
|
||||
* it's ignored as never added as a custom token.
|
||||
*/
|
||||
void EnableCustomToken(Token const& aToken, bool aEnable);
|
||||
|
||||
/**
|
||||
* Mode of tokenization.
|
||||
* FULL tokenization, the default, recognizes built-in tokens and any custom tokens,
|
||||
* if added.
|
||||
* CUSTOM_ONLY will only recognize custom tokens, the rest is seen as 'raw'.
|
||||
* This mode can be understood as a 'binary' mode.
|
||||
*/
|
||||
enum class Mode
|
||||
{
|
||||
FULL,
|
||||
CUSTOM_ONLY
|
||||
};
|
||||
void SetTokenizingMode(Mode aMode);
|
||||
|
||||
/**
|
||||
* Return false iff the last Check*() call has returned false or when we've read past
|
||||
* the end of the input string.
|
||||
*/
|
||||
MOZ_MUST_USE bool HasFailed() const;
|
||||
|
||||
protected:
|
||||
explicit TokenizerBase(const char* aWhitespaces = nullptr,
|
||||
const char* aAdditionalWordChars = nullptr);
|
||||
|
||||
// false if we have already read the EOF token.
|
||||
bool HasInput() const;
|
||||
// Main parsing function, it doesn't shift the read cursor, just returns the next
|
||||
// token position.
|
||||
nsACString::const_char_iterator Parse(Token& aToken) const;
|
||||
// Is read cursor at the end?
|
||||
bool IsEnd(const nsACString::const_char_iterator& caret) const;
|
||||
// True, when we are at the end of the input data, but it has not been marked
|
||||
// as complete yet. In that case we cannot proceed with providing a multi-char token.
|
||||
bool IsPending(const nsACString::const_char_iterator & caret) const;
|
||||
// Is read cursor on a character that is a word start?
|
||||
bool IsWordFirst(const char aInput) const;
|
||||
// Is read cursor on a character that is an in-word letter?
|
||||
bool IsWord(const char aInput) const;
|
||||
// Is read cursor on a character that is a valid number?
|
||||
// TODO - support multiple radix
|
||||
bool IsNumber(const char aInput) const;
|
||||
// Is equal to the given custom token?
|
||||
bool IsCustom(const nsACString::const_char_iterator& caret,
|
||||
const Token& aCustomToken, uint32_t* aLongest = nullptr) const;
|
||||
|
||||
// Friendly helper to assign a fragment on a Token
|
||||
static void AssignFragment(Token& aToken,
|
||||
nsACString::const_char_iterator begin,
|
||||
nsACString::const_char_iterator end);
|
||||
|
||||
// true iff we have already read the EOF token
|
||||
bool mPastEof;
|
||||
// true iff the last Check*() call has returned false, reverts to true on Rollback() call
|
||||
bool mHasFailed;
|
||||
// true if the input string is final (finished), false when we expect more data
|
||||
// yet to be fed to the tokenizer (see IncrementalTokenizer derived class).
|
||||
bool mInputFinished;
|
||||
// custom only vs full tokenizing mode, see the Parse() method
|
||||
Mode mMode;
|
||||
// minimal raw data chunked delivery during incremental feed
|
||||
uint32_t mMinRawDelivery;
|
||||
|
||||
// Customizable list of whitespaces
|
||||
const char* mWhitespaces;
|
||||
// Additinal custom word characters
|
||||
const char* mAdditionalWordChars;
|
||||
|
||||
// All these point to the original buffer passed to the constructor or to the incremental
|
||||
// buffer after FeedInput.
|
||||
nsACString::const_char_iterator mCursor; // Position of the current (actually next to read) token start
|
||||
nsACString::const_char_iterator mEnd; // End of the input position
|
||||
|
||||
// This is the list of tokens user has registered with AddCustomToken()
|
||||
nsTArray<UniquePtr<Token>> mCustomTokens;
|
||||
uint32_t mNextCustomTokenID;
|
||||
|
||||
private:
|
||||
TokenizerBase() = delete;
|
||||
TokenizerBase(const TokenizerBase&) = delete;
|
||||
TokenizerBase(TokenizerBase&&) = delete;
|
||||
TokenizerBase(const TokenizerBase&&) = delete;
|
||||
TokenizerBase &operator=(const TokenizerBase&) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a simple implementation of a lexical analyzer or maybe better
|
||||
* called a tokenizer. It doesn't allow any user dictionaries or
|
||||
* user define token types.
|
||||
*
|
||||
* It is limited only to ASCII input for now. UTF-8 or any other input
|
||||
* encoding must yet be implemented.
|
||||
*/
|
||||
class Tokenizer : public TokenizerBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param aSource
|
||||
* The string to parse.
|
||||
* IMPORTANT NOTE: Tokenizer doesn't ensure the input string buffer lifetime.
|
||||
* It's up to the consumer to make sure the string's buffer outlives the Tokenizer!
|
||||
* @param aWhitespaces
|
||||
* If non-null Tokenizer will use this custom set of whitespaces for CheckWhite()
|
||||
* and SkipWhites() calls.
|
||||
* By default the list consists of space and tab.
|
||||
* @param aAdditionalWordChars
|
||||
* If non-null it will be added to the list of characters that consist a word.
|
||||
* This is useful when you want to accept e.g. '-' in HTTP headers.
|
||||
* By default a word character is consider any character for which upper case
|
||||
* is different from lower case.
|
||||
*
|
||||
* If there is an overlap between aWhitespaces and aAdditionalWordChars, the check for
|
||||
* word characters is made first.
|
||||
*/
|
||||
explicit Tokenizer(const nsACString& aSource,
|
||||
const char* aWhitespaces = nullptr,
|
||||
const char* aAdditionalWordChars = nullptr);
|
||||
explicit Tokenizer(const char* aSource,
|
||||
const char* aWhitespaces = nullptr,
|
||||
const char* aAdditionalWordChars = nullptr);
|
||||
|
||||
/**
|
||||
* When there is still anything to read from the input, tokenize it, store the token type
|
||||
* and value to aToken result and shift the cursor past this just parsed token. Each call
|
||||
* to Next() reads another token from the input and shifts the cursor.
|
||||
* Returns false if we have passed the end of the input.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool Next(Token& aToken);
|
||||
|
||||
/**
|
||||
* Parse the token on the input read cursor position, check its type is equal to aTokenType
|
||||
* and if so, put it into aResult, shift the cursor and return true. Otherwise, leave
|
||||
* the input read cursor position intact and return false.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool Check(const TokenType aTokenType, Token& aResult);
|
||||
/**
|
||||
* Same as above method, just compares both token type and token value passed in aToken.
|
||||
* When both the type and the value equals, shift the cursor and return true. Otherwise
|
||||
* return false.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool Check(const Token& aToken);
|
||||
|
||||
/**
|
||||
* SkipWhites method (below) may also skip new line characters automatically.
|
||||
*/
|
||||
enum WhiteSkipping {
|
||||
/**
|
||||
* SkipWhites will only skip what is defined as a white space (default).
|
||||
*/
|
||||
DONT_INCLUDE_NEW_LINE = 0,
|
||||
/**
|
||||
* SkipWhites will skip definited white spaces as well as new lines
|
||||
* automatically.
|
||||
*/
|
||||
INCLUDE_NEW_LINE = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Skips any occurence of whitespaces specified in mWhitespaces member,
|
||||
* optionally skip also new lines.
|
||||
*/
|
||||
void SkipWhites(WhiteSkipping aIncludeNewLines = DONT_INCLUDE_NEW_LINE);
|
||||
|
||||
/**
|
||||
* Skips all tokens until the given one is found or EOF is hit. The token
|
||||
* or EOF are next to read.
|
||||
*/
|
||||
void SkipUntil(Token const& aToken);
|
||||
|
||||
// These are mostly shortcuts for the Check() methods above.
|
||||
|
||||
/**
|
||||
* Check whitespace character is present.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool CheckWhite() { return Check(Token::Whitespace()); }
|
||||
/**
|
||||
* Check there is a single character on the read cursor position. If so, shift the read
|
||||
* cursor position and return true. Otherwise false.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool CheckChar(const char aChar) { return Check(Token::Char(aChar)); }
|
||||
/**
|
||||
* This is a customizable version of CheckChar. aClassifier is a function called with
|
||||
* value of the character on the current input read position. If this user function
|
||||
* returns true, read cursor is shifted and true returned. Otherwise false.
|
||||
* The user classifiction function is not called when we are at or past the end and
|
||||
* false is immediately returned.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool CheckChar(bool (*aClassifier)(const char aChar));
|
||||
/**
|
||||
* Check for a whole expected word.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool CheckWord(const nsACString& aWord) { return Check(Token::Word(aWord)); }
|
||||
/**
|
||||
* Shortcut for literal const word check with compile time length calculation.
|
||||
*/
|
||||
template <uint32_t N>
|
||||
MOZ_MUST_USE
|
||||
bool CheckWord(const char (&aWord)[N]) { return Check(Token::Word(nsDependentCString(aWord, N - 1))); }
|
||||
/**
|
||||
* Checks \r, \n or \r\n.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool CheckEOL() { return Check(Token::NewLine()); }
|
||||
/**
|
||||
* Checks we are at the end of the input string reading. If so, shift past the end
|
||||
* and returns true. Otherwise does nothing and returns false.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool CheckEOF() { return Check(Token::EndOfFile()); }
|
||||
|
||||
/**
|
||||
* These are shortcuts to obtain the value immediately when the token type matches.
|
||||
*/
|
||||
MOZ_MUST_USE bool ReadChar(char* aValue);
|
||||
MOZ_MUST_USE bool ReadChar(bool (*aClassifier)(const char aChar),
|
||||
char* aValue);
|
||||
MOZ_MUST_USE bool ReadWord(nsACString& aValue);
|
||||
MOZ_MUST_USE bool ReadWord(nsDependentCSubstring& aValue);
|
||||
|
||||
/**
|
||||
* This is an integer read helper. It returns false and doesn't move the read
|
||||
* cursor when any of the following happens:
|
||||
* - the token at the read cursor is not an integer
|
||||
* - the final number doesn't fit the T type
|
||||
* Otherwise true is returned, aValue is filled with the integral number
|
||||
* and the cursor is moved forward.
|
||||
*/
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool ReadInteger(T* aValue)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aValue);
|
||||
|
||||
nsACString::const_char_iterator rollback = mRollback;
|
||||
nsACString::const_char_iterator cursor = mCursor;
|
||||
Token t;
|
||||
if (!Check(TOKEN_INTEGER, t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::CheckedInt<T> checked(t.AsInteger());
|
||||
if (!checked.isValid()) {
|
||||
// Move to a state as if Check() call has failed
|
||||
mRollback = rollback;
|
||||
mCursor = cursor;
|
||||
mHasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
*aValue = checked.value();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the read cursor position back as it was before the last call of any parsing
|
||||
* method of Tokenizer (Next, Check*, Skip*, Read*) so that the last operation
|
||||
* can be repeated.
|
||||
* Rollback cannot be used multiple times, it only reverts the last successfull parse
|
||||
* operation. It also cannot be used before any parsing operation has been called
|
||||
* on the Tokenizer.
|
||||
*/
|
||||
void Rollback();
|
||||
|
||||
/**
|
||||
* Record() and Claim() are collecting the input as it is being parsed to obtain
|
||||
* a substring between particular syntax bounderies defined by any recursive
|
||||
* descent parser or simple parser the Tokenizer is used to read the input for.
|
||||
* Inlucsion of a token that has just been parsed can be controlled using an arguemnt.
|
||||
*/
|
||||
enum ClaimInclusion {
|
||||
/**
|
||||
* Include resulting (or passed) token of the last lexical analyzer operation in the result.
|
||||
*/
|
||||
INCLUDE_LAST,
|
||||
/**
|
||||
* Do not include it.
|
||||
*/
|
||||
EXCLUDE_LAST
|
||||
};
|
||||
|
||||
/**
|
||||
* Start the process of recording. Based on aInclude value the begining of the recorded
|
||||
* sub-string is at the current position (EXCLUDE_LAST) or at the position before the last
|
||||
* parsed token (INCLUDE_LAST).
|
||||
*/
|
||||
void Record(ClaimInclusion aInclude = EXCLUDE_LAST);
|
||||
/**
|
||||
* Claim result of the record started with Record() call before. Depending on aInclude
|
||||
* the ending of the sub-string result includes or excludes the last parsed or checked
|
||||
* token.
|
||||
*/
|
||||
void Claim(nsACString& aResult, ClaimInclusion aInclude = EXCLUDE_LAST);
|
||||
void Claim(nsDependentCSubstring& aResult, ClaimInclusion aInclude = EXCLUDE_LAST);
|
||||
|
||||
/**
|
||||
* If aToken is found, aResult is set to the substring between the current
|
||||
* position and the position of aToken, potentially including aToken depending
|
||||
* on aInclude.
|
||||
* If aToken isn't found aResult is set to the substring between the current
|
||||
* position and the end of the string.
|
||||
* If aToken is found, the method returns true. Otherwise it returns false.
|
||||
*
|
||||
* Calling Rollback() after ReadUntil() will return the read cursor to the
|
||||
* position it had before ReadUntil was called.
|
||||
*/
|
||||
MOZ_MUST_USE bool ReadUntil(Token const& aToken, nsDependentCSubstring& aResult,
|
||||
ClaimInclusion aInclude = EXCLUDE_LAST);
|
||||
MOZ_MUST_USE bool ReadUntil(Token const& aToken, nsACString& aResult,
|
||||
ClaimInclusion aInclude = EXCLUDE_LAST);
|
||||
|
||||
protected:
|
||||
// All these point to the original buffer passed to the Tokenizer's constructor
|
||||
nsACString::const_char_iterator mRecord; // Position where the recorded sub-string for Claim() is
|
||||
nsACString::const_char_iterator mRollback; // Position of the previous token start
|
||||
|
||||
private:
|
||||
Tokenizer() = delete;
|
||||
Tokenizer(const Tokenizer&) = delete;
|
||||
Tokenizer(Tokenizer&&) = delete;
|
||||
Tokenizer(const Tokenizer&&) = delete;
|
||||
Tokenizer &operator=(const Tokenizer&) = delete;
|
||||
};
|
||||
|
||||
} // mozilla
|
||||
|
||||
#endif // Tokenizer_h__
|
||||
105
xpcom/ds/moz.build
Normal file
105
xpcom/ds/moz.build
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIArray.idl',
|
||||
'nsIArrayExtensions.idl',
|
||||
'nsIAtom.idl',
|
||||
'nsIAtomService.idl',
|
||||
'nsICollection.idl',
|
||||
'nsIEnumerator.idl',
|
||||
'nsIHashable.idl',
|
||||
'nsIINIParser.idl',
|
||||
'nsIMutableArray.idl',
|
||||
'nsIObserver.idl',
|
||||
'nsIObserverService.idl',
|
||||
'nsIPersistentProperties2.idl',
|
||||
'nsIProperties.idl',
|
||||
'nsIProperty.idl',
|
||||
'nsIPropertyBag.idl',
|
||||
'nsIPropertyBag2.idl',
|
||||
'nsISerializable.idl',
|
||||
'nsISimpleEnumerator.idl',
|
||||
'nsIStringEnumerator.idl',
|
||||
'nsISupportsArray.idl',
|
||||
'nsISupportsIterators.idl',
|
||||
'nsISupportsPrimitives.idl',
|
||||
'nsIVariant.idl',
|
||||
'nsIWritablePropertyBag.idl',
|
||||
'nsIWritablePropertyBag2.idl',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
XPIDL_SOURCES += [
|
||||
'nsIWindowsRegKey.idl',
|
||||
]
|
||||
EXPORTS += ['nsWindowsRegKey.h']
|
||||
SOURCES += [
|
||||
'nsWindowsRegKey.cpp'
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'xpcom_ds'
|
||||
|
||||
EXPORTS += [
|
||||
'nsArray.h',
|
||||
'nsAtomService.h',
|
||||
'nsCharSeparatedTokenizer.h',
|
||||
'nsCheapSets.h',
|
||||
'nsCRT.h',
|
||||
'nsExpirationTracker.h',
|
||||
'nsHashPropertyBag.h',
|
||||
'nsMathUtils.h',
|
||||
'nsStaticAtom.h',
|
||||
'nsStaticNameTable.h',
|
||||
'nsStringEnumerator.h',
|
||||
'nsSupportsArray.h',
|
||||
'nsSupportsPrimitives.h',
|
||||
'nsVariant.h',
|
||||
'nsWhitespaceTokenizer.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'IncrementalTokenizer.h',
|
||||
'StickyTimeDuration.h',
|
||||
'Tokenizer.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'IncrementalTokenizer.cpp',
|
||||
'nsArray.cpp',
|
||||
'nsAtomService.cpp',
|
||||
'nsAtomTable.cpp',
|
||||
'nsCRT.cpp',
|
||||
'nsHashPropertyBag.cpp',
|
||||
'nsINIParserImpl.cpp',
|
||||
'nsObserverList.cpp',
|
||||
'nsObserverService.cpp',
|
||||
'nsProperties.cpp',
|
||||
'nsStringEnumerator.cpp',
|
||||
'nsSupportsArray.cpp',
|
||||
'nsSupportsArrayEnumerator.cpp',
|
||||
'nsSupportsPrimitives.cpp',
|
||||
'nsVariant.cpp',
|
||||
'Tokenizer.cpp',
|
||||
]
|
||||
|
||||
# These two files cannot be built in unified mode because they use the
|
||||
# PL_ARENA_CONST_ALIGN_MASK macro with plarena.h.
|
||||
SOURCES += [
|
||||
'nsPersistentProperties.cpp',
|
||||
'nsStaticNameTable.cpp',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsINIProcessor.js',
|
||||
'nsINIProcessor.manifest',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../io',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
242
xpcom/ds/nsArray.cpp
Normal file
242
xpcom/ds/nsArray.cpp
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsArray.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
// used by IndexOf()
|
||||
struct MOZ_STACK_CLASS findIndexOfClosure
|
||||
{
|
||||
// This is only used for pointer comparison, so we can just use a void*.
|
||||
void* targetElement;
|
||||
uint32_t startIndex;
|
||||
uint32_t resultIndex;
|
||||
};
|
||||
|
||||
static bool FindElementCallback(void* aElement, void* aClosure);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsArray)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIArray)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIArrayExtensions)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMutableArray)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMutableArray)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsArrayCC)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIArray)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIArrayExtensions)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMutableArray)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMutableArray)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsArrayBase::~nsArrayBase()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ADDREF(nsArray)
|
||||
NS_IMPL_RELEASE(nsArray)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsArrayCC)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsArrayCC)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsArrayCC)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsArrayCC)
|
||||
tmp->Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsArrayCC)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArray)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::GetLength(uint32_t* aLength)
|
||||
{
|
||||
*aLength = mArray.Count();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::QueryElementAt(uint32_t aIndex,
|
||||
const nsIID& aIID,
|
||||
void** aResult)
|
||||
{
|
||||
nsISupports* obj = mArray.SafeObjectAt(aIndex);
|
||||
if (!obj) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
// no need to worry about a leak here, because SafeObjectAt()
|
||||
// doesn't addref its result
|
||||
return obj->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::IndexOf(uint32_t aStartIndex, nsISupports* aElement,
|
||||
uint32_t* aResult)
|
||||
{
|
||||
// optimize for the common case by forwarding to mArray
|
||||
if (aStartIndex == 0) {
|
||||
uint32_t idx = mArray.IndexOf(aElement);
|
||||
if (idx == UINT32_MAX) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aResult = idx;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
findIndexOfClosure closure = { aElement, aStartIndex, 0 };
|
||||
bool notFound = mArray.EnumerateForwards(FindElementCallback, &closure);
|
||||
if (notFound) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aResult = closure.resultIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::Enumerate(nsISimpleEnumerator** aResult)
|
||||
{
|
||||
return NS_NewArrayEnumerator(aResult, static_cast<nsIArray*>(this));
|
||||
}
|
||||
|
||||
// nsIMutableArray implementation
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::AppendElement(nsISupports* aElement, bool aWeak)
|
||||
{
|
||||
bool result;
|
||||
if (aWeak) {
|
||||
nsCOMPtr<nsIWeakReference> elementRef = do_GetWeakReference(aElement);
|
||||
NS_ASSERTION(elementRef,
|
||||
"AppendElement: Trying to use weak references on an object that doesn't support it");
|
||||
if (!elementRef) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
result = mArray.AppendObject(elementRef);
|
||||
}
|
||||
|
||||
else {
|
||||
// add the object directly
|
||||
result = mArray.AppendObject(aElement);
|
||||
}
|
||||
return result ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::RemoveElementAt(uint32_t aIndex)
|
||||
{
|
||||
bool result = mArray.RemoveObjectAt(aIndex);
|
||||
return result ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::InsertElementAt(nsISupports* aElement, uint32_t aIndex, bool aWeak)
|
||||
{
|
||||
nsCOMPtr<nsISupports> elementRef;
|
||||
if (aWeak) {
|
||||
elementRef = do_GetWeakReference(aElement);
|
||||
NS_ASSERTION(elementRef,
|
||||
"InsertElementAt: Trying to use weak references on an object that doesn't support it");
|
||||
if (!elementRef) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
elementRef = aElement;
|
||||
}
|
||||
bool result = mArray.InsertObjectAt(elementRef, aIndex);
|
||||
return result ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex, bool aWeak)
|
||||
{
|
||||
nsCOMPtr<nsISupports> elementRef;
|
||||
if (aWeak) {
|
||||
elementRef = do_GetWeakReference(aElement);
|
||||
NS_ASSERTION(elementRef,
|
||||
"ReplaceElementAt: Trying to use weak references on an object that doesn't support it");
|
||||
if (!elementRef) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
elementRef = aElement;
|
||||
}
|
||||
mArray.ReplaceObjectAt(elementRef, aIndex);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::Clear()
|
||||
{
|
||||
mArray.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIArrayExtensions implementation.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::Count(uint32_t* aResult)
|
||||
{
|
||||
return GetLength(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsArrayBase::GetElementAt(uint32_t aIndex, nsISupports** aResult)
|
||||
{
|
||||
nsCOMPtr<nsISupports> obj = mArray.SafeObjectAt(aIndex);
|
||||
obj.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// static helper routines
|
||||
//
|
||||
bool
|
||||
FindElementCallback(void* aElement, void* aClosure)
|
||||
{
|
||||
findIndexOfClosure* closure = static_cast<findIndexOfClosure*>(aClosure);
|
||||
nsISupports* element = static_cast<nsISupports*>(aElement);
|
||||
|
||||
// don't start searching until we're past the startIndex
|
||||
if (closure->resultIndex >= closure->startIndex &&
|
||||
element == closure->targetElement) {
|
||||
return false; // stop! We found it
|
||||
}
|
||||
closure->resultIndex++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsArrayBase::XPCOMConstructor(nsISupports* aOuter, const nsIID& aIID,
|
||||
void** aResult)
|
||||
{
|
||||
if (aOuter) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMutableArray> inst = Create();
|
||||
return inst->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIMutableArray>
|
||||
nsArrayBase::Create()
|
||||
{
|
||||
nsCOMPtr<nsIMutableArray> inst;
|
||||
if (NS_IsMainThread()) {
|
||||
inst = new nsArrayCC;
|
||||
} else {
|
||||
inst = new nsArray;
|
||||
}
|
||||
return inst.forget();
|
||||
}
|
||||
76
xpcom/ds/nsArray.h
Normal file
76
xpcom/ds/nsArray.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsArray_h__
|
||||
#define nsArray_h__
|
||||
|
||||
#include "nsIArrayExtensions.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// {35C66FD1-95E9-4e0a-80C5-C3BD2B375481}
|
||||
#define NS_ARRAY_CID \
|
||||
{ 0x35c66fd1, 0x95e9, 0x4e0a, \
|
||||
{ 0x80, 0xc5, 0xc3, 0xbd, 0x2b, 0x37, 0x54, 0x81 } }
|
||||
|
||||
// nsArray without any refcounting declarations
|
||||
class nsArrayBase : public nsIMutableArray
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIARRAY
|
||||
NS_DECL_NSIARRAYEXTENSIONS
|
||||
NS_DECL_NSIMUTABLEARRAY
|
||||
|
||||
/* Both of these factory functions create a cycle-collectable array
|
||||
on the main thread and a non-cycle-collectable array on other
|
||||
threads. */
|
||||
static already_AddRefed<nsIMutableArray> Create();
|
||||
/* Only for the benefit of the XPCOM module system, use Create()
|
||||
instead. */
|
||||
static nsresult XPCOMConstructor(nsISupports* aOuter, const nsIID& aIID,
|
||||
void** aResult);
|
||||
protected:
|
||||
nsArrayBase() {}
|
||||
nsArrayBase(const nsArrayBase& aOther);
|
||||
explicit nsArrayBase(const nsCOMArray_base& aBaseArray) : mArray(aBaseArray) {}
|
||||
virtual ~nsArrayBase();
|
||||
|
||||
nsCOMArray_base mArray;
|
||||
};
|
||||
|
||||
class nsArray final : public nsArrayBase
|
||||
{
|
||||
friend class nsArrayBase;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
private:
|
||||
nsArray() : nsArrayBase() {}
|
||||
nsArray(const nsArray& aOther);
|
||||
explicit nsArray(const nsCOMArray_base& aBaseArray) : nsArrayBase(aBaseArray) {}
|
||||
~nsArray() {}
|
||||
};
|
||||
|
||||
class nsArrayCC final : public nsArrayBase
|
||||
{
|
||||
friend class nsArrayBase;
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsArrayCC, nsIMutableArray)
|
||||
|
||||
private:
|
||||
nsArrayCC() : nsArrayBase() {}
|
||||
nsArrayCC(const nsArrayCC& aOther);
|
||||
explicit nsArrayCC(const nsCOMArray_base& aBaseArray) : nsArrayBase(aBaseArray) {}
|
||||
~nsArrayCC() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
25
xpcom/ds/nsAtomService.cpp
Normal file
25
xpcom/ds/nsAtomService.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsAtomService.h"
|
||||
#include "nsIAtom.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAtomService, nsIAtomService)
|
||||
|
||||
nsAtomService::nsAtomService()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAtomService::GetAtom(const nsAString& aString, nsIAtom** aResult)
|
||||
{
|
||||
*aResult = NS_Atomize(aString).take();
|
||||
if (!*aResult) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
25
xpcom/ds/nsAtomService.h
Normal file
25
xpcom/ds/nsAtomService.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __nsAtomService_h
|
||||
#define __nsAtomService_h
|
||||
|
||||
#include "nsIAtomService.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsAtomService final : public nsIAtomService
|
||||
{
|
||||
public:
|
||||
nsAtomService();
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIATOMSERVICE
|
||||
|
||||
private:
|
||||
~nsAtomService() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
736
xpcom/ds/nsAtomTable.cpp
Normal file
736
xpcom/ds/nsAtomTable.cpp
Normal file
|
|
@ -0,0 +1,736 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "nsAtomTable.h"
|
||||
#include "nsStaticAtom.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCRT.h"
|
||||
#include "PLDHashTable.h"
|
||||
#include "prenv.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
// There are two kinds of atoms handled by this module.
|
||||
//
|
||||
// - DynamicAtom: the atom itself is heap allocated, as is the nsStringBuffer it
|
||||
// points to. |gAtomTable| holds weak references to them DynamicAtoms. When
|
||||
// the refcount of a DynamicAtom drops to zero, we increment a static counter.
|
||||
// When that counter reaches a certain threshold, we iterate over the atom
|
||||
// table, removing and deleting DynamicAtoms with refcount zero. This allows
|
||||
// us to avoid acquiring the atom table lock during normal refcounting.
|
||||
//
|
||||
// - StaticAtom: the atom itself is heap allocated, but it points to a static
|
||||
// nsStringBuffer. |gAtomTable| effectively owns StaticAtoms, because such
|
||||
// atoms ignore all AddRef/Release calls, which ensures they stay alive until
|
||||
// |gAtomTable| itself is destroyed whereupon they are explicitly deleted.
|
||||
//
|
||||
// Note that gAtomTable is used on multiple threads, and callers must
|
||||
// acquire gAtomTableLock before touching it.
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class CheckStaticAtomSizes
|
||||
{
|
||||
CheckStaticAtomSizes()
|
||||
{
|
||||
static_assert((sizeof(nsFakeStringBuffer<1>().mRefCnt) ==
|
||||
sizeof(nsStringBuffer().mRefCount)) &&
|
||||
(sizeof(nsFakeStringBuffer<1>().mSize) ==
|
||||
sizeof(nsStringBuffer().mStorageSize)) &&
|
||||
(offsetof(nsFakeStringBuffer<1>, mRefCnt) ==
|
||||
offsetof(nsStringBuffer, mRefCount)) &&
|
||||
(offsetof(nsFakeStringBuffer<1>, mSize) ==
|
||||
offsetof(nsStringBuffer, mStorageSize)) &&
|
||||
(offsetof(nsFakeStringBuffer<1>, mStringData) ==
|
||||
sizeof(nsStringBuffer)),
|
||||
"mocked-up strings' representations should be compatible");
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static Atomic<uint32_t, ReleaseAcquire> gUnusedAtomCount(0);
|
||||
|
||||
class DynamicAtom final : public nsIAtom
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<DynamicAtom> Create(const nsAString& aString, uint32_t aHash)
|
||||
{
|
||||
// The refcount is appropriately initialized in the constructor.
|
||||
return dont_AddRef(new DynamicAtom(aString, aHash));
|
||||
}
|
||||
|
||||
static void GCAtomTable();
|
||||
|
||||
enum class GCKind {
|
||||
RegularOperation,
|
||||
Shutdown,
|
||||
};
|
||||
|
||||
static void GCAtomTableLocked(const MutexAutoLock& aProofOfLock,
|
||||
GCKind aKind);
|
||||
|
||||
private:
|
||||
DynamicAtom(const nsAString& aString, uint32_t aHash)
|
||||
: mRefCnt(1)
|
||||
{
|
||||
mLength = aString.Length();
|
||||
mIsStatic = false;
|
||||
RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
|
||||
if (buf) {
|
||||
mString = static_cast<char16_t*>(buf->Data());
|
||||
} else {
|
||||
const size_t size = (mLength + 1) * sizeof(char16_t);
|
||||
buf = nsStringBuffer::Alloc(size);
|
||||
if (MOZ_UNLIKELY(!buf)) {
|
||||
// We OOM because atom allocations should be small and it's hard to
|
||||
// handle them more gracefully in a constructor.
|
||||
NS_ABORT_OOM(size);
|
||||
}
|
||||
mString = static_cast<char16_t*>(buf->Data());
|
||||
CopyUnicodeTo(aString, 0, mString, mLength);
|
||||
mString[mLength] = char16_t(0);
|
||||
}
|
||||
|
||||
mHash = aHash;
|
||||
MOZ_ASSERT(mHash == HashString(mString, mLength));
|
||||
|
||||
NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
|
||||
NS_ASSERTION(buf && buf->StorageSize() >= (mLength + 1) * sizeof(char16_t),
|
||||
"enough storage");
|
||||
NS_ASSERTION(Equals(aString), "correct data");
|
||||
|
||||
// Take ownership of buffer
|
||||
mozilla::Unused << buf.forget();
|
||||
}
|
||||
|
||||
private:
|
||||
// We don't need a virtual destructor because we always delete via a
|
||||
// DynamicAtom* pointer (in GCAtomTable()), not an nsIAtom* pointer.
|
||||
~DynamicAtom();
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIATOM
|
||||
};
|
||||
|
||||
class StaticAtom final : public nsIAtom
|
||||
{
|
||||
public:
|
||||
StaticAtom(nsStringBuffer* aStringBuffer, uint32_t aLength, uint32_t aHash)
|
||||
{
|
||||
mLength = aLength;
|
||||
mIsStatic = true;
|
||||
mString = static_cast<char16_t*>(aStringBuffer->Data());
|
||||
// Technically we could currently avoid doing this addref by instead making
|
||||
// the static atom buffers have an initial refcount of 2.
|
||||
aStringBuffer->AddRef();
|
||||
|
||||
mHash = aHash;
|
||||
MOZ_ASSERT(mHash == HashString(mString, mLength));
|
||||
|
||||
MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
|
||||
MOZ_ASSERT(aStringBuffer &&
|
||||
aStringBuffer->StorageSize() == (mLength + 1) * sizeof(char16_t),
|
||||
"correct storage");
|
||||
}
|
||||
|
||||
// We don't need a virtual destructor because we always delete via a
|
||||
// StaticAtom* pointer (in AtomTableClearEntry()), not an nsIAtom* pointer.
|
||||
~StaticAtom() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIATOM
|
||||
};
|
||||
|
||||
NS_IMPL_QUERY_INTERFACE(StaticAtom, nsIAtom)
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
StaticAtom::AddRef()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
StaticAtom::Release()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DynamicAtom::ScriptableToString(nsAString& aBuf)
|
||||
{
|
||||
nsStringBuffer::FromData(mString)->ToString(mLength, aBuf);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StaticAtom::ScriptableToString(nsAString& aBuf)
|
||||
{
|
||||
nsStringBuffer::FromData(mString)->ToString(mLength, aBuf);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DynamicAtom::ToUTF8String(nsACString& aBuf)
|
||||
{
|
||||
CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StaticAtom::ToUTF8String(nsACString& aBuf)
|
||||
{
|
||||
CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DynamicAtom::ScriptableEquals(const nsAString& aString, bool* aResult)
|
||||
{
|
||||
*aResult = aString.Equals(nsDependentString(mString, mLength));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StaticAtom::ScriptableEquals(const nsAString& aString, bool* aResult)
|
||||
{
|
||||
*aResult = aString.Equals(nsDependentString(mString, mLength));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(size_t)
|
||||
DynamicAtom::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
|
||||
{
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += nsStringBuffer::FromData(mString)->SizeOfIncludingThisIfUnshared(
|
||||
aMallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(size_t)
|
||||
StaticAtom::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
|
||||
{
|
||||
size_t n = aMallocSizeOf(this);
|
||||
// Don't measure the string buffer pointed to by the StaticAtom because it's
|
||||
// in static memory.
|
||||
return n;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The shared hash table for atom lookups.
|
||||
*
|
||||
* Callers must hold gAtomTableLock before manipulating the table.
|
||||
*/
|
||||
static PLDHashTable* gAtomTable;
|
||||
static Mutex* gAtomTableLock;
|
||||
|
||||
struct AtomTableKey
|
||||
{
|
||||
AtomTableKey(const char16_t* aUTF16String, uint32_t aLength, uint32_t aHash)
|
||||
: mUTF16String(aUTF16String)
|
||||
, mUTF8String(nullptr)
|
||||
, mLength(aLength)
|
||||
, mHash(aHash)
|
||||
{
|
||||
MOZ_ASSERT(mHash == HashString(mUTF16String, mLength));
|
||||
}
|
||||
|
||||
AtomTableKey(const char* aUTF8String, uint32_t aLength, uint32_t aHash)
|
||||
: mUTF16String(nullptr)
|
||||
, mUTF8String(aUTF8String)
|
||||
, mLength(aLength)
|
||||
, mHash(aHash)
|
||||
{
|
||||
mozilla::DebugOnly<bool> err;
|
||||
MOZ_ASSERT(aHash == HashUTF8AsUTF16(mUTF8String, mLength, &err));
|
||||
}
|
||||
|
||||
AtomTableKey(const char16_t* aUTF16String, uint32_t aLength,
|
||||
uint32_t* aHashOut)
|
||||
: mUTF16String(aUTF16String)
|
||||
, mUTF8String(nullptr)
|
||||
, mLength(aLength)
|
||||
{
|
||||
mHash = HashString(mUTF16String, mLength);
|
||||
*aHashOut = mHash;
|
||||
}
|
||||
|
||||
AtomTableKey(const char* aUTF8String, uint32_t aLength, uint32_t* aHashOut)
|
||||
: mUTF16String(nullptr)
|
||||
, mUTF8String(aUTF8String)
|
||||
, mLength(aLength)
|
||||
{
|
||||
bool err;
|
||||
mHash = HashUTF8AsUTF16(mUTF8String, mLength, &err);
|
||||
if (err) {
|
||||
mUTF8String = nullptr;
|
||||
mLength = 0;
|
||||
mHash = 0;
|
||||
}
|
||||
*aHashOut = mHash;
|
||||
}
|
||||
|
||||
const char16_t* mUTF16String;
|
||||
const char* mUTF8String;
|
||||
uint32_t mLength;
|
||||
uint32_t mHash;
|
||||
};
|
||||
|
||||
struct AtomTableEntry : public PLDHashEntryHdr
|
||||
{
|
||||
// These references are either to DynamicAtoms, in which case they are
|
||||
// non-owning, or they are to StaticAtoms, which aren't really refcounted.
|
||||
// See the comment at the top of this file for more details.
|
||||
nsIAtom* MOZ_NON_OWNING_REF mAtom;
|
||||
};
|
||||
|
||||
static PLDHashNumber
|
||||
AtomTableGetHash(const void* aKey)
|
||||
{
|
||||
const AtomTableKey* k = static_cast<const AtomTableKey*>(aKey);
|
||||
return k->mHash;
|
||||
}
|
||||
|
||||
static bool
|
||||
AtomTableMatchKey(const PLDHashEntryHdr* aEntry, const void* aKey)
|
||||
{
|
||||
const AtomTableEntry* he = static_cast<const AtomTableEntry*>(aEntry);
|
||||
const AtomTableKey* k = static_cast<const AtomTableKey*>(aKey);
|
||||
|
||||
if (k->mUTF8String) {
|
||||
return
|
||||
CompareUTF8toUTF16(nsDependentCSubstring(k->mUTF8String,
|
||||
k->mUTF8String + k->mLength),
|
||||
nsDependentAtomString(he->mAtom)) == 0;
|
||||
}
|
||||
|
||||
uint32_t length = he->mAtom->GetLength();
|
||||
if (length != k->mLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(he->mAtom->GetUTF16String(),
|
||||
k->mUTF16String, length * sizeof(char16_t)) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
AtomTableClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
||||
{
|
||||
auto entry = static_cast<AtomTableEntry*>(aEntry);
|
||||
nsIAtom* atom = entry->mAtom;
|
||||
if (atom->IsStaticAtom()) {
|
||||
// This case -- when the entry being cleared holds a StaticAtom -- only
|
||||
// occurs when gAtomTable is destroyed, whereupon all StaticAtoms within it
|
||||
// must be explicitly deleted. The cast is required because StaticAtom
|
||||
// doesn't have a virtual destructor.
|
||||
delete static_cast<StaticAtom*>(atom);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AtomTableInitEntry(PLDHashEntryHdr* aEntry, const void* aKey)
|
||||
{
|
||||
static_cast<AtomTableEntry*>(aEntry)->mAtom = nullptr;
|
||||
}
|
||||
|
||||
static const PLDHashTableOps AtomTableOps = {
|
||||
AtomTableGetHash,
|
||||
AtomTableMatchKey,
|
||||
PLDHashTable::MoveEntryStub,
|
||||
AtomTableClearEntry,
|
||||
AtomTableInitEntry
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
DynamicAtom::GCAtomTable()
|
||||
{
|
||||
MutexAutoLock lock(*gAtomTableLock);
|
||||
GCAtomTableLocked(lock, GCKind::RegularOperation);
|
||||
}
|
||||
|
||||
void
|
||||
DynamicAtom::GCAtomTableLocked(const MutexAutoLock& aProofOfLock,
|
||||
GCKind aKind)
|
||||
{
|
||||
uint32_t removedCount = 0; // Use a non-atomic temporary for cheaper increments.
|
||||
nsAutoCString nonZeroRefcountAtoms;
|
||||
uint32_t nonZeroRefcountAtomsCount = 0;
|
||||
for (auto i = gAtomTable->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<AtomTableEntry*>(i.Get());
|
||||
if (entry->mAtom->IsStaticAtom()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto atom = static_cast<DynamicAtom*>(entry->mAtom);
|
||||
if (atom->mRefCnt == 0) {
|
||||
i.Remove();
|
||||
delete atom;
|
||||
++removedCount;
|
||||
}
|
||||
#ifdef NS_FREE_PERMANENT_DATA
|
||||
else if (aKind == GCKind::Shutdown && PR_GetEnv("XPCOM_MEM_BLOAT_LOG")) {
|
||||
// Only report leaking atoms in leak-checking builds in a run
|
||||
// where we are checking for leaks, during shutdown. If
|
||||
// something is anomalous, then we'll assert later in this
|
||||
// function.
|
||||
nsAutoCString name;
|
||||
atom->ToUTF8String(name);
|
||||
if (nonZeroRefcountAtomsCount == 0) {
|
||||
nonZeroRefcountAtoms = name;
|
||||
} else if (nonZeroRefcountAtomsCount < 20) {
|
||||
nonZeroRefcountAtoms += NS_LITERAL_CSTRING(",") + name;
|
||||
} else if (nonZeroRefcountAtomsCount == 20) {
|
||||
nonZeroRefcountAtoms += NS_LITERAL_CSTRING(",...");
|
||||
}
|
||||
nonZeroRefcountAtomsCount++;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
if (nonZeroRefcountAtomsCount) {
|
||||
nsPrintfCString msg("%d dynamic atom(s) with non-zero refcount: %s",
|
||||
nonZeroRefcountAtomsCount, nonZeroRefcountAtoms.get());
|
||||
NS_ASSERTION(nonZeroRefcountAtomsCount == 0, msg.get());
|
||||
}
|
||||
|
||||
// During the course of this function, the atom table is locked. This means
|
||||
// that, barring refcounting bugs in consumers, an atom can never go from
|
||||
// refcount == 0 to refcount != 0 during a GC. However, an atom _can_ go from
|
||||
// refcount != 0 to refcount == 0 if a Release() occurs in parallel with GC.
|
||||
// This means that we cannot assert that gUnusedAtomCount == removedCount, and
|
||||
// thus that there are no unused atoms at the end of a GC. We can and do,
|
||||
// however, assert this after the last GC at shutdown.
|
||||
if (aKind == GCKind::RegularOperation) {
|
||||
MOZ_ASSERT(removedCount <= gUnusedAtomCount);
|
||||
} else {
|
||||
// Complain if somebody adds new GCKind enums.
|
||||
MOZ_ASSERT(aKind == GCKind::Shutdown);
|
||||
// Our unused atom count should be accurate.
|
||||
MOZ_ASSERT(removedCount == gUnusedAtomCount);
|
||||
}
|
||||
|
||||
gUnusedAtomCount -= removedCount;
|
||||
}
|
||||
|
||||
NS_IMPL_QUERY_INTERFACE(DynamicAtom, nsIAtom)
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
DynamicAtom::AddRef(void)
|
||||
{
|
||||
nsrefcnt count = ++mRefCnt;
|
||||
if (count == 1) {
|
||||
MOZ_ASSERT(gUnusedAtomCount > 0);
|
||||
gUnusedAtomCount--;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// We set a lower GC threshold for atoms in debug builds so that we exercise
|
||||
// the GC machinery more often.
|
||||
static const uint32_t kAtomGCThreshold = 20;
|
||||
#else
|
||||
static const uint32_t kAtomGCThreshold = 10000;
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
DynamicAtom::Release(void)
|
||||
{
|
||||
MOZ_ASSERT(mRefCnt > 0);
|
||||
nsrefcnt count = --mRefCnt;
|
||||
if (count == 0) {
|
||||
if (++gUnusedAtomCount >= kAtomGCThreshold) {
|
||||
GCAtomTable();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
DynamicAtom::~DynamicAtom()
|
||||
{
|
||||
nsStringBuffer::FromData(mString)->Release();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class StaticAtomEntry : public PLDHashEntryHdr
|
||||
{
|
||||
public:
|
||||
typedef const nsAString& KeyType;
|
||||
typedef const nsAString* KeyTypePointer;
|
||||
|
||||
explicit StaticAtomEntry(KeyTypePointer aKey) {}
|
||||
StaticAtomEntry(const StaticAtomEntry& aOther) : mAtom(aOther.mAtom) {}
|
||||
|
||||
// We do not delete the atom because that's done when gAtomTable is
|
||||
// destroyed -- which happens immediately after gStaticAtomTable is destroyed
|
||||
// -- in NS_PurgeAtomTable().
|
||||
~StaticAtomEntry() {}
|
||||
|
||||
bool KeyEquals(KeyTypePointer aKey) const
|
||||
{
|
||||
return mAtom->Equals(*aKey);
|
||||
}
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
||||
static PLDHashNumber HashKey(KeyTypePointer aKey)
|
||||
{
|
||||
return HashString(*aKey);
|
||||
}
|
||||
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
// StaticAtoms aren't really refcounted. Because these entries live in a
|
||||
// global hashtable, this reference is essentially owning.
|
||||
StaticAtom* MOZ_OWNING_REF mAtom;
|
||||
};
|
||||
|
||||
/**
|
||||
* A hashtable of static atoms that existed at app startup. This hashtable
|
||||
* helps nsHtml5AtomTable.
|
||||
*/
|
||||
typedef nsTHashtable<StaticAtomEntry> StaticAtomTable;
|
||||
static StaticAtomTable* gStaticAtomTable = nullptr;
|
||||
|
||||
/**
|
||||
* Whether it is still OK to add atoms to gStaticAtomTable.
|
||||
*/
|
||||
static bool gStaticAtomTableSealed = false;
|
||||
|
||||
// The atom table very quickly gets 10,000+ entries in it (or even 100,000+).
|
||||
// But choosing the best initial length has some subtleties: we add ~2700
|
||||
// static atoms to the table at start-up, and then we start adding and removing
|
||||
// dynamic atoms. If we make the table too big to start with, when the first
|
||||
// dynamic atom gets removed the load factor will be < 25% and so we will
|
||||
// shrink it to 4096 entries.
|
||||
//
|
||||
// By choosing an initial length of 4096, we get an initial capacity of 8192.
|
||||
// That's the biggest initial capacity that will let us be > 25% full when the
|
||||
// first dynamic atom is removed (when the count is ~2700), thus avoiding any
|
||||
// shrinking.
|
||||
#define ATOM_HASHTABLE_INITIAL_LENGTH 4096
|
||||
|
||||
void
|
||||
NS_InitAtomTable()
|
||||
{
|
||||
MOZ_ASSERT(!gAtomTable);
|
||||
gAtomTable = new PLDHashTable(&AtomTableOps, sizeof(AtomTableEntry),
|
||||
ATOM_HASHTABLE_INITIAL_LENGTH);
|
||||
gAtomTableLock = new Mutex("Atom Table Lock");
|
||||
}
|
||||
|
||||
void
|
||||
NS_ShutdownAtomTable()
|
||||
{
|
||||
delete gStaticAtomTable;
|
||||
gStaticAtomTable = nullptr;
|
||||
|
||||
#ifdef NS_FREE_PERMANENT_DATA
|
||||
// Do a final GC to satisfy leak checking. We skip this step in release
|
||||
// builds.
|
||||
{
|
||||
MutexAutoLock lock(*gAtomTableLock);
|
||||
DynamicAtom::GCAtomTableLocked(lock, DynamicAtom::GCKind::Shutdown);
|
||||
}
|
||||
#endif
|
||||
|
||||
delete gAtomTable;
|
||||
gAtomTable = nullptr;
|
||||
delete gAtomTableLock;
|
||||
gAtomTableLock = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
NS_SizeOfAtomTablesIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||
size_t* aMain, size_t* aStatic)
|
||||
{
|
||||
MutexAutoLock lock(*gAtomTableLock);
|
||||
*aMain = gAtomTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
||||
for (auto iter = gAtomTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
auto entry = static_cast<AtomTableEntry*>(iter.Get());
|
||||
*aMain += entry->mAtom->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
// The atoms pointed to by gStaticAtomTable are also pointed to by gAtomTable,
|
||||
// and they're measured by the loop above. So no need to measure them here.
|
||||
*aStatic = gStaticAtomTable
|
||||
? gStaticAtomTable->ShallowSizeOfIncludingThis(aMallocSizeOf)
|
||||
: 0;
|
||||
}
|
||||
|
||||
static inline AtomTableEntry*
|
||||
GetAtomHashEntry(const char* aString, uint32_t aLength, uint32_t* aHashOut)
|
||||
{
|
||||
gAtomTableLock->AssertCurrentThreadOwns();
|
||||
AtomTableKey key(aString, aLength, aHashOut);
|
||||
// This is an infallible add.
|
||||
return static_cast<AtomTableEntry*>(gAtomTable->Add(&key));
|
||||
}
|
||||
|
||||
static inline AtomTableEntry*
|
||||
GetAtomHashEntry(const char16_t* aString, uint32_t aLength, uint32_t* aHashOut)
|
||||
{
|
||||
gAtomTableLock->AssertCurrentThreadOwns();
|
||||
AtomTableKey key(aString, aLength, aHashOut);
|
||||
// This is an infallible add.
|
||||
return static_cast<AtomTableEntry*>(gAtomTable->Add(&key));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount)
|
||||
{
|
||||
MutexAutoLock lock(*gAtomTableLock);
|
||||
|
||||
MOZ_RELEASE_ASSERT(!gStaticAtomTableSealed,
|
||||
"Atom table has already been sealed!");
|
||||
|
||||
if (!gStaticAtomTable) {
|
||||
gStaticAtomTable = new StaticAtomTable();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aAtomCount; ++i) {
|
||||
nsStringBuffer* stringBuffer = aAtoms[i].mStringBuffer;
|
||||
nsIAtom** atomp = aAtoms[i].mAtom;
|
||||
|
||||
MOZ_ASSERT(nsCRT::IsAscii(static_cast<char16_t*>(stringBuffer->Data())));
|
||||
|
||||
uint32_t stringLen = stringBuffer->StorageSize() / sizeof(char16_t) - 1;
|
||||
|
||||
uint32_t hash;
|
||||
AtomTableEntry* he =
|
||||
GetAtomHashEntry(static_cast<char16_t*>(stringBuffer->Data()),
|
||||
stringLen, &hash);
|
||||
|
||||
nsIAtom* atom = he->mAtom;
|
||||
if (atom) {
|
||||
// Disallow creating a dynamic atom, and then later, while the
|
||||
// dynamic atom is still alive, registering that same atom as a
|
||||
// static atom. It causes subtle bugs, and we're programming in
|
||||
// C++ here, not Smalltalk.
|
||||
if (!atom->IsStaticAtom()) {
|
||||
nsAutoCString name;
|
||||
atom->ToUTF8String(name);
|
||||
MOZ_CRASH_UNSAFE_PRINTF(
|
||||
"Static atom registration for %s should be pushed back", name.get());
|
||||
}
|
||||
} else {
|
||||
atom = new StaticAtom(stringBuffer, stringLen, hash);
|
||||
he->mAtom = atom;
|
||||
}
|
||||
*atomp = atom;
|
||||
|
||||
if (!gStaticAtomTableSealed) {
|
||||
StaticAtomEntry* entry =
|
||||
gStaticAtomTable->PutEntry(nsDependentAtomString(atom));
|
||||
MOZ_ASSERT(atom->IsStaticAtom());
|
||||
entry->mAtom = static_cast<StaticAtom*>(atom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsIAtom>
|
||||
NS_Atomize(const char* aUTF8String)
|
||||
{
|
||||
return NS_Atomize(nsDependentCString(aUTF8String));
|
||||
}
|
||||
|
||||
already_AddRefed<nsIAtom>
|
||||
NS_Atomize(const nsACString& aUTF8String)
|
||||
{
|
||||
MutexAutoLock lock(*gAtomTableLock);
|
||||
uint32_t hash;
|
||||
AtomTableEntry* he = GetAtomHashEntry(aUTF8String.Data(),
|
||||
aUTF8String.Length(),
|
||||
&hash);
|
||||
|
||||
if (he->mAtom) {
|
||||
nsCOMPtr<nsIAtom> atom = he->mAtom;
|
||||
|
||||
return atom.forget();
|
||||
}
|
||||
|
||||
// This results in an extra addref/release of the nsStringBuffer.
|
||||
// Unfortunately there doesn't seem to be any APIs to avoid that.
|
||||
// Actually, now there is, sort of: ForgetSharedBuffer.
|
||||
nsString str;
|
||||
CopyUTF8toUTF16(aUTF8String, str);
|
||||
RefPtr<DynamicAtom> atom = DynamicAtom::Create(str, hash);
|
||||
|
||||
he->mAtom = atom;
|
||||
|
||||
return atom.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIAtom>
|
||||
NS_Atomize(const char16_t* aUTF16String)
|
||||
{
|
||||
return NS_Atomize(nsDependentString(aUTF16String));
|
||||
}
|
||||
|
||||
already_AddRefed<nsIAtom>
|
||||
NS_Atomize(const nsAString& aUTF16String)
|
||||
{
|
||||
MutexAutoLock lock(*gAtomTableLock);
|
||||
uint32_t hash;
|
||||
AtomTableEntry* he = GetAtomHashEntry(aUTF16String.Data(),
|
||||
aUTF16String.Length(),
|
||||
&hash);
|
||||
|
||||
if (he->mAtom) {
|
||||
nsCOMPtr<nsIAtom> atom = he->mAtom;
|
||||
|
||||
return atom.forget();
|
||||
}
|
||||
|
||||
RefPtr<DynamicAtom> atom = DynamicAtom::Create(aUTF16String, hash);
|
||||
he->mAtom = atom;
|
||||
|
||||
return atom.forget();
|
||||
}
|
||||
|
||||
nsrefcnt
|
||||
NS_GetNumberOfAtoms(void)
|
||||
{
|
||||
DynamicAtom::GCAtomTable(); // Trigger a GC so that we return a deterministic result.
|
||||
MutexAutoLock lock(*gAtomTableLock);
|
||||
return gAtomTable->EntryCount();
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
NS_GetStaticAtom(const nsAString& aUTF16String)
|
||||
{
|
||||
NS_PRECONDITION(gStaticAtomTable, "Static atom table not created yet.");
|
||||
NS_PRECONDITION(gStaticAtomTableSealed, "Static atom table not sealed yet.");
|
||||
StaticAtomEntry* entry = gStaticAtomTable->GetEntry(aUTF16String);
|
||||
return entry ? entry->mAtom : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
NS_SealStaticAtomTable()
|
||||
{
|
||||
gStaticAtomTableSealed = true;
|
||||
}
|
||||
19
xpcom/ds/nsAtomTable.h
Normal file
19
xpcom/ds/nsAtomTable.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsAtomTable_h__
|
||||
#define nsAtomTable_h__
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include <stddef.h>
|
||||
|
||||
void NS_InitAtomTable();
|
||||
void NS_ShutdownAtomTable();
|
||||
|
||||
void NS_SizeOfAtomTablesIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
size_t* aMain, size_t* aStatic);
|
||||
|
||||
#endif // nsAtomTable_h__
|
||||
187
xpcom/ds/nsCRT.cpp
Normal file
187
xpcom/ds/nsCRT.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
|
||||
/**
|
||||
* MODULE NOTES:
|
||||
* @update gess7/30/98
|
||||
*
|
||||
* Much as I hate to do it, we were using string compares wrong.
|
||||
* Often, programmers call functions like strcmp(s1,s2), and pass
|
||||
* one or more null strings. Rather than blow up on these, I've
|
||||
* added quick checks to ensure that cases like this don't cause
|
||||
* us to fail.
|
||||
*
|
||||
* In general, if you pass a null into any of these string compare
|
||||
* routines, we simply return 0.
|
||||
*/
|
||||
|
||||
|
||||
#include "nsCRT.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// My lovely strtok routine
|
||||
|
||||
#define IS_DELIM(m, c) ((m)[(c) >> 3] & (1 << ((c) & 7)))
|
||||
#define SET_DELIM(m, c) ((m)[(c) >> 3] |= (1 << ((c) & 7)))
|
||||
#define DELIM_TABLE_SIZE 32
|
||||
|
||||
char*
|
||||
nsCRT::strtok(char* aString, const char* aDelims, char** aNewStr)
|
||||
{
|
||||
NS_ASSERTION(aString,
|
||||
"Unlike regular strtok, the first argument cannot be null.");
|
||||
|
||||
char delimTable[DELIM_TABLE_SIZE];
|
||||
uint32_t i;
|
||||
char* result;
|
||||
char* str = aString;
|
||||
|
||||
for (i = 0; i < DELIM_TABLE_SIZE; ++i) {
|
||||
delimTable[i] = '\0';
|
||||
}
|
||||
|
||||
for (i = 0; aDelims[i]; i++) {
|
||||
SET_DELIM(delimTable, static_cast<uint8_t>(aDelims[i]));
|
||||
}
|
||||
NS_ASSERTION(aDelims[i] == '\0', "too many delimiters");
|
||||
|
||||
// skip to beginning
|
||||
while (*str && IS_DELIM(delimTable, static_cast<uint8_t>(*str))) {
|
||||
str++;
|
||||
}
|
||||
result = str;
|
||||
|
||||
// fix up the end of the token
|
||||
while (*str) {
|
||||
if (IS_DELIM(delimTable, static_cast<uint8_t>(*str))) {
|
||||
*str++ = '\0';
|
||||
break;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
*aNewStr = str;
|
||||
|
||||
return str == result ? nullptr : result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Compare unichar string ptrs, stopping at the 1st null
|
||||
* NOTE: If both are null, we return 0.
|
||||
* NOTE: We terminate the search upon encountering a nullptr
|
||||
*
|
||||
* @update gess 11/10/99
|
||||
* @param s1 and s2 both point to unichar strings
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
int32_t
|
||||
nsCRT::strcmp(const char16_t* aStr1, const char16_t* aStr2)
|
||||
{
|
||||
if (aStr1 && aStr2) {
|
||||
for (;;) {
|
||||
char16_t c1 = *aStr1++;
|
||||
char16_t c2 = *aStr2++;
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (c1 == 0 || c2 == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (aStr1) { // aStr2 must have been null
|
||||
return -1;
|
||||
}
|
||||
if (aStr2) { // aStr1 must have been null
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare unichar string ptrs, stopping at the 1st null or nth char.
|
||||
* NOTE: If either is null, we return 0.
|
||||
* NOTE: We DO NOT terminate the search upon encountering nullptr's before N
|
||||
*
|
||||
* @update gess 11/10/99
|
||||
* @param s1 and s2 both point to unichar strings
|
||||
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
|
||||
*/
|
||||
int32_t
|
||||
nsCRT::strncmp(const char16_t* aStr1, const char16_t* aStr2, uint32_t aNum)
|
||||
{
|
||||
if (aStr1 && aStr2) {
|
||||
if (aNum != 0) {
|
||||
do {
|
||||
char16_t c1 = *aStr1++;
|
||||
char16_t c2 = *aStr2++;
|
||||
if (c1 != c2) {
|
||||
if (c1 < c2) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
} while (--aNum != 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char*
|
||||
nsCRT::memmem(const char* aHaystack, uint32_t aHaystackLen,
|
||||
const char* aNeedle, uint32_t aNeedleLen)
|
||||
{
|
||||
// Sanity checking
|
||||
if (!(aHaystack && aNeedle && aHaystackLen && aNeedleLen &&
|
||||
aNeedleLen <= aHaystackLen)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MEMMEM
|
||||
return (const char*)::memmem(aHaystack, aHaystackLen, aNeedle, aNeedleLen);
|
||||
#else
|
||||
// No memmem means we need to roll our own. This isn't really optimized
|
||||
// for performance ... if that becomes an issue we can take some inspiration
|
||||
// from the js string compare code in jsstr.cpp
|
||||
for (uint32_t i = 0; i < aHaystackLen - aNeedleLen; i++) {
|
||||
if (!memcmp(aHaystack + i, aNeedle, aNeedleLen)) {
|
||||
return aHaystack + i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This should use NSPR but NSPR isn't exporting its PR_strtoll function
|
||||
// Until then...
|
||||
int64_t
|
||||
nsCRT::atoll(const char* aStr)
|
||||
{
|
||||
if (!aStr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t ll = 0;
|
||||
|
||||
while (*aStr && *aStr >= '0' && *aStr <= '9') {
|
||||
ll *= 10;
|
||||
ll += *aStr - '0';
|
||||
aStr++;
|
||||
}
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
186
xpcom/ds/nsCRT.h
Normal file
186
xpcom/ds/nsCRT.h
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef nsCRT_h___
|
||||
#define nsCRT_h___
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "plstr.h"
|
||||
#include "nscore.h"
|
||||
#include "nsCRTGlue.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
# define NS_LINEBREAK "\015\012"
|
||||
# define NS_LINEBREAK_LEN 2
|
||||
#else
|
||||
# ifdef XP_UNIX
|
||||
# define NS_LINEBREAK "\012"
|
||||
# define NS_LINEBREAK_LEN 1
|
||||
# endif /* XP_UNIX */
|
||||
#endif /* XP_WIN */
|
||||
|
||||
extern const char16_t kIsoLatin1ToUCS2[256];
|
||||
|
||||
// This macro can be used in a class declaration for classes that want
|
||||
// to ensure that their instance memory is zeroed.
|
||||
#define NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW \
|
||||
void* operator new(size_t sz) CPP_THROW_NEW { \
|
||||
void* rv = ::operator new(sz); \
|
||||
if (rv) { \
|
||||
memset(rv, 0, sz); \
|
||||
} \
|
||||
return rv; \
|
||||
} \
|
||||
void operator delete(void* ptr) { \
|
||||
::operator delete(ptr); \
|
||||
}
|
||||
|
||||
// This macro works with the next macro to declare a non-inlined
|
||||
// version of the above.
|
||||
#define NS_DECL_ZEROING_OPERATOR_NEW \
|
||||
void* operator new(size_t sz) CPP_THROW_NEW; \
|
||||
void operator delete(void* ptr);
|
||||
|
||||
#define NS_IMPL_ZEROING_OPERATOR_NEW(_class) \
|
||||
void* _class::operator new(size_t sz) CPP_THROW_NEW { \
|
||||
void* rv = ::operator new(sz); \
|
||||
if (rv) { \
|
||||
memset(rv, 0, sz); \
|
||||
} \
|
||||
return rv; \
|
||||
} \
|
||||
void _class::operator delete(void* ptr) { \
|
||||
::operator delete(ptr); \
|
||||
}
|
||||
|
||||
// Freeing helper
|
||||
#define CRTFREEIF(x) if (x) { nsCRT::free(x); x = 0; }
|
||||
|
||||
/// This is a wrapper class around all the C runtime functions.
|
||||
|
||||
class nsCRT
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
LF = '\n' /* Line Feed */,
|
||||
VTAB = '\v' /* Vertical Tab */,
|
||||
CR = '\r' /* Carriage Return */
|
||||
};
|
||||
|
||||
/// String comparison.
|
||||
static int32_t strcmp(const char* aStr1, const char* aStr2)
|
||||
{
|
||||
return int32_t(PL_strcmp(aStr1, aStr2));
|
||||
}
|
||||
|
||||
static int32_t strncmp(const char* aStr1, const char* aStr2,
|
||||
uint32_t aMaxLen)
|
||||
{
|
||||
return int32_t(PL_strncmp(aStr1, aStr2, aMaxLen));
|
||||
}
|
||||
|
||||
/// Case-insensitive string comparison.
|
||||
static int32_t strcasecmp(const char* aStr1, const char* aStr2)
|
||||
{
|
||||
return int32_t(PL_strcasecmp(aStr1, aStr2));
|
||||
}
|
||||
|
||||
/// Case-insensitive string comparison with length
|
||||
static int32_t strncasecmp(const char* aStr1, const char* aStr2,
|
||||
uint32_t aMaxLen)
|
||||
{
|
||||
int32_t result = int32_t(PL_strncasecmp(aStr1, aStr2, aMaxLen));
|
||||
//Egads. PL_strncasecmp is returning *very* negative numbers.
|
||||
//Some folks expect -1,0,1, so let's temper its enthusiasm.
|
||||
if (result < 0) {
|
||||
result = -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int32_t strncmp(const char* aStr1, const char* aStr2, int32_t aMaxLen)
|
||||
{
|
||||
// inline the first test (assumes strings are not null):
|
||||
int32_t diff =
|
||||
((const unsigned char*)aStr1)[0] - ((const unsigned char*)aStr2)[0];
|
||||
if (diff != 0) {
|
||||
return diff;
|
||||
}
|
||||
return int32_t(PL_strncmp(aStr1, aStr2, unsigned(aMaxLen)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
How to use this fancy (thread-safe) version of strtok:
|
||||
|
||||
void main(void) {
|
||||
printf("%s\n\nTokens:\n", string);
|
||||
// Establish string and get the first token:
|
||||
char* newStr;
|
||||
token = nsCRT::strtok(string, seps, &newStr);
|
||||
while (token != nullptr) {
|
||||
// While there are tokens in "string"
|
||||
printf(" %s\n", token);
|
||||
// Get next token:
|
||||
token = nsCRT::strtok(newStr, seps, &newStr);
|
||||
}
|
||||
}
|
||||
* WARNING - STRTOK WHACKS str THE FIRST TIME IT IS CALLED *
|
||||
* MAKE A COPY OF str IF YOU NEED TO USE IT AFTER strtok() *
|
||||
*/
|
||||
static char* strtok(char* aStr, const char* aDelims, char** aNewStr);
|
||||
|
||||
/// Like strcmp except for ucs2 strings
|
||||
static int32_t strcmp(const char16_t* aStr1, const char16_t* aStr2);
|
||||
/// Like strcmp except for ucs2 strings
|
||||
static int32_t strncmp(const char16_t* aStr1, const char16_t* aStr2,
|
||||
uint32_t aMaxLen);
|
||||
|
||||
// The GNU libc has memmem, which is strstr except for binary data
|
||||
// This is our own implementation that uses memmem on platforms
|
||||
// where it's available.
|
||||
static const char* memmem(const char* aHaystack, uint32_t aHaystackLen,
|
||||
const char* aNeedle, uint32_t aNeedleLen);
|
||||
|
||||
// String to longlong
|
||||
static int64_t atoll(const char* aStr);
|
||||
|
||||
static char ToUpper(char aChar) { return NS_ToUpper(aChar); }
|
||||
static char ToLower(char aChar) { return NS_ToLower(aChar); }
|
||||
|
||||
static bool IsUpper(char aChar) { return NS_IsUpper(aChar); }
|
||||
static bool IsLower(char aChar) { return NS_IsLower(aChar); }
|
||||
|
||||
static bool IsAscii(char16_t aChar) { return NS_IsAscii(aChar); }
|
||||
static bool IsAscii(const char16_t* aString) { return NS_IsAscii(aString); }
|
||||
static bool IsAsciiAlpha(char16_t aChar) { return NS_IsAsciiAlpha(aChar); }
|
||||
static bool IsAsciiDigit(char16_t aChar) { return NS_IsAsciiDigit(aChar); }
|
||||
static bool IsAsciiSpace(char16_t aChar) { return NS_IsAsciiWhitespace(aChar); }
|
||||
static bool IsAscii(const char* aString) { return NS_IsAscii(aString); }
|
||||
static bool IsAscii(const char* aString, uint32_t aLength)
|
||||
{
|
||||
return NS_IsAscii(aString, aLength);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline bool
|
||||
NS_IS_SPACE(char16_t aChar)
|
||||
{
|
||||
return ((int(aChar) & 0x7f) == int(aChar)) && isspace(int(aChar));
|
||||
}
|
||||
|
||||
#define NS_IS_CNTRL(i) ((((unsigned int) (i)) > 0x7f) ? (int) 0 : iscntrl(i))
|
||||
#define NS_IS_DIGIT(i) ((((unsigned int) (i)) > 0x7f) ? (int) 0 : isdigit(i))
|
||||
#if defined(XP_WIN)
|
||||
#define NS_IS_ALPHA(VAL) (isascii((int)(VAL)) && isalpha((int)(VAL)))
|
||||
#else
|
||||
#define NS_IS_ALPHA(VAL) ((((unsigned int) (VAL)) > 0x7f) ? (int) 0 : isalpha((int)(VAL)))
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* nsCRT_h___ */
|
||||
200
xpcom/ds/nsCharSeparatedTokenizer.h
Normal file
200
xpcom/ds/nsCharSeparatedTokenizer.h
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __nsCharSeparatedTokenizer_h
|
||||
#define __nsCharSeparatedTokenizer_h
|
||||
|
||||
#include "mozilla/RangedPtr.h"
|
||||
|
||||
#include "nsDependentSubstring.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
/**
|
||||
* This parses a SeparatorChar-separated string into tokens.
|
||||
* Whitespace surrounding tokens is not treated as part of tokens, however
|
||||
* whitespace inside a token is. If the final token is the empty string, it is
|
||||
* not returned.
|
||||
*
|
||||
* Some examples, with SeparatorChar = ',':
|
||||
*
|
||||
* "foo, bar, baz" -> "foo" "bar" "baz"
|
||||
* "foo,bar,baz" -> "foo" "bar" "baz"
|
||||
* "foo , bar hi , baz" -> "foo" "bar hi" "baz"
|
||||
* "foo, ,bar,baz" -> "foo" "" "bar" "baz"
|
||||
* "foo,,bar,baz" -> "foo" "" "bar" "baz"
|
||||
* "foo,bar,baz," -> "foo" "bar" "baz"
|
||||
*
|
||||
* The function used for whitespace detection is a template argument.
|
||||
* By default, it is NS_IsAsciiWhitespace.
|
||||
*/
|
||||
template<typename DependentSubstringType, bool IsWhitespace(char16_t)>
|
||||
class nsTCharSeparatedTokenizer
|
||||
{
|
||||
typedef typename DependentSubstringType::char_type CharType;
|
||||
typedef typename DependentSubstringType::substring_type SubstringType;
|
||||
|
||||
public:
|
||||
// Flags -- only one for now. If we need more, they should be defined to
|
||||
// be 1 << 1, 1 << 2, etc. (They're masks, and aFlags is a bitfield.)
|
||||
enum
|
||||
{
|
||||
SEPARATOR_OPTIONAL = 1
|
||||
};
|
||||
|
||||
nsTCharSeparatedTokenizer(const SubstringType& aSource,
|
||||
CharType aSeparatorChar,
|
||||
uint32_t aFlags = 0)
|
||||
: mIter(aSource.Data(), aSource.Length())
|
||||
, mEnd(aSource.Data() + aSource.Length(), aSource.Data(),
|
||||
aSource.Length())
|
||||
, mSeparatorChar(aSeparatorChar)
|
||||
, mWhitespaceBeforeFirstToken(false)
|
||||
, mWhitespaceAfterCurrentToken(false)
|
||||
, mSeparatorAfterCurrentToken(false)
|
||||
, mSeparatorOptional(aFlags & SEPARATOR_OPTIONAL)
|
||||
{
|
||||
// Skip initial whitespace
|
||||
while (mIter < mEnd && IsWhitespace(*mIter)) {
|
||||
mWhitespaceBeforeFirstToken = true;
|
||||
++mIter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any more tokens are available.
|
||||
*/
|
||||
bool hasMoreTokens() const
|
||||
{
|
||||
MOZ_ASSERT(mIter == mEnd || !IsWhitespace(*mIter),
|
||||
"Should be at beginning of token if there is one");
|
||||
|
||||
return mIter < mEnd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if there is whitespace prior to the first token.
|
||||
*/
|
||||
bool whitespaceBeforeFirstToken() const
|
||||
{
|
||||
return mWhitespaceBeforeFirstToken;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if there is a separator after the current token.
|
||||
* Useful if you want to check whether the last token has a separator
|
||||
* after it which may not be valid.
|
||||
*/
|
||||
bool separatorAfterCurrentToken() const
|
||||
{
|
||||
return mSeparatorAfterCurrentToken;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if there is any whitespace after the current token.
|
||||
*/
|
||||
bool whitespaceAfterCurrentToken() const
|
||||
{
|
||||
return mWhitespaceAfterCurrentToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next token.
|
||||
*/
|
||||
const DependentSubstringType nextToken()
|
||||
{
|
||||
mozilla::RangedPtr<const CharType> tokenStart = mIter;
|
||||
mozilla::RangedPtr<const CharType> tokenEnd = mIter;
|
||||
|
||||
MOZ_ASSERT(mIter == mEnd || !IsWhitespace(*mIter),
|
||||
"Should be at beginning of token if there is one");
|
||||
|
||||
// Search until we hit separator or end (or whitespace, if a separator
|
||||
// isn't required -- see clause with 'break' below).
|
||||
while (mIter < mEnd && *mIter != mSeparatorChar) {
|
||||
// Skip to end of the current word.
|
||||
while (mIter < mEnd &&
|
||||
!IsWhitespace(*mIter) && *mIter != mSeparatorChar) {
|
||||
++mIter;
|
||||
}
|
||||
tokenEnd = mIter;
|
||||
|
||||
// Skip whitespace after the current word.
|
||||
mWhitespaceAfterCurrentToken = false;
|
||||
while (mIter < mEnd && IsWhitespace(*mIter)) {
|
||||
mWhitespaceAfterCurrentToken = true;
|
||||
++mIter;
|
||||
}
|
||||
if (mSeparatorOptional) {
|
||||
// We've hit (and skipped) whitespace, and that's sufficient to end
|
||||
// our token, regardless of whether we've reached a SeparatorChar.
|
||||
break;
|
||||
} // (else, we'll keep looping until we hit mEnd or SeparatorChar)
|
||||
}
|
||||
|
||||
mSeparatorAfterCurrentToken = (mIter != mEnd &&
|
||||
*mIter == mSeparatorChar);
|
||||
MOZ_ASSERT(mSeparatorOptional ||
|
||||
(mSeparatorAfterCurrentToken == (mIter < mEnd)),
|
||||
"If we require a separator and haven't hit the end of "
|
||||
"our string, then we shouldn't have left the loop "
|
||||
"unless we hit a separator");
|
||||
|
||||
// Skip separator (and any whitespace after it), if we're at one.
|
||||
if (mSeparatorAfterCurrentToken) {
|
||||
++mIter;
|
||||
|
||||
while (mIter < mEnd && IsWhitespace(*mIter)) {
|
||||
mWhitespaceAfterCurrentToken = true;
|
||||
++mIter;
|
||||
}
|
||||
}
|
||||
|
||||
return Substring(tokenStart.get(), tokenEnd.get());
|
||||
}
|
||||
|
||||
private:
|
||||
mozilla::RangedPtr<const CharType> mIter;
|
||||
const mozilla::RangedPtr<const CharType> mEnd;
|
||||
CharType mSeparatorChar;
|
||||
bool mWhitespaceBeforeFirstToken;
|
||||
bool mWhitespaceAfterCurrentToken;
|
||||
bool mSeparatorAfterCurrentToken;
|
||||
bool mSeparatorOptional;
|
||||
};
|
||||
|
||||
template<bool IsWhitespace(char16_t) = NS_IsAsciiWhitespace>
|
||||
class nsCharSeparatedTokenizerTemplate
|
||||
: public nsTCharSeparatedTokenizer<nsDependentSubstring, IsWhitespace>
|
||||
{
|
||||
public:
|
||||
nsCharSeparatedTokenizerTemplate(const nsSubstring& aSource,
|
||||
char16_t aSeparatorChar,
|
||||
uint32_t aFlags = 0)
|
||||
: nsTCharSeparatedTokenizer<nsDependentSubstring,
|
||||
IsWhitespace>(aSource, aSeparatorChar, aFlags)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef nsCharSeparatedTokenizerTemplate<> nsCharSeparatedTokenizer;
|
||||
|
||||
template<bool IsWhitespace(char16_t) = NS_IsAsciiWhitespace>
|
||||
class nsCCharSeparatedTokenizerTemplate
|
||||
: public nsTCharSeparatedTokenizer<nsDependentCSubstring, IsWhitespace>
|
||||
{
|
||||
public:
|
||||
nsCCharSeparatedTokenizerTemplate(const nsCSubstring& aSource,
|
||||
char aSeparatorChar,
|
||||
uint32_t aFlags = 0)
|
||||
: nsTCharSeparatedTokenizer<nsDependentCSubstring,
|
||||
IsWhitespace>(aSource, aSeparatorChar, aFlags)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef nsCCharSeparatedTokenizerTemplate<> nsCCharSeparatedTokenizer;
|
||||
|
||||
#endif /* __nsCharSeparatedTokenizer_h */
|
||||
171
xpcom/ds/nsCheapSets.h
Normal file
171
xpcom/ds/nsCheapSets.h
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __nsCheapSets_h__
|
||||
#define __nsCheapSets_h__
|
||||
|
||||
#include "nsTHashtable.h"
|
||||
#include <stdint.h>
|
||||
|
||||
enum nsCheapSetOperator
|
||||
{
|
||||
OpNext = 0, // enumerator says continue
|
||||
OpRemove = 1, // enumerator says remove and continue
|
||||
};
|
||||
|
||||
/**
|
||||
* A set that takes up minimal size when there are 0 or 1 entries in the set.
|
||||
* Use for cases where sizes of 0 and 1 are even slightly common.
|
||||
*/
|
||||
template<typename EntryType>
|
||||
class nsCheapSet
|
||||
{
|
||||
public:
|
||||
typedef typename EntryType::KeyType KeyType;
|
||||
typedef nsCheapSetOperator (*Enumerator)(EntryType* aEntry, void* userArg);
|
||||
|
||||
nsCheapSet() : mState(ZERO) {}
|
||||
~nsCheapSet() { Clear(); }
|
||||
|
||||
/**
|
||||
* Remove all entries.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
break;
|
||||
case ONE:
|
||||
GetSingleEntry()->~EntryType();
|
||||
break;
|
||||
case MANY:
|
||||
delete mUnion.table;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
break;
|
||||
}
|
||||
mState = ZERO;
|
||||
}
|
||||
|
||||
void Put(const KeyType aVal);
|
||||
|
||||
void Remove(const KeyType aVal);
|
||||
|
||||
bool Contains(const KeyType aVal)
|
||||
{
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
return false;
|
||||
case ONE:
|
||||
return GetSingleEntry()->KeyEquals(EntryType::KeyToPointer(aVal));
|
||||
case MANY:
|
||||
return !!mUnion.table->GetEntry(aVal);
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t EnumerateEntries(Enumerator aEnumFunc, void* aUserArg)
|
||||
{
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
return 0;
|
||||
case ONE:
|
||||
if (aEnumFunc(GetSingleEntry(), aUserArg) == OpRemove) {
|
||||
GetSingleEntry()->~EntryType();
|
||||
mState = ZERO;
|
||||
}
|
||||
return 1;
|
||||
case MANY: {
|
||||
uint32_t n = mUnion.table->Count();
|
||||
for (auto iter = mUnion.table->Iter(); !iter.Done(); iter.Next()) {
|
||||
auto entry = static_cast<EntryType*>(iter.Get());
|
||||
if (aEnumFunc(entry, aUserArg) == OpRemove) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EntryType* GetSingleEntry()
|
||||
{
|
||||
return reinterpret_cast<EntryType*>(&mUnion.singleEntry[0]);
|
||||
}
|
||||
|
||||
enum SetState
|
||||
{
|
||||
ZERO,
|
||||
ONE,
|
||||
MANY
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
nsTHashtable<EntryType>* table;
|
||||
char singleEntry[sizeof(EntryType)];
|
||||
} mUnion;
|
||||
enum SetState mState;
|
||||
};
|
||||
|
||||
template<typename EntryType>
|
||||
void
|
||||
nsCheapSet<EntryType>::Put(const KeyType aVal)
|
||||
{
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
new (GetSingleEntry()) EntryType(EntryType::KeyToPointer(aVal));
|
||||
mState = ONE;
|
||||
return;
|
||||
case ONE: {
|
||||
nsTHashtable<EntryType>* table = new nsTHashtable<EntryType>();
|
||||
EntryType* entry = GetSingleEntry();
|
||||
table->PutEntry(entry->GetKey());
|
||||
entry->~EntryType();
|
||||
mUnion.table = table;
|
||||
mState = MANY;
|
||||
}
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case MANY:
|
||||
mUnion.table->PutEntry(aVal);
|
||||
return;
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename EntryType>
|
||||
void
|
||||
nsCheapSet<EntryType>::Remove(const KeyType aVal)
|
||||
{
|
||||
switch (mState) {
|
||||
case ZERO:
|
||||
break;
|
||||
case ONE:
|
||||
if (Contains(aVal)) {
|
||||
GetSingleEntry()->~EntryType();
|
||||
mState = ZERO;
|
||||
}
|
||||
break;
|
||||
case MANY:
|
||||
mUnion.table->RemoveEntry(aVal);
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("bogus state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
570
xpcom/ds/nsExpirationTracker.h
Normal file
570
xpcom/ds/nsExpirationTracker.h
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef NSEXPIRATIONTRACKER_H_
|
||||
#define NSEXPIRATIONTRACKER_H_
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
/**
|
||||
* Data used to track the expiration state of an object. We promise that this
|
||||
* is 32 bits so that objects that includes this as a field can pad and align
|
||||
* efficiently.
|
||||
*/
|
||||
struct nsExpirationState
|
||||
{
|
||||
enum
|
||||
{
|
||||
NOT_TRACKED = (1U << 4) - 1,
|
||||
MAX_INDEX_IN_GENERATION = (1U << 28) - 1
|
||||
};
|
||||
|
||||
nsExpirationState() : mGeneration(NOT_TRACKED) {}
|
||||
bool IsTracked() { return mGeneration != NOT_TRACKED; }
|
||||
|
||||
/**
|
||||
* The generation that this object belongs to, or NOT_TRACKED.
|
||||
*/
|
||||
uint32_t mGeneration:4;
|
||||
uint32_t mIndexInGeneration:28;
|
||||
};
|
||||
|
||||
/**
|
||||
* ExpirationTracker classes:
|
||||
* - ExpirationTrackerImpl (Thread-safe class)
|
||||
* - nsExpirationTracker (Main-thread only class)
|
||||
*
|
||||
* These classes can track the lifetimes and usage of a large number of
|
||||
* objects, and send a notification some window of time after a live object was
|
||||
* last used. This is very useful when you manage a large number of objects
|
||||
* and want to flush some after they haven't been used for a while.
|
||||
* nsExpirationTracker is designed to be very space and time efficient.
|
||||
*
|
||||
* The type parameter T is the object type that we will track pointers to. T
|
||||
* must include an accessible method GetExpirationState() that returns a
|
||||
* pointer to an nsExpirationState associated with the object (preferably,
|
||||
* stored in a field of the object).
|
||||
*
|
||||
* The parameter K is the number of generations that will be used. Increasing
|
||||
* the number of generations narrows the window within which we promise
|
||||
* to fire notifications, at a slight increase in space cost for the tracker.
|
||||
* We require 2 <= K <= nsExpirationState::NOT_TRACKED (currently 15).
|
||||
*
|
||||
* To use this class, you need to inherit from it and override the
|
||||
* NotifyExpired() method.
|
||||
*
|
||||
* The approach is to track objects in K generations. When an object is accessed
|
||||
* it moves from its current generation to the newest generation. Generations
|
||||
* are stored in a cyclic array; when a timer interrupt fires, we advance
|
||||
* the current generation pointer to effectively age all objects very efficiently.
|
||||
* By storing information in each object about its generation and index within its
|
||||
* generation array, we make removal of objects from a generation very cheap.
|
||||
*
|
||||
* Future work:
|
||||
* -- Add a method to change the timer period?
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for ExiprationTracker implementations.
|
||||
*
|
||||
* nsExpirationTracker class below is a specialized class to be inherited by the
|
||||
* instances to be accessed only on main-thread.
|
||||
*
|
||||
* For creating a thread-safe tracker, you can define a subclass inheriting this
|
||||
* base class and specialize the Mutex and AutoLock to be used.
|
||||
*
|
||||
*/
|
||||
template<typename T, uint32_t K, typename Mutex, typename AutoLock>
|
||||
class ExpirationTrackerImpl
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initialize the tracker.
|
||||
* @param aTimerPeriod the timer period in milliseconds. The guarantees
|
||||
* provided by the tracker are defined in terms of this period. If the
|
||||
* period is zero, then we don't use a timer and rely on someone calling
|
||||
* AgeOneGenerationLocked explicitly.
|
||||
*/
|
||||
ExpirationTrackerImpl(uint32_t aTimerPeriod, const char* aName)
|
||||
: mTimerPeriod(aTimerPeriod)
|
||||
, mNewestGeneration(0)
|
||||
, mInAgeOneGeneration(false)
|
||||
, mName(aName)
|
||||
{
|
||||
static_assert(K >= 2 && K <= nsExpirationState::NOT_TRACKED,
|
||||
"Unsupported number of generations (must be 2 <= K <= 15)");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mObserver = new ExpirationTrackerObserver();
|
||||
mObserver->Init(this);
|
||||
}
|
||||
|
||||
virtual ~ExpirationTrackerImpl()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
}
|
||||
mObserver->Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object to be tracked. It must not already be tracked. It will
|
||||
* be added to the newest generation, i.e., as if it was just used.
|
||||
* @return an error on out-of-memory
|
||||
*/
|
||||
nsresult AddObjectLocked(T* aObj, const AutoLock& aAutoLock)
|
||||
{
|
||||
nsExpirationState* state = aObj->GetExpirationState();
|
||||
NS_ASSERTION(!state->IsTracked(),
|
||||
"Tried to add an object that's already tracked");
|
||||
nsTArray<T*>& generation = mGenerations[mNewestGeneration];
|
||||
uint32_t index = generation.Length();
|
||||
if (index > nsExpirationState::MAX_INDEX_IN_GENERATION) {
|
||||
NS_WARNING("More than 256M elements tracked, this is probably a problem");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (index == 0) {
|
||||
// We might need to start the timer
|
||||
nsresult rv = CheckStartTimerLocked(aAutoLock);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
if (!generation.AppendElement(aObj)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
state->mGeneration = mNewestGeneration;
|
||||
state->mIndexInGeneration = index;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an object from the tracker. It must currently be tracked.
|
||||
*/
|
||||
void RemoveObjectLocked(T* aObj, const AutoLock& aAutoLock)
|
||||
{
|
||||
nsExpirationState* state = aObj->GetExpirationState();
|
||||
NS_ASSERTION(state->IsTracked(), "Tried to remove an object that's not tracked");
|
||||
nsTArray<T*>& generation = mGenerations[state->mGeneration];
|
||||
uint32_t index = state->mIndexInGeneration;
|
||||
NS_ASSERTION(generation.Length() > index &&
|
||||
generation[index] == aObj, "Object is lying about its index");
|
||||
// Move the last object to fill the hole created by removing aObj
|
||||
uint32_t last = generation.Length() - 1;
|
||||
T* lastObj = generation[last];
|
||||
generation[index] = lastObj;
|
||||
lastObj->GetExpirationState()->mIndexInGeneration = index;
|
||||
generation.RemoveElementAt(last);
|
||||
state->mGeneration = nsExpirationState::NOT_TRACKED;
|
||||
// We do not check whether we need to stop the timer here. The timer
|
||||
// will check that itself next time it fires. Checking here would not
|
||||
// be efficient since we'd need to track all generations. Also we could
|
||||
// thrash by incessantly creating and destroying timers if someone
|
||||
// kept adding and removing an object from the tracker.
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that an object has been used.
|
||||
* @return an error if we lost the object from the tracker...
|
||||
*/
|
||||
nsresult MarkUsedLocked(T* aObj, const AutoLock& aAutoLock)
|
||||
{
|
||||
nsExpirationState* state = aObj->GetExpirationState();
|
||||
if (mNewestGeneration == state->mGeneration) {
|
||||
return NS_OK;
|
||||
}
|
||||
RemoveObjectLocked(aObj, aAutoLock);
|
||||
return AddObjectLocked(aObj, aAutoLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* The timer calls this, but it can also be manually called if you want
|
||||
* to age objects "artifically". This can result in calls to NotifyExpiredLocked.
|
||||
*/
|
||||
void AgeOneGenerationLocked(const AutoLock& aAutoLock)
|
||||
{
|
||||
if (mInAgeOneGeneration) {
|
||||
NS_WARNING("Can't reenter AgeOneGeneration from NotifyExpired");
|
||||
return;
|
||||
}
|
||||
|
||||
mInAgeOneGeneration = true;
|
||||
uint32_t reapGeneration =
|
||||
mNewestGeneration > 0 ? mNewestGeneration - 1 : K - 1;
|
||||
nsTArray<T*>& generation = mGenerations[reapGeneration];
|
||||
// The following is rather tricky. We have to cope with objects being
|
||||
// removed from this generation either because of a call to RemoveObject
|
||||
// (or indirectly via MarkUsedLocked) inside NotifyExpiredLocked. Fortunately
|
||||
// no objects can be added to this generation because it's not the newest
|
||||
// generation. We depend on the fact that RemoveObject can only cause
|
||||
// the indexes of objects in this generation to *decrease*, not increase.
|
||||
// So if we start from the end and work our way backwards we are guaranteed
|
||||
// to see each object at least once.
|
||||
size_t index = generation.Length();
|
||||
for (;;) {
|
||||
// Objects could have been removed so index could be outside
|
||||
// the array
|
||||
index = XPCOM_MIN(index, generation.Length());
|
||||
if (index == 0) {
|
||||
break;
|
||||
}
|
||||
--index;
|
||||
NotifyExpiredLocked(generation[index], aAutoLock);
|
||||
}
|
||||
// Any leftover objects from reapGeneration just end up in the new
|
||||
// newest-generation. This is bad form, though, so warn if there are any.
|
||||
if (!generation.IsEmpty()) {
|
||||
NS_WARNING("Expired objects were not removed or marked used");
|
||||
}
|
||||
// Free excess memory used by the generation array, since we probably
|
||||
// just removed most or all of its elements.
|
||||
generation.Compact();
|
||||
mNewestGeneration = reapGeneration;
|
||||
mInAgeOneGeneration = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This just calls AgeOneGenerationLocked K times. Under normal circumstances
|
||||
* this will result in all objects getting NotifyExpiredLocked called on them,
|
||||
* but if NotifyExpiredLocked itself marks some objects as used, then those
|
||||
* objects might not expire. This would be a good thing to call if we get into
|
||||
* a critically-low memory situation.
|
||||
*/
|
||||
void AgeAllGenerationsLocked(const AutoLock& aAutoLock)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < K; ++i) {
|
||||
AgeOneGenerationLocked(aAutoLock);
|
||||
}
|
||||
}
|
||||
|
||||
class Iterator
|
||||
{
|
||||
private:
|
||||
ExpirationTrackerImpl<T, K, Mutex, AutoLock>* mTracker;
|
||||
uint32_t mGeneration;
|
||||
uint32_t mIndex;
|
||||
public:
|
||||
Iterator(ExpirationTrackerImpl<T, K, Mutex, AutoLock>* aTracker,
|
||||
AutoLock& aAutoLock)
|
||||
: mTracker(aTracker)
|
||||
, mGeneration(0)
|
||||
, mIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
T* Next()
|
||||
{
|
||||
while (mGeneration < K) {
|
||||
nsTArray<T*>* generation = &mTracker->mGenerations[mGeneration];
|
||||
if (mIndex < generation->Length()) {
|
||||
++mIndex;
|
||||
return (*generation)[mIndex - 1];
|
||||
}
|
||||
++mGeneration;
|
||||
mIndex = 0;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
friend class Iterator;
|
||||
|
||||
bool IsEmptyLocked(const AutoLock& aAutoLock)
|
||||
{
|
||||
for (uint32_t i = 0; i < K; ++i) {
|
||||
if (!mGenerations[i].IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This must be overridden to catch notifications. It is called whenever
|
||||
* we detect that an object has not been used for at least (K-1)*mTimerPeriod
|
||||
* milliseconds. If timer events are not delayed, it will be called within
|
||||
* roughly K*mTimerPeriod milliseconds after the last use.
|
||||
* (Unless AgeOneGenerationLocked or AgeAllGenerationsLocked have been called
|
||||
* to accelerate the aging process.)
|
||||
*
|
||||
* NOTE: These bounds ignore delays in timer firings due to actual work being
|
||||
* performed by the browser. We use a slack timer so there is always at least
|
||||
* mTimerPeriod milliseconds between firings, which gives us (K-1)*mTimerPeriod
|
||||
* as a pretty solid lower bound. The upper bound is rather loose, however.
|
||||
* If the maximum amount by which any given timer firing is delayed is D, then
|
||||
* the upper bound before NotifyExpiredLocked is called is K*(mTimerPeriod + D).
|
||||
*
|
||||
* The NotifyExpiredLocked call is expected to remove the object from the tracker,
|
||||
* but it need not. The object (or other objects) could be "resurrected"
|
||||
* by calling MarkUsedLocked() on them, or they might just not be removed.
|
||||
* Any objects left over that have not been resurrected or removed
|
||||
* are placed in the new newest-generation, but this is considered "bad form"
|
||||
* and should be avoided (we'll issue a warning). (This recycling counts
|
||||
* as "a use" for the purposes of the expiry guarantee above...)
|
||||
*
|
||||
* For robustness and simplicity, we allow objects to be notified more than
|
||||
* once here in the same timer tick.
|
||||
*/
|
||||
virtual void NotifyExpiredLocked(T*, const AutoLock&) = 0;
|
||||
|
||||
virtual Mutex& GetMutex() = 0;
|
||||
|
||||
private:
|
||||
class ExpirationTrackerObserver;
|
||||
RefPtr<ExpirationTrackerObserver> mObserver;
|
||||
nsTArray<T*> mGenerations[K];
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
uint32_t mTimerPeriod;
|
||||
uint32_t mNewestGeneration;
|
||||
bool mInAgeOneGeneration;
|
||||
const char* const mName; // Used for timer firing profiling.
|
||||
|
||||
/**
|
||||
* Whenever "memory-pressure" is observed, it calls AgeAllGenerationsLocked()
|
||||
* to minimize memory usage.
|
||||
*/
|
||||
class ExpirationTrackerObserver final : public nsIObserver
|
||||
{
|
||||
public:
|
||||
void Init(ExpirationTrackerImpl<T, K, Mutex, AutoLock>* aObj)
|
||||
{
|
||||
mOwner = aObj;
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "memory-pressure", false);
|
||||
}
|
||||
}
|
||||
void Destroy()
|
||||
{
|
||||
mOwner = nullptr;
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "memory-pressure");
|
||||
}
|
||||
}
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
private:
|
||||
ExpirationTrackerImpl<T, K, Mutex, AutoLock>* mOwner;
|
||||
};
|
||||
|
||||
void HandleLowMemory() {
|
||||
AutoLock lock(GetMutex());
|
||||
AgeAllGenerationsLocked(lock);
|
||||
}
|
||||
|
||||
void HandleTimeout() {
|
||||
AutoLock lock(GetMutex());
|
||||
AgeOneGenerationLocked(lock);
|
||||
// Cancel the timer if we have no objects to track
|
||||
if (IsEmptyLocked(lock)) {
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void TimerCallback(nsITimer* aTimer, void* aThis)
|
||||
{
|
||||
ExpirationTrackerImpl* tracker = static_cast<ExpirationTrackerImpl*>(aThis);
|
||||
tracker->HandleTimeout();
|
||||
}
|
||||
|
||||
nsresult CheckStartTimerLocked(const AutoLock& aAutoLock)
|
||||
{
|
||||
if (mTimer || !mTimerPeriod) {
|
||||
return NS_OK;
|
||||
}
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (!mTimer) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!NS_IsMainThread()) {
|
||||
// TimerCallback should always be run on the main thread to prevent races
|
||||
// to the destruction of the tracker.
|
||||
nsCOMPtr<nsIEventTarget> target = do_GetMainThread();
|
||||
NS_ENSURE_STATE(target);
|
||||
mTimer->SetTarget(target);
|
||||
}
|
||||
mTimer->InitWithNamedFuncCallback(TimerCallback, this, mTimerPeriod,
|
||||
nsITimer::TYPE_REPEATING_SLACK, mName);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
class PlaceholderLock {
|
||||
public:
|
||||
void Lock() {}
|
||||
void Unlock() {}
|
||||
};
|
||||
|
||||
class PlaceholderAutoLock {
|
||||
public:
|
||||
explicit PlaceholderAutoLock(PlaceholderLock&) { }
|
||||
~PlaceholderAutoLock() = default;
|
||||
|
||||
};
|
||||
|
||||
template<typename T, uint32_t K>
|
||||
using SingleThreadedExpirationTracker =
|
||||
ExpirationTrackerImpl<T, K, PlaceholderLock, PlaceholderAutoLock>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, uint32_t K>
|
||||
class nsExpirationTracker : protected ::detail::SingleThreadedExpirationTracker<T, K>
|
||||
{
|
||||
typedef ::detail::PlaceholderLock Lock;
|
||||
typedef ::detail::PlaceholderAutoLock AutoLock;
|
||||
|
||||
Lock mLock;
|
||||
|
||||
AutoLock FakeLock() {
|
||||
return AutoLock(mLock);
|
||||
}
|
||||
|
||||
Lock& GetMutex() override
|
||||
{
|
||||
return mLock;
|
||||
}
|
||||
|
||||
void NotifyExpiredLocked(T* aObject, const AutoLock&) override
|
||||
{
|
||||
NotifyExpired(aObject);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void NotifyExpired(T* aObj) = 0;
|
||||
|
||||
public:
|
||||
nsExpirationTracker(uint32_t aTimerPeriod, const char* aName)
|
||||
: ::detail::SingleThreadedExpirationTracker<T, K>(aTimerPeriod, aName)
|
||||
{ }
|
||||
|
||||
virtual ~nsExpirationTracker()
|
||||
{ }
|
||||
|
||||
nsresult AddObject(T* aObj)
|
||||
{
|
||||
return this->AddObjectLocked(aObj, FakeLock());
|
||||
}
|
||||
|
||||
void RemoveObject(T* aObj)
|
||||
{
|
||||
this->RemoveObjectLocked(aObj, FakeLock());
|
||||
}
|
||||
|
||||
nsresult MarkUsed(T* aObj)
|
||||
{
|
||||
return this->MarkUsedLocked(aObj, FakeLock());
|
||||
}
|
||||
|
||||
void AgeOneGeneration()
|
||||
{
|
||||
this->AgeOneGenerationLocked(FakeLock());
|
||||
}
|
||||
|
||||
void AgeAllGenerations()
|
||||
{
|
||||
this->AgeAllGenerationsLocked(FakeLock());
|
||||
}
|
||||
|
||||
class Iterator
|
||||
{
|
||||
private:
|
||||
AutoLock mAutoLock;
|
||||
typename ExpirationTrackerImpl<T, K, Lock, AutoLock>::Iterator mIterator;
|
||||
public:
|
||||
explicit Iterator(nsExpirationTracker<T, K>* aTracker)
|
||||
: mAutoLock(aTracker->GetMutex())
|
||||
, mIterator(aTracker, mAutoLock)
|
||||
{
|
||||
}
|
||||
|
||||
T* Next()
|
||||
{
|
||||
return mIterator.Next();
|
||||
}
|
||||
};
|
||||
|
||||
friend class Iterator;
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
return this->IsEmptyLocked(FakeLock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, uint32_t K, typename Mutex, typename AutoLock>
|
||||
NS_IMETHODIMP
|
||||
ExpirationTrackerImpl<T, K, Mutex, AutoLock>::
|
||||
ExpirationTrackerObserver::Observe(
|
||||
nsISupports* aSubject, const char* aTopic, const char16_t* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "memory-pressure") && mOwner) {
|
||||
mOwner->HandleLowMemory();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<class T, uint32_t K, typename Mutex, typename AutoLock>
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
ExpirationTrackerImpl<T, K, Mutex, AutoLock>::
|
||||
ExpirationTrackerObserver::AddRef(void)
|
||||
{
|
||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
|
||||
NS_ASSERT_OWNINGTHREAD(ExpirationTrackerObserver);
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "ExpirationTrackerObserver", sizeof(*this));
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
template<class T, uint32_t K, typename Mutex, typename AutoLock>
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
ExpirationTrackerImpl<T, K, Mutex, AutoLock>::
|
||||
ExpirationTrackerObserver::Release(void)
|
||||
{
|
||||
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
|
||||
NS_ASSERT_OWNINGTHREAD(ExpirationTrackerObserver);
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "ExpirationTrackerObserver");
|
||||
if (mRefCnt == 0) {
|
||||
NS_ASSERT_OWNINGTHREAD(ExpirationTrackerObserver);
|
||||
mRefCnt = 1; /* stabilize */
|
||||
delete (this);
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
template<class T, uint32_t K, typename Mutex, typename AutoLock>
|
||||
NS_IMETHODIMP
|
||||
ExpirationTrackerImpl<T, K, Mutex, AutoLock>::
|
||||
ExpirationTrackerObserver::QueryInterface(
|
||||
REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
NS_ASSERTION(aInstancePtr,
|
||||
"QueryInterface requires a non-NULL destination!");
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
NS_INTERFACE_TABLE(ExpirationTrackerObserver, nsIObserver)
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif /*NSEXPIRATIONTRACKER_H_*/
|
||||
284
xpcom/ds/nsHashPropertyBag.cpp
Normal file
284
xpcom/ds/nsHashPropertyBag.cpp
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "nsArray.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsIProperty.h"
|
||||
#include "nsVariant.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
/*
|
||||
* nsHashPropertyBagBase implementation.
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::HasKey(const nsAString& aName, bool* aResult)
|
||||
{
|
||||
*aResult = mPropertyHash.Get(aName, nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::Get(const nsAString& aName, nsIVariant** aResult)
|
||||
{
|
||||
if (!mPropertyHash.Get(aName, aResult)) {
|
||||
*aResult = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::GetProperty(const nsAString& aName, nsIVariant** aResult)
|
||||
{
|
||||
bool isFound = mPropertyHash.Get(aName, aResult);
|
||||
if (!isFound) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::SetProperty(const nsAString& aName, nsIVariant* aValue)
|
||||
{
|
||||
if (NS_WARN_IF(!aValue)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mPropertyHash.Put(aName, aValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::DeleteProperty(const nsAString& aName)
|
||||
{
|
||||
// is it too much to ask for ns*Hashtable to return
|
||||
// a boolean indicating whether RemoveEntry succeeded
|
||||
// or not?!?!
|
||||
bool isFound = mPropertyHash.Get(aName, nullptr);
|
||||
if (!isFound) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// then from the hash
|
||||
mPropertyHash.Remove(aName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// nsSimpleProperty class and impl; used for GetEnumerator
|
||||
//
|
||||
|
||||
class nsSimpleProperty final : public nsIProperty
|
||||
{
|
||||
~nsSimpleProperty() {}
|
||||
|
||||
public:
|
||||
nsSimpleProperty(const nsAString& aName, nsIVariant* aValue)
|
||||
: mName(aName)
|
||||
, mValue(aValue)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPROPERTY
|
||||
protected:
|
||||
nsString mName;
|
||||
nsCOMPtr<nsIVariant> mValue;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSimpleProperty, nsIProperty)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSimpleProperty::GetName(nsAString& aName)
|
||||
{
|
||||
aName.Assign(mName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSimpleProperty::GetValue(nsIVariant** aValue)
|
||||
{
|
||||
NS_IF_ADDREF(*aValue = mValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// end nsSimpleProperty
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::GetEnumerator(nsISimpleEnumerator** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIMutableArray> propertyArray = nsArray::Create();
|
||||
if (!propertyArray) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
const nsAString& key = iter.Key();
|
||||
nsIVariant* data = iter.UserData();
|
||||
nsSimpleProperty* sprop = new nsSimpleProperty(key, data);
|
||||
propertyArray->AppendElement(sprop, false);
|
||||
}
|
||||
|
||||
return NS_NewArrayEnumerator(aResult, propertyArray);
|
||||
}
|
||||
|
||||
#define IMPL_GETSETPROPERTY_AS(Name, Type) \
|
||||
NS_IMETHODIMP \
|
||||
nsHashPropertyBagBase::GetPropertyAs ## Name (const nsAString & prop, Type *_retval) \
|
||||
{ \
|
||||
nsIVariant* v = mPropertyHash.GetWeak(prop); \
|
||||
if (!v) \
|
||||
return NS_ERROR_NOT_AVAILABLE; \
|
||||
return v->GetAs ## Name(_retval); \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP \
|
||||
nsHashPropertyBagBase::SetPropertyAs ## Name (const nsAString & prop, Type value) \
|
||||
{ \
|
||||
nsCOMPtr<nsIWritableVariant> var = new nsVariant(); \
|
||||
var->SetAs ## Name(value); \
|
||||
return SetProperty(prop, var); \
|
||||
}
|
||||
|
||||
IMPL_GETSETPROPERTY_AS(Int32, int32_t)
|
||||
IMPL_GETSETPROPERTY_AS(Uint32, uint32_t)
|
||||
IMPL_GETSETPROPERTY_AS(Int64, int64_t)
|
||||
IMPL_GETSETPROPERTY_AS(Uint64, uint64_t)
|
||||
IMPL_GETSETPROPERTY_AS(Double, double)
|
||||
IMPL_GETSETPROPERTY_AS(Bool, bool)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::GetPropertyAsAString(const nsAString& aProp,
|
||||
nsAString& aResult)
|
||||
{
|
||||
nsIVariant* v = mPropertyHash.GetWeak(aProp);
|
||||
if (!v) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return v->GetAsAString(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::GetPropertyAsACString(const nsAString& aProp,
|
||||
nsACString& aResult)
|
||||
{
|
||||
nsIVariant* v = mPropertyHash.GetWeak(aProp);
|
||||
if (!v) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return v->GetAsACString(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::GetPropertyAsAUTF8String(const nsAString& aProp,
|
||||
nsACString& aResult)
|
||||
{
|
||||
nsIVariant* v = mPropertyHash.GetWeak(aProp);
|
||||
if (!v) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return v->GetAsAUTF8String(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::GetPropertyAsInterface(const nsAString& aProp,
|
||||
const nsIID& aIID,
|
||||
void** aResult)
|
||||
{
|
||||
nsIVariant* v = mPropertyHash.GetWeak(aProp);
|
||||
if (!v) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
nsCOMPtr<nsISupports> val;
|
||||
nsresult rv = v->GetAsISupports(getter_AddRefs(val));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (!val) {
|
||||
// We have a value, but it's null
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
return val->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::SetPropertyAsAString(const nsAString& aProp,
|
||||
const nsAString& aValue)
|
||||
{
|
||||
nsCOMPtr<nsIWritableVariant> var = new nsVariant();
|
||||
var->SetAsAString(aValue);
|
||||
return SetProperty(aProp, var);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::SetPropertyAsACString(const nsAString& aProp,
|
||||
const nsACString& aValue)
|
||||
{
|
||||
nsCOMPtr<nsIWritableVariant> var = new nsVariant();
|
||||
var->SetAsACString(aValue);
|
||||
return SetProperty(aProp, var);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::SetPropertyAsAUTF8String(const nsAString& aProp,
|
||||
const nsACString& aValue)
|
||||
{
|
||||
nsCOMPtr<nsIWritableVariant> var = new nsVariant();
|
||||
var->SetAsAUTF8String(aValue);
|
||||
return SetProperty(aProp, var);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashPropertyBagBase::SetPropertyAsInterface(const nsAString& aProp,
|
||||
nsISupports* aValue)
|
||||
{
|
||||
nsCOMPtr<nsIWritableVariant> var = new nsVariant();
|
||||
var->SetAsISupports(aValue);
|
||||
return SetProperty(aProp, var);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* nsHashPropertyBag implementation.
|
||||
*/
|
||||
|
||||
NS_IMPL_ADDREF(nsHashPropertyBag)
|
||||
NS_IMPL_RELEASE(nsHashPropertyBag)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsHashPropertyBag)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
/*
|
||||
* nsHashPropertyBagCC implementation.
|
||||
*/
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(nsHashPropertyBagCC, mPropertyHash)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHashPropertyBagCC)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHashPropertyBagCC)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHashPropertyBagCC)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
|
||||
NS_INTERFACE_MAP_END
|
||||
57
xpcom/ds/nsHashPropertyBag.h
Normal file
57
xpcom/ds/nsHashPropertyBag.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsHashPropertyBag_h___
|
||||
#define nsHashPropertyBag_h___
|
||||
|
||||
#include "nsIVariant.h"
|
||||
#include "nsIWritablePropertyBag.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
|
||||
class nsHashPropertyBagBase
|
||||
: public nsIWritablePropertyBag
|
||||
, public nsIWritablePropertyBag2
|
||||
{
|
||||
public:
|
||||
nsHashPropertyBagBase() {}
|
||||
|
||||
NS_DECL_NSIPROPERTYBAG
|
||||
NS_DECL_NSIPROPERTYBAG2
|
||||
|
||||
NS_DECL_NSIWRITABLEPROPERTYBAG
|
||||
NS_DECL_NSIWRITABLEPROPERTYBAG2
|
||||
|
||||
protected:
|
||||
// a hash table of string -> nsIVariant
|
||||
nsInterfaceHashtable<nsStringHashKey, nsIVariant> mPropertyHash;
|
||||
};
|
||||
|
||||
class nsHashPropertyBag : public nsHashPropertyBagBase
|
||||
{
|
||||
public:
|
||||
nsHashPropertyBag() {}
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
protected:
|
||||
virtual ~nsHashPropertyBag() {}
|
||||
};
|
||||
|
||||
/* A cycle collected nsHashPropertyBag for main-thread-only use. */
|
||||
class nsHashPropertyBagCC final : public nsHashPropertyBagBase
|
||||
{
|
||||
public:
|
||||
nsHashPropertyBagCC() {}
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHashPropertyBagCC,
|
||||
nsIWritablePropertyBag)
|
||||
protected:
|
||||
virtual ~nsHashPropertyBagCC() {}
|
||||
};
|
||||
|
||||
#endif /* nsHashPropertyBag_h___ */
|
||||
91
xpcom/ds/nsIArray.idl
Normal file
91
xpcom/ds/nsIArray.idl
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
/**
|
||||
* nsIArray
|
||||
*
|
||||
* An indexed collection of elements. Provides basic functionality for
|
||||
* retrieving elements at a specific position, searching for
|
||||
* elements. Indexes are zero-based, such that the last element in the
|
||||
* array is stored at the index length-1.
|
||||
*
|
||||
* For an array which can be modified, see nsIMutableArray below.
|
||||
*
|
||||
* Neither interface makes any attempt to protect the individual
|
||||
* elements from modification. The convention is that the elements of
|
||||
* the array should not be modified. Documentation within a specific
|
||||
* interface should describe variations from this convention.
|
||||
*
|
||||
* It is also convention that if an interface provides access to an
|
||||
* nsIArray, that the array should not be QueryInterfaced to an
|
||||
* nsIMutableArray for modification. If the interface in question had
|
||||
* intended the array to be modified, it would have returned an
|
||||
* nsIMutableArray!
|
||||
*
|
||||
* null is a valid entry in the array, and as such any nsISupports
|
||||
* parameters may be null, except where noted.
|
||||
*/
|
||||
[scriptable, uuid(114744d9-c369-456e-b55a-52fe52880d2d)]
|
||||
interface nsIArray : nsISupports
|
||||
{
|
||||
/**
|
||||
* length
|
||||
*
|
||||
* number of elements in the array.
|
||||
*/
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
/**
|
||||
* queryElementAt()
|
||||
*
|
||||
* Retrieve a specific element of the array, and QueryInterface it
|
||||
* to the specified interface. null is a valid result for
|
||||
* this method, but exceptions are thrown in other circumstances
|
||||
*
|
||||
* @param index position of element
|
||||
* @param uuid the IID of the requested interface
|
||||
* @param result the object, QI'd to the requested interface
|
||||
*
|
||||
* @throws NS_ERROR_NO_INTERFACE when an entry exists at the
|
||||
* specified index, but the requested interface is not
|
||||
* available.
|
||||
* @throws NS_ERROR_ILLEGAL_VALUE when index > length-1
|
||||
*
|
||||
*/
|
||||
void queryElementAt(in unsigned long index,
|
||||
in nsIIDRef uuid,
|
||||
[iid_is(uuid), retval] out nsQIResult result);
|
||||
|
||||
/**
|
||||
* indexOf()
|
||||
*
|
||||
* Get the position of a specific element. Note that since null is
|
||||
* a valid input, exceptions are used to indicate that an element
|
||||
* is not found.
|
||||
*
|
||||
* @param startIndex The initial element to search in the array
|
||||
* To start at the beginning, use 0 as the
|
||||
* startIndex
|
||||
* @param element The element you are looking for
|
||||
* @returns a number >= startIndex which is the position of the
|
||||
* element in the array.
|
||||
* @throws NS_ERROR_FAILURE if the element was not in the array.
|
||||
*/
|
||||
unsigned long indexOf(in unsigned long startIndex,
|
||||
in nsISupports element);
|
||||
|
||||
/**
|
||||
* enumerate the array
|
||||
*
|
||||
* @returns a new enumerator positioned at the start of the array
|
||||
* @throws NS_ERROR_FAILURE if the array is empty (to make it easy
|
||||
* to detect errors), or NS_ERROR_OUT_OF_MEMORY if out of memory.
|
||||
*/
|
||||
nsISimpleEnumerator enumerate();
|
||||
};
|
||||
51
xpcom/ds/nsIArrayExtensions.idl
Normal file
51
xpcom/ds/nsIArrayExtensions.idl
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsIArray.idl"
|
||||
|
||||
/**
|
||||
* Helper interface for allowing scripts to treat nsIArray instances as if
|
||||
* they were nsISupportsArray instances while iterating.
|
||||
*
|
||||
* nsISupportsArray is convenient to iterate over in JavaScript:
|
||||
*
|
||||
* for (let i = 0; i < array.Count(); ++i) {
|
||||
* let elem = array.GetElementAt(i);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* but doing the same with nsIArray is somewhat less convenient, since
|
||||
* queryElementAt is not nearly so nice to use from JavaScript. So we provide
|
||||
* this extension interface so interfaces that currently return
|
||||
* nsISupportsArray can start returning nsIArrayExtensions and all JavaScript
|
||||
* should Just Work. Eventually we'll roll this interface into nsIArray
|
||||
* itself, possibly getting rid of the Count() method, as it duplicates
|
||||
* nsIArray functionality.
|
||||
*/
|
||||
[scriptable, uuid(261d442e-050c-453d-8aaa-b3f23bcc528b)]
|
||||
interface nsIArrayExtensions : nsIArray
|
||||
{
|
||||
/**
|
||||
* Count()
|
||||
*
|
||||
* Retrieves the length of the array. This is an alias for the
|
||||
* |nsIArray.length| attribute.
|
||||
*/
|
||||
uint32_t Count();
|
||||
|
||||
/**
|
||||
* GetElementAt()
|
||||
*
|
||||
* Retrieve a specific element of the array. null is a valid result for
|
||||
* this method.
|
||||
*
|
||||
* Note: If the index is out of bounds null will be returned.
|
||||
* This differs from the behavior of nsIArray.queryElementAt() which
|
||||
* will throw if an invalid index is specified.
|
||||
*
|
||||
* @param index position of element
|
||||
*/
|
||||
nsISupports GetElementAt(in uint32_t index);
|
||||
};
|
||||
166
xpcom/ds/nsIAtom.idl
Normal file
166
xpcom/ds/nsIAtom.idl
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsStringBuffer.h"
|
||||
%}
|
||||
|
||||
native MallocSizeOf(mozilla::MallocSizeOf);
|
||||
|
||||
/*
|
||||
* Should this really be scriptable? Using atoms from script or proxies
|
||||
* could be dangerous since double-wrapping could lead to loss of
|
||||
* pointer identity.
|
||||
*/
|
||||
|
||||
[scriptable, builtinclass, uuid(8b8c11d4-3ed5-4079-8974-73c7576cdb34)]
|
||||
interface nsIAtom : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get the Unicode or UTF8 value for the string
|
||||
*/
|
||||
[binaryname(ScriptableToString)] AString toString();
|
||||
[noscript] AUTF8String toUTF8String();
|
||||
|
||||
/**
|
||||
* Compare the atom to a specific string value
|
||||
* Note that this will NEVER return/throw an error condition.
|
||||
*/
|
||||
[binaryname(ScriptableEquals)] boolean equals(in AString aString);
|
||||
|
||||
[noscript, notxpcom]
|
||||
size_t SizeOfIncludingThis(in MallocSizeOf aMallocSizeOf);
|
||||
|
||||
%{C++
|
||||
// note this is NOT virtual so this won't muck with the vtable!
|
||||
inline bool Equals(const nsAString& aString) const {
|
||||
return aString.Equals(nsDependentString(mString, mLength));
|
||||
}
|
||||
|
||||
inline bool IsStaticAtom() const {
|
||||
return mIsStatic;
|
||||
}
|
||||
|
||||
inline char16ptr_t GetUTF16String() const {
|
||||
return mString;
|
||||
}
|
||||
|
||||
inline uint32_t GetLength() const {
|
||||
return mLength;
|
||||
}
|
||||
|
||||
inline void ToString(nsAString& aBuf) {
|
||||
// See the comment on |mString|'s declaration.
|
||||
nsStringBuffer::FromData(mString)->ToString(mLength, aBuf);
|
||||
}
|
||||
|
||||
inline nsStringBuffer* GetStringBuffer() const {
|
||||
// See the comment on |mString|'s declaration.
|
||||
return nsStringBuffer::FromData(mString);
|
||||
}
|
||||
|
||||
/**
|
||||
* A hashcode that is better distributed than the actual atom
|
||||
* pointer, for use in situations that need a well-distributed
|
||||
* hashcode.
|
||||
*/
|
||||
inline uint32_t hash() const {
|
||||
return mHash;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t mLength:31;
|
||||
uint32_t mIsStatic:1;
|
||||
uint32_t mHash;
|
||||
/**
|
||||
* WARNING! There is an invisible constraint on |mString|: the chars it
|
||||
* points to must belong to an nsStringBuffer. This is so that the
|
||||
* nsStringBuffer::FromData() calls above are valid.
|
||||
*/
|
||||
char16_t* mString;
|
||||
%}
|
||||
};
|
||||
|
||||
|
||||
%{C++
|
||||
/*
|
||||
* The four forms of NS_Atomize (for use with |nsCOMPtr<nsIAtom>|) return the
|
||||
* atom for the string given. At any given time there will always be one atom
|
||||
* representing a given string. Atoms are intended to make string comparison
|
||||
* cheaper by simplifying it to pointer equality. A pointer to the atom that
|
||||
* does not own a reference is not guaranteed to be valid.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Find an atom that matches the given UTF-8 string.
|
||||
* The string is assumed to be zero terminated. Never returns null.
|
||||
*/
|
||||
extern already_AddRefed<nsIAtom> NS_Atomize(const char* aUTF8String);
|
||||
|
||||
/**
|
||||
* Find an atom that matches the given UTF-8 string. Never returns null.
|
||||
*/
|
||||
extern already_AddRefed<nsIAtom> NS_Atomize(const nsACString& aUTF8String);
|
||||
|
||||
/**
|
||||
* Find an atom that matches the given UTF-16 string.
|
||||
* The string is assumed to be zero terminated. Never returns null.
|
||||
*/
|
||||
extern already_AddRefed<nsIAtom> NS_Atomize(const char16_t* aUTF16String);
|
||||
|
||||
/**
|
||||
* Find an atom that matches the given UTF-16 string. Never returns null.
|
||||
*/
|
||||
extern already_AddRefed<nsIAtom> NS_Atomize(const nsAString& aUTF16String);
|
||||
|
||||
/**
|
||||
* Return a count of the total number of atoms currently
|
||||
* alive in the system.
|
||||
*/
|
||||
extern nsrefcnt NS_GetNumberOfAtoms(void);
|
||||
|
||||
/**
|
||||
* Return a pointer for a static atom for the string or null if there's
|
||||
* no static atom for this string.
|
||||
*/
|
||||
extern nsIAtom* NS_GetStaticAtom(const nsAString& aUTF16String);
|
||||
|
||||
/**
|
||||
* Seal the static atom table
|
||||
*/
|
||||
extern void NS_SealStaticAtomTable();
|
||||
|
||||
class nsAtomString : public nsString
|
||||
{
|
||||
public:
|
||||
explicit nsAtomString(nsIAtom* aAtom)
|
||||
{
|
||||
aAtom->ToString(*this);
|
||||
}
|
||||
};
|
||||
|
||||
class nsAtomCString : public nsCString
|
||||
{
|
||||
public:
|
||||
explicit nsAtomCString(nsIAtom* aAtom)
|
||||
{
|
||||
aAtom->ToUTF8String(*this);
|
||||
}
|
||||
};
|
||||
|
||||
class nsDependentAtomString : public nsDependentString
|
||||
{
|
||||
public:
|
||||
explicit nsDependentAtomString(nsIAtom* aAtom)
|
||||
: nsDependentString(aAtom->GetUTF16String(), aAtom->GetLength())
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
%}
|
||||
35
xpcom/ds/nsIAtomService.idl
Normal file
35
xpcom/ds/nsIAtomService.idl
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAtom;
|
||||
|
||||
%{C++
|
||||
#define NS_ATOMSERVICE_CID \
|
||||
{ /* ed3db3fc-0168-4cab-8818-98f5475a490c */ \
|
||||
0xed3db3fc, \
|
||||
0x0168, \
|
||||
0x4cab, \
|
||||
{0x88, 0x18, 0x98, 0xf5, 0x47, 0x5a, 0x49, 0x0c} }
|
||||
|
||||
#define NS_ATOMSERVICE_CONTRACTID "@mozilla.org/atom-service;1"
|
||||
%}
|
||||
|
||||
/*
|
||||
* Should this really be scriptable? Using atoms from script or proxies
|
||||
* could be dangerous since double-wrapping could lead to loss of
|
||||
* pointer identity.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(9c1f50b9-f9eb-42d4-a8cb-2c7600aeb241)]
|
||||
interface nsIAtomService : nsISupports {
|
||||
|
||||
/**
|
||||
* Version of NS_Atomize that doesn't require linking against the
|
||||
* XPCOM library. See nsIAtom.idl.
|
||||
*/
|
||||
nsIAtom getAtom(in AString value);
|
||||
};
|
||||
67
xpcom/ds/nsICollection.idl
Normal file
67
xpcom/ds/nsICollection.idl
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISerializable.idl"
|
||||
|
||||
interface nsIEnumerator;
|
||||
|
||||
[deprecated, scriptable, uuid(83b6019c-cbc4-11d2-8cca-0060b0fc14a3)]
|
||||
interface nsICollection : nsISerializable
|
||||
{
|
||||
|
||||
uint32_t Count();
|
||||
nsISupports GetElementAt(in uint32_t index);
|
||||
void QueryElementAt(in uint32_t index, in nsIIDRef uuid,
|
||||
[iid_is(uuid),retval] out nsQIResult result);
|
||||
void SetElementAt(in uint32_t index, in nsISupports item);
|
||||
void AppendElement(in nsISupports item);
|
||||
void RemoveElement(in nsISupports item);
|
||||
|
||||
/**
|
||||
* This clashes with |nsISimpleEnumerator nsIArray.enumerate()| (only on the
|
||||
* binary side), so it is renamed with a 'Deprecated' prefix in favor of the
|
||||
* non-deprecated |nsIArray.enumerate|.
|
||||
*/
|
||||
[binaryname(DeprecatedEnumerate)]
|
||||
nsIEnumerator Enumerate();
|
||||
|
||||
void Clear();
|
||||
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
||||
#ifndef nsCOMPtr_h__
|
||||
#include "nsCOMPtr.h"
|
||||
#endif
|
||||
|
||||
class MOZ_STACK_CLASS nsQueryElementAt : public nsCOMPtr_helper
|
||||
{
|
||||
public:
|
||||
nsQueryElementAt( nsICollection* aCollection, uint32_t aIndex, nsresult* aErrorPtr )
|
||||
: mCollection(aCollection),
|
||||
mIndex(aIndex),
|
||||
mErrorPtr(aErrorPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** )
|
||||
const override;
|
||||
|
||||
private:
|
||||
nsICollection* MOZ_NON_OWNING_REF mCollection;
|
||||
uint32_t mIndex;
|
||||
nsresult* mErrorPtr;
|
||||
};
|
||||
|
||||
inline
|
||||
const nsQueryElementAt
|
||||
do_QueryElementAt( nsICollection* aCollection, uint32_t aIndex, nsresult* aErrorPtr = 0 )
|
||||
{
|
||||
return nsQueryElementAt(aCollection, aIndex, aErrorPtr);
|
||||
}
|
||||
|
||||
%}
|
||||
50
xpcom/ds/nsIEnumerator.idl
Normal file
50
xpcom/ds/nsIEnumerator.idl
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
#define NS_ENUMERATOR_FALSE 1
|
||||
%}
|
||||
/*
|
||||
* DO NOT USE THIS INTERFACE. IT IS HORRIBLY BROKEN, USES NS_COMFALSE
|
||||
* AND IS BASICALLY IMPOSSIBLE TO USE CORRECTLY THROUGH PROXIES OR
|
||||
* XPCONNECT. IF YOU SEE NEW USES OF THIS INTERFACE IN CODE YOU ARE
|
||||
* REVIEWING, YOU SHOULD INSIST ON nsISimpleEnumerator.
|
||||
*
|
||||
* DON'T MAKE ME COME OVER THERE.
|
||||
*/
|
||||
[deprecated, scriptable, uuid(ad385286-cbc4-11d2-8cca-0060b0fc14a3)]
|
||||
interface nsIEnumerator : nsISupports {
|
||||
/** First will reset the list. will return NS_FAILED if no items
|
||||
*/
|
||||
void first();
|
||||
|
||||
/** Next will advance the list. will return failed if already at end
|
||||
*/
|
||||
void next();
|
||||
|
||||
/** CurrentItem will return the CurrentItem item it will fail if the
|
||||
* list is empty
|
||||
*/
|
||||
nsISupports currentItem();
|
||||
|
||||
/** return if the collection is at the end. that is the beginning following
|
||||
* a call to Prev and it is the end of the list following a call to next
|
||||
*/
|
||||
void isDone();
|
||||
};
|
||||
|
||||
[deprecated, uuid(75f158a0-cadd-11d2-8cca-0060b0fc14a3)]
|
||||
interface nsIBidirectionalEnumerator : nsIEnumerator {
|
||||
|
||||
/** Last will reset the list to the end. will return NS_FAILED if no items
|
||||
*/
|
||||
void last();
|
||||
|
||||
/** Prev will decrement the list. will return failed if already at beginning
|
||||
*/
|
||||
void prev();
|
||||
};
|
||||
24
xpcom/ds/nsIHashable.idl
Normal file
24
xpcom/ds/nsIHashable.idl
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Represents an object that can be stored in a hashtable.
|
||||
*/
|
||||
[scriptable, uuid(17e595fa-b57a-4933-bd0f-b1812e8ab188)]
|
||||
interface nsIHashable : nsISupports
|
||||
{
|
||||
/**
|
||||
* Is this object the equivalent of the other object?
|
||||
*/
|
||||
boolean equals(in nsIHashable aOther);
|
||||
|
||||
/**
|
||||
* A generated hashcode for this object. Objects that are equivalent
|
||||
* must have the same hash code. Getting this property should never
|
||||
* throw an exception!
|
||||
*/
|
||||
readonly attribute unsigned long hashCode;
|
||||
};
|
||||
58
xpcom/ds/nsIINIParser.idl
Normal file
58
xpcom/ds/nsIINIParser.idl
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIUTF8StringEnumerator;
|
||||
interface nsIFile;
|
||||
|
||||
[scriptable, uuid(7eb955f6-3e78-4d39-b72f-c1bf12a94bce)]
|
||||
interface nsIINIParser : nsISupports
|
||||
{
|
||||
/**
|
||||
* Enumerates the [section]s available in the INI file.
|
||||
*/
|
||||
nsIUTF8StringEnumerator getSections();
|
||||
|
||||
/**
|
||||
* Enumerates the keys available within a section.
|
||||
*/
|
||||
nsIUTF8StringEnumerator getKeys(in AUTF8String aSection);
|
||||
|
||||
/**
|
||||
* Get the value of a string for a particular section and key.
|
||||
*/
|
||||
AUTF8String getString(in AUTF8String aSection, in AUTF8String aKey);
|
||||
};
|
||||
|
||||
[scriptable, uuid(b67bb24b-31a3-4a6a-a5d9-0485c9af5a04)]
|
||||
interface nsIINIParserWriter : nsISupports
|
||||
{
|
||||
/**
|
||||
* Windows and the NSIS installer code sometimes expect INI files to be in
|
||||
* UTF-16 encoding. On Windows only, this flag to writeFile can be used to
|
||||
* change the encoding from its default UTF-8.
|
||||
*/
|
||||
const unsigned long WRITE_UTF16 = 0x1;
|
||||
|
||||
/**
|
||||
* Set the value of a string for a particular section and key.
|
||||
*/
|
||||
void setString(in AUTF8String aSection, in AUTF8String aKey, in AUTF8String aValue);
|
||||
|
||||
/**
|
||||
* Write to the INI file.
|
||||
*/
|
||||
void writeFile([optional] in nsIFile aINIFile,
|
||||
[optional] in unsigned long aFlags);
|
||||
};
|
||||
|
||||
[scriptable, uuid(ccae7ea5-1218-4b51-aecb-c2d8ecd46af9)]
|
||||
interface nsIINIParserFactory : nsISupports
|
||||
{
|
||||
/**
|
||||
* Create an iniparser instance from a local file.
|
||||
*/
|
||||
nsIINIParser createINIParser(in nsIFile aINIFile);
|
||||
};
|
||||
110
xpcom/ds/nsIMutableArray.idl
Normal file
110
xpcom/ds/nsIMutableArray.idl
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsIArrayExtensions.idl"
|
||||
|
||||
/**
|
||||
* nsIMutableArray
|
||||
* A separate set of methods that will act on the array. Consumers of
|
||||
* nsIArray should not QueryInterface to nsIMutableArray unless they
|
||||
* own the array.
|
||||
*
|
||||
* As above, it is legal to add null elements to the array. Note also
|
||||
* that null elements can be created as a side effect of
|
||||
* insertElementAt(). Conversely, if insertElementAt() is never used,
|
||||
* and null elements are never explicitly added to the array, then it
|
||||
* is guaranteed that queryElementAt() will never return a null value.
|
||||
*
|
||||
* Any of these methods may throw NS_ERROR_OUT_OF_MEMORY when the
|
||||
* array must grow to complete the call, but the allocation fails.
|
||||
*/
|
||||
[scriptable, uuid(af059da0-c85b-40ec-af07-ae4bfdc192cc)]
|
||||
interface nsIMutableArray : nsIArrayExtensions
|
||||
{
|
||||
/**
|
||||
* appendElement()
|
||||
*
|
||||
* Append an element at the end of the array.
|
||||
*
|
||||
* @param element The element to append.
|
||||
* @param weak Whether or not to store the element using a weak
|
||||
* reference.
|
||||
* @throws NS_ERROR_FAILURE when a weak reference is requested,
|
||||
* but the element does not support
|
||||
* nsIWeakReference.
|
||||
*/
|
||||
void appendElement(in nsISupports element, in boolean weak);
|
||||
|
||||
/**
|
||||
* removeElementAt()
|
||||
*
|
||||
* Remove an element at a specific position, moving all elements
|
||||
* stored at a higher position down one.
|
||||
* To remove a specific element, use indexOf() to find the index
|
||||
* first, then call removeElementAt().
|
||||
*
|
||||
* @param index the position of the item
|
||||
*
|
||||
*/
|
||||
void removeElementAt(in unsigned long index);
|
||||
|
||||
/**
|
||||
* insertElementAt()
|
||||
*
|
||||
* Insert an element at the given position, moving the element
|
||||
* currently located in that position, and all elements in higher
|
||||
* position, up by one.
|
||||
*
|
||||
* @param element The element to insert
|
||||
* @param index The position in the array:
|
||||
* If the position is lower than the current length
|
||||
* of the array, the elements at that position and
|
||||
* onwards are bumped one position up.
|
||||
* If the position is equal to the current length
|
||||
* of the array, the new element is appended.
|
||||
* An index lower than 0 or higher than the current
|
||||
* length of the array is invalid and will be ignored.
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE when a weak reference is requested,
|
||||
* but the element does not support
|
||||
* nsIWeakReference.
|
||||
*/
|
||||
void insertElementAt(in nsISupports element, in unsigned long index,
|
||||
in boolean weak);
|
||||
|
||||
/**
|
||||
* replaceElementAt()
|
||||
*
|
||||
* Replace the element at the given position.
|
||||
*
|
||||
* @param element The new element to insert
|
||||
* @param index The position in the array
|
||||
* If the position is lower than the current length
|
||||
* of the array, an existing element will be replaced.
|
||||
* If the position is equal to the current length
|
||||
* of the array, the new element is appended.
|
||||
* If the position is higher than the current length
|
||||
* of the array, empty elements are appended followed
|
||||
* by the new element at the specified position.
|
||||
* An index lower than 0 is invalid and will be ignored.
|
||||
*
|
||||
* @param weak Whether or not to store the new element using a weak
|
||||
* reference.
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE when a weak reference is requested,
|
||||
* but the element does not support
|
||||
* nsIWeakReference.
|
||||
*/
|
||||
void replaceElementAt(in nsISupports element, in unsigned long index,
|
||||
in boolean weak);
|
||||
|
||||
|
||||
/**
|
||||
* clear()
|
||||
*
|
||||
* clear the entire array, releasing all stored objects
|
||||
*/
|
||||
void clear();
|
||||
};
|
||||
142
xpcom/ds/nsINIParserImpl.cpp
Normal file
142
xpcom/ds/nsINIParserImpl.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsINIParserImpl.h"
|
||||
|
||||
#include "nsINIParser.h"
|
||||
#include "nsStringEnumerator.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsINIParserImpl final
|
||||
: public nsIINIParser
|
||||
{
|
||||
~nsINIParserImpl() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINIPARSER
|
||||
|
||||
nsresult Init(nsIFile* aINIFile) { return mParser.Init(aINIFile); }
|
||||
|
||||
private:
|
||||
nsINIParser mParser;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsINIParserFactory,
|
||||
nsIINIParserFactory,
|
||||
nsIFactory)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsINIParserFactory::CreateINIParser(nsIFile* aINIFile,
|
||||
nsIINIParser** aResult)
|
||||
{
|
||||
*aResult = nullptr;
|
||||
|
||||
RefPtr<nsINIParserImpl> p(new nsINIParserImpl());
|
||||
if (!p) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult rv = p->Init(aINIFile);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ADDREF(*aResult = p);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsINIParserFactory::CreateInstance(nsISupports* aOuter,
|
||||
REFNSIID aIID,
|
||||
void** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(aOuter)) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
// We are our own singleton.
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsINIParserFactory::LockFactory(bool aLock)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsINIParserImpl,
|
||||
nsIINIParser)
|
||||
|
||||
static bool
|
||||
SectionCB(const char* aSection, void* aClosure)
|
||||
{
|
||||
nsTArray<nsCString>* strings = static_cast<nsTArray<nsCString>*>(aClosure);
|
||||
strings->AppendElement()->Assign(aSection);
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsINIParserImpl::GetSections(nsIUTF8StringEnumerator** aResult)
|
||||
{
|
||||
nsTArray<nsCString>* strings = new nsTArray<nsCString>;
|
||||
if (!strings) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult rv = mParser.GetSections(SectionCB, strings);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = NS_NewAdoptingUTF8StringEnumerator(aResult, strings);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
delete strings;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool
|
||||
KeyCB(const char* aKey, const char* aValue, void* aClosure)
|
||||
{
|
||||
nsTArray<nsCString>* strings = static_cast<nsTArray<nsCString>*>(aClosure);
|
||||
strings->AppendElement()->Assign(aKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsINIParserImpl::GetKeys(const nsACString& aSection,
|
||||
nsIUTF8StringEnumerator** aResult)
|
||||
{
|
||||
nsTArray<nsCString>* strings = new nsTArray<nsCString>;
|
||||
if (!strings) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult rv = mParser.GetStrings(PromiseFlatCString(aSection).get(),
|
||||
KeyCB, strings);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = NS_NewAdoptingUTF8StringEnumerator(aResult, strings);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
delete strings;
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsINIParserImpl::GetString(const nsACString& aSection,
|
||||
const nsACString& aKey,
|
||||
nsACString& aResult)
|
||||
{
|
||||
return mParser.GetString(PromiseFlatCString(aSection).get(),
|
||||
PromiseFlatCString(aKey).get(),
|
||||
aResult);
|
||||
}
|
||||
33
xpcom/ds/nsINIParserImpl.h
Normal file
33
xpcom/ds/nsINIParserImpl.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsINIParserImpl_h__
|
||||
#define nsINIParserImpl_h__
|
||||
|
||||
#include "nsIINIParser.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#define NS_INIPARSERFACTORY_CID \
|
||||
{ 0xdfac10a9, 0xdd24, 0x43cf, \
|
||||
{ 0xa0, 0x95, 0x6f, 0xfa, 0x2e, 0x4b, 0x6a, 0x6c } }
|
||||
|
||||
#define NS_INIPARSERFACTORY_CONTRACTID \
|
||||
"@mozilla.org/xpcom/ini-parser-factory;1"
|
||||
|
||||
class nsINIParserFactory final
|
||||
: public nsIINIParserFactory
|
||||
, public nsIFactory
|
||||
{
|
||||
~nsINIParserFactory() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINIPARSERFACTORY
|
||||
NS_DECL_NSIFACTORY
|
||||
};
|
||||
|
||||
#endif // nsINIParserImpl_h__
|
||||
192
xpcom/ds/nsINIProcessor.js
Normal file
192
xpcom/ds/nsINIProcessor.js
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/* 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/. */
|
||||
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function INIProcessorFactory() {
|
||||
}
|
||||
|
||||
INIProcessorFactory.prototype = {
|
||||
classID: Components.ID("{6ec5f479-8e13-4403-b6ca-fe4c2dca14fd}"),
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIINIParserFactory]),
|
||||
|
||||
createINIParser : function (aINIFile) {
|
||||
return new INIProcessor(aINIFile);
|
||||
}
|
||||
|
||||
}; // end of INIProcessorFactory implementation
|
||||
|
||||
const MODE_WRONLY = 0x02;
|
||||
const MODE_CREATE = 0x08;
|
||||
const MODE_TRUNCATE = 0x20;
|
||||
|
||||
// nsIINIParser implementation
|
||||
function INIProcessor(aFile) {
|
||||
this._iniFile = aFile;
|
||||
this._iniData = {};
|
||||
this._readFile();
|
||||
}
|
||||
|
||||
INIProcessor.prototype = {
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIINIParser, Ci.nsIINIParserWriter]),
|
||||
|
||||
__utf8Converter : null, // UCS2 <--> UTF8 string conversion
|
||||
get _utf8Converter() {
|
||||
if (!this.__utf8Converter) {
|
||||
this.__utf8Converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
this.__utf8Converter.charset = "UTF-8";
|
||||
}
|
||||
return this.__utf8Converter;
|
||||
},
|
||||
|
||||
__utf16leConverter : null, // UCS2 <--> UTF16LE string conversion
|
||||
get _utf16leConverter() {
|
||||
if (!this.__utf16leConverter) {
|
||||
this.__utf16leConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
this.__utf16leConverter.charset = "UTF-16LE";
|
||||
}
|
||||
return this.__utf16leConverter;
|
||||
},
|
||||
|
||||
_utfConverterReset : function() {
|
||||
this.__utf8Converter = null;
|
||||
this.__utf16leConverter = null;
|
||||
},
|
||||
|
||||
_iniFile : null,
|
||||
_iniData : null,
|
||||
|
||||
/*
|
||||
* Reads the INI file and stores the data internally.
|
||||
*/
|
||||
_readFile : function() {
|
||||
// If file doesn't exist, there's nothing to do.
|
||||
if (!this._iniFile.exists() || 0 == this._iniFile.fileSize)
|
||||
return;
|
||||
|
||||
let iniParser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]
|
||||
.getService(Ci.nsIINIParserFactory).createINIParser(this._iniFile);
|
||||
for (let section of XPCOMUtils.IterStringEnumerator(iniParser.getSections())) {
|
||||
this._iniData[section] = {};
|
||||
for (let key of XPCOMUtils.IterStringEnumerator(iniParser.getKeys(section))) {
|
||||
this._iniData[section][key] = iniParser.getString(section, key);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// nsIINIParser
|
||||
|
||||
getSections : function() {
|
||||
let sections = [];
|
||||
for (let section in this._iniData)
|
||||
sections.push(section);
|
||||
return new stringEnumerator(sections);
|
||||
},
|
||||
|
||||
getKeys : function(aSection) {
|
||||
let keys = [];
|
||||
if (aSection in this._iniData)
|
||||
for (let key in this._iniData[aSection])
|
||||
keys.push(key);
|
||||
return new stringEnumerator(keys);
|
||||
},
|
||||
|
||||
getString : function(aSection, aKey) {
|
||||
if (!(aSection in this._iniData))
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
if (!(aKey in this._iniData[aSection]))
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
return this._iniData[aSection][aKey];
|
||||
},
|
||||
|
||||
|
||||
// nsIINIParserWriter
|
||||
|
||||
setString : function(aSection, aKey, aValue) {
|
||||
const isSectionIllegal = /[\0\r\n\[\]]/;
|
||||
const isKeyValIllegal = /[\0\r\n=]/;
|
||||
|
||||
if (isSectionIllegal.test(aSection))
|
||||
throw Components.Exception("bad character in section name",
|
||||
Cr.ERROR_ILLEGAL_VALUE);
|
||||
if (isKeyValIllegal.test(aKey) || isKeyValIllegal.test(aValue))
|
||||
throw Components.Exception("bad character in key/value",
|
||||
Cr.ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (!(aSection in this._iniData))
|
||||
this._iniData[aSection] = {};
|
||||
|
||||
this._iniData[aSection][aKey] = aValue;
|
||||
},
|
||||
|
||||
writeFile : function(aFile, aFlags) {
|
||||
|
||||
let converter;
|
||||
function writeLine(data) {
|
||||
data += "\n";
|
||||
data = converter.ConvertFromUnicode(data);
|
||||
data += converter.Finish();
|
||||
outputStream.write(data, data.length);
|
||||
}
|
||||
|
||||
if (!aFile)
|
||||
aFile = this._iniFile;
|
||||
|
||||
let safeStream = Cc["@mozilla.org/network/safe-file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
safeStream.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE,
|
||||
0o600, null);
|
||||
|
||||
var outputStream = Cc["@mozilla.org/network/buffered-output-stream;1"].
|
||||
createInstance(Ci.nsIBufferedOutputStream);
|
||||
outputStream.init(safeStream, 8192);
|
||||
outputStream.QueryInterface(Ci.nsISafeOutputStream); // for .finish()
|
||||
|
||||
if (Ci.nsIINIParserWriter.WRITE_UTF16 == aFlags
|
||||
&& 'nsIWindowsRegKey' in Ci) {
|
||||
outputStream.write("\xFF\xFE", 2);
|
||||
converter = this._utf16leConverter;
|
||||
} else {
|
||||
converter = this._utf8Converter;
|
||||
}
|
||||
|
||||
for (let section in this._iniData) {
|
||||
writeLine("[" + section + "]");
|
||||
for (let key in this._iniData[section]) {
|
||||
writeLine(key + "=" + this._iniData[section][key]);
|
||||
}
|
||||
}
|
||||
|
||||
outputStream.finish();
|
||||
}
|
||||
};
|
||||
|
||||
function stringEnumerator(stringArray) {
|
||||
this._strings = stringArray;
|
||||
}
|
||||
stringEnumerator.prototype = {
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIUTF8StringEnumerator]),
|
||||
|
||||
_strings : null,
|
||||
_enumIndex: 0,
|
||||
|
||||
hasMore : function() {
|
||||
return (this._enumIndex < this._strings.length);
|
||||
},
|
||||
|
||||
getNext : function() {
|
||||
return this._strings[this._enumIndex++];
|
||||
}
|
||||
};
|
||||
|
||||
var component = [INIProcessorFactory];
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);
|
||||
2
xpcom/ds/nsINIProcessor.manifest
Normal file
2
xpcom/ds/nsINIProcessor.manifest
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
component {6ec5f479-8e13-4403-b6ca-fe4c2dca14fd} nsINIProcessor.js
|
||||
contract @mozilla.org/xpcom/ini-processor-factory;1 {6ec5f479-8e13-4403-b6ca-fe4c2dca14fd}
|
||||
38
xpcom/ds/nsIObserver.idl
Normal file
38
xpcom/ds/nsIObserver.idl
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* This interface is implemented by an object that wants
|
||||
* to observe an event corresponding to a topic.
|
||||
*/
|
||||
|
||||
[scriptable, function, uuid(DB242E01-E4D9-11d2-9DDE-000064657374)]
|
||||
interface nsIObserver : nsISupports {
|
||||
|
||||
/**
|
||||
* Observe will be called when there is a notification for the
|
||||
* topic |aTopic|. This assumes that the object implementing
|
||||
* this interface has been registered with an observer service
|
||||
* such as the nsIObserverService.
|
||||
*
|
||||
* If you expect multiple topics/subjects, the impl is
|
||||
* responsible for filtering.
|
||||
*
|
||||
* You should not modify, add, remove, or enumerate
|
||||
* notifications in the implemention of observe.
|
||||
*
|
||||
* @param aSubject : Notification specific interface pointer.
|
||||
* @param aTopic : The notification topic or subject.
|
||||
* @param aData : Notification specific wide string.
|
||||
* subject event.
|
||||
*/
|
||||
void observe( in nsISupports aSubject,
|
||||
in string aTopic,
|
||||
in wstring aData );
|
||||
|
||||
};
|
||||
|
||||
77
xpcom/ds/nsIObserverService.idl
Normal file
77
xpcom/ds/nsIObserverService.idl
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIObserver;
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
/**
|
||||
* nsIObserverService
|
||||
*
|
||||
* Service allows a client listener (nsIObserver) to register and unregister for
|
||||
* notifications of specific string referenced topic. Service also provides a
|
||||
* way to notify registered listeners and a way to enumerate registered client
|
||||
* listeners.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(D07F5192-E3D1-11d2-8ACD-00105A1B8860)]
|
||||
interface nsIObserverService : nsISupports
|
||||
{
|
||||
|
||||
/**
|
||||
* AddObserver
|
||||
*
|
||||
* Registers a given listener for a notifications regarding the specified
|
||||
* topic.
|
||||
*
|
||||
* @param anObserve : The interface pointer which will receive notifications.
|
||||
* @param aTopic : The notification topic or subject.
|
||||
* @param ownsWeak : If set to false, the nsIObserverService will hold a
|
||||
* strong reference to |anObserver|. If set to true and
|
||||
* |anObserver| supports the nsIWeakReference interface,
|
||||
* a weak reference will be held. Otherwise an error will be
|
||||
* returned.
|
||||
*/
|
||||
void addObserver( in nsIObserver anObserver, in string aTopic, in boolean ownsWeak);
|
||||
|
||||
/**
|
||||
* removeObserver
|
||||
*
|
||||
* Unregisters a given listener from notifications regarding the specified
|
||||
* topic.
|
||||
*
|
||||
* @param anObserver : The interface pointer which will stop recieving
|
||||
* notifications.
|
||||
* @param aTopic : The notification topic or subject.
|
||||
*/
|
||||
void removeObserver( in nsIObserver anObserver, in string aTopic );
|
||||
|
||||
/**
|
||||
* notifyObservers
|
||||
*
|
||||
* Notifies all registered listeners of the given topic.
|
||||
*
|
||||
* @param aSubject : Notification specific interface pointer.
|
||||
* @param aTopic : The notification topic or subject.
|
||||
* @param someData : Notification specific wide string.
|
||||
*/
|
||||
void notifyObservers( in nsISupports aSubject,
|
||||
in string aTopic,
|
||||
in wstring someData );
|
||||
|
||||
/**
|
||||
* enumerateObservers
|
||||
*
|
||||
* Returns an enumeration of all registered listeners.
|
||||
*
|
||||
* @param aTopic : The notification topic or subject.
|
||||
*/
|
||||
nsISimpleEnumerator enumerateObservers( in string aTopic );
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
14
xpcom/ds/nsIPersistentProperties.h
Normal file
14
xpcom/ds/nsIPersistentProperties.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
|
||||
#ifndef __gen_nsIPersistentProperties_h__
|
||||
#define __gen_nsIPersistentProperties_h__
|
||||
|
||||
// "soft" switch over to an IDL generated header file
|
||||
#include "nsIPersistentProperties2.h"
|
||||
|
||||
#endif /* __gen_nsIPersistentProperties_h__ */
|
||||
63
xpcom/ds/nsIPersistentProperties2.idl
Normal file
63
xpcom/ds/nsIPersistentProperties2.idl
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsIProperties.idl"
|
||||
|
||||
interface nsIInputStream;
|
||||
interface nsIOutputStream;
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
[scriptable, uuid(283EE646-1AEF-11D4-98B3-00C04fA0CE9A)]
|
||||
interface nsIPropertyElement : nsISupports {
|
||||
attribute AUTF8String key;
|
||||
attribute AString value;
|
||||
};
|
||||
|
||||
[scriptable, uuid(706867af-0400-4faa-beb1-0dae87308784)]
|
||||
interface nsIPersistentProperties : nsIProperties
|
||||
{
|
||||
/**
|
||||
* load a set of name/value pairs from the input stream
|
||||
* names and values should be in UTF8
|
||||
*/
|
||||
void load(in nsIInputStream input);
|
||||
|
||||
/**
|
||||
* output the values to the stream - results will be in UTF8
|
||||
*/
|
||||
void save(in nsIOutputStream output, in AUTF8String header);
|
||||
|
||||
/**
|
||||
* get an enumeration of nsIPropertyElement objects,
|
||||
* which are read-only (i.e. setting properties on the element will
|
||||
* not make changes back into the source nsIPersistentProperties
|
||||
*/
|
||||
nsISimpleEnumerator enumerate();
|
||||
|
||||
/**
|
||||
* shortcut to nsIProperty's get() which retrieves a string value
|
||||
* directly (and thus faster)
|
||||
*/
|
||||
AString getStringProperty(in AUTF8String key);
|
||||
|
||||
/**
|
||||
* shortcut to nsIProperty's set() which sets a string value
|
||||
* directly (and thus faster). If the given property already exists,
|
||||
* then the old value will be returned
|
||||
*/
|
||||
AString setStringProperty(in AUTF8String key, in AString value);
|
||||
};
|
||||
|
||||
|
||||
%{C++
|
||||
|
||||
#define NS_IPERSISTENTPROPERTIES_CID \
|
||||
{ 0x2245e573, 0x9464, 0x11d2, \
|
||||
{ 0x9b, 0x8b, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } }
|
||||
|
||||
#define NS_PERSISTENTPROPERTIES_CONTRACTID "@mozilla.org/persistent-properties;1"
|
||||
|
||||
%}
|
||||
|
||||
46
xpcom/ds/nsIProperties.idl
Normal file
46
xpcom/ds/nsIProperties.idl
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/*
|
||||
* Simple mapping service interface.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(78650582-4e93-4b60-8e85-26ebd3eb14ca)]
|
||||
interface nsIProperties : nsISupports
|
||||
{
|
||||
/**
|
||||
* Gets a property with a given name.
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE if a property with that name doesn't exist.
|
||||
* @throws NS_ERROR_NO_INTERFACE if the found property fails to QI to the
|
||||
* given iid.
|
||||
*/
|
||||
void get(in string prop, in nsIIDRef iid,
|
||||
[iid_is(iid),retval] out nsQIResult result);
|
||||
|
||||
/**
|
||||
* Sets a property with a given name to a given value.
|
||||
*/
|
||||
void set(in string prop, in nsISupports value);
|
||||
|
||||
/**
|
||||
* Returns true if the property with the given name exists.
|
||||
*/
|
||||
boolean has(in string prop);
|
||||
|
||||
/**
|
||||
* Undefines a property.
|
||||
* @throws NS_ERROR_FAILURE if a property with that name doesn't
|
||||
* already exist.
|
||||
*/
|
||||
void undefine(in string prop);
|
||||
|
||||
/**
|
||||
* Returns an array of the keys.
|
||||
*/
|
||||
void getKeys(out uint32_t count, [array, size_is(count), retval] out string keys);
|
||||
};
|
||||
25
xpcom/ds/nsIProperty.idl
Normal file
25
xpcom/ds/nsIProperty.idl
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
/* nsIVariant based Property support. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIVariant;
|
||||
|
||||
[scriptable, uuid(6dcf9030-a49f-11d5-910d-0010a4e73d9a)]
|
||||
interface nsIProperty : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get the name of the property.
|
||||
*/
|
||||
readonly attribute AString name;
|
||||
|
||||
/**
|
||||
* Get the value of the property.
|
||||
*/
|
||||
readonly attribute nsIVariant value;
|
||||
};
|
||||
30
xpcom/ds/nsIPropertyBag.idl
Normal file
30
xpcom/ds/nsIPropertyBag.idl
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
/* nsIVariant based Property Bag support. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIVariant;
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
[scriptable, uuid(bfcd37b0-a49f-11d5-910d-0010a4e73d9a)]
|
||||
interface nsIPropertyBag : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get a nsISimpleEnumerator whose elements are nsIProperty objects.
|
||||
*/
|
||||
readonly attribute nsISimpleEnumerator enumerator;
|
||||
|
||||
/**
|
||||
* Get a property value for the given name.
|
||||
* @throws NS_ERROR_FAILURE if a property with that name doesn't
|
||||
* exist.
|
||||
*/
|
||||
nsIVariant getProperty(in AString name);
|
||||
};
|
||||
|
||||
|
||||
42
xpcom/ds/nsIPropertyBag2.idl
Normal file
42
xpcom/ds/nsIPropertyBag2.idl
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* 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/. */
|
||||
|
||||
/* nsIVariant based Property Bag support. */
|
||||
|
||||
#include "nsIPropertyBag.idl"
|
||||
|
||||
[scriptable, uuid(625cfd1e-da1e-4417-9ee9-dbc8e0b3fd79)]
|
||||
interface nsIPropertyBag2 : nsIPropertyBag
|
||||
{
|
||||
// Accessing a property as a different type may attempt conversion to the
|
||||
// requested value
|
||||
|
||||
int32_t getPropertyAsInt32 (in AString prop);
|
||||
uint32_t getPropertyAsUint32 (in AString prop);
|
||||
int64_t getPropertyAsInt64 (in AString prop);
|
||||
uint64_t getPropertyAsUint64 (in AString prop);
|
||||
double getPropertyAsDouble (in AString prop);
|
||||
AString getPropertyAsAString (in AString prop);
|
||||
ACString getPropertyAsACString (in AString prop);
|
||||
AUTF8String getPropertyAsAUTF8String (in AString prop);
|
||||
boolean getPropertyAsBool (in AString prop);
|
||||
|
||||
/**
|
||||
* This method returns null if the value exists, but is null.
|
||||
*/
|
||||
void getPropertyAsInterface (in AString prop,
|
||||
in nsIIDRef iid,
|
||||
[iid_is(iid), retval] out nsQIResult result);
|
||||
|
||||
/**
|
||||
* This method returns null if the value does not exist,
|
||||
* or exists but is null.
|
||||
*/
|
||||
nsIVariant get (in AString prop);
|
||||
|
||||
/**
|
||||
* Check for the existence of a key.
|
||||
*/
|
||||
boolean hasKey (in AString prop);
|
||||
};
|
||||
32
xpcom/ds/nsISerializable.idl
Normal file
32
xpcom/ds/nsISerializable.idl
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIObjectInputStream;
|
||||
interface nsIObjectOutputStream;
|
||||
|
||||
[scriptable, uuid(91cca981-c26d-44a8-bebe-d9ed4891503a)]
|
||||
interface nsISerializable : nsISupports
|
||||
{
|
||||
/**
|
||||
* Initialize the object implementing nsISerializable, which must have
|
||||
* been freshly constructed via CreateInstance. All data members that
|
||||
* can't be set to default values must have been serialized by write,
|
||||
* and should be read from aInputStream in the same order by this method.
|
||||
*/
|
||||
void read(in nsIObjectInputStream aInputStream);
|
||||
|
||||
/**
|
||||
* Serialize the object implementing nsISerializable to aOutputStream, by
|
||||
* writing each data member that must be recovered later to reconstitute
|
||||
* a working replica of this object, in a canonical member and byte order,
|
||||
* to aOutputStream.
|
||||
*
|
||||
* NB: a class that implements nsISerializable *must* also implement
|
||||
* nsIClassInfo, in particular nsIClassInfo::GetClassID.
|
||||
*/
|
||||
void write(in nsIObjectOutputStream aOutputStream);
|
||||
};
|
||||
46
xpcom/ds/nsISimpleEnumerator.idl
Normal file
46
xpcom/ds/nsISimpleEnumerator.idl
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Used to enumerate over elements defined by its implementor.
|
||||
* Although hasMoreElements() can be called independently of getNext(),
|
||||
* getNext() must be pre-ceeded by a call to hasMoreElements(). There is
|
||||
* no way to "reset" an enumerator, once you obtain one.
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
[scriptable, uuid(D1899240-F9D2-11D2-BDD6-000064657374)]
|
||||
interface nsISimpleEnumerator : nsISupports {
|
||||
/**
|
||||
* Called to determine whether or not the enumerator has
|
||||
* any elements that can be returned via getNext(). This method
|
||||
* is generally used to determine whether or not to initiate or
|
||||
* continue iteration over the enumerator, though it can be
|
||||
* called without subsequent getNext() calls. Does not affect
|
||||
* internal state of enumerator.
|
||||
*
|
||||
* @see getNext()
|
||||
* @return true if there are remaining elements in the enumerator.
|
||||
* false if there are no more elements in the enumerator.
|
||||
*/
|
||||
boolean hasMoreElements();
|
||||
|
||||
/**
|
||||
* Called to retrieve the next element in the enumerator. The "next"
|
||||
* element is the first element upon the first call. Must be
|
||||
* pre-ceeded by a call to hasMoreElements() which returns PR_TRUE.
|
||||
* This method is generally called within a loop to iterate over
|
||||
* the elements in the enumerator.
|
||||
*
|
||||
* @see hasMoreElements()
|
||||
* @throws NS_ERROR_FAILURE if there are no more elements
|
||||
* to enumerate.
|
||||
* @return the next element in the enumeration.
|
||||
*/
|
||||
nsISupports getNext();
|
||||
};
|
||||
25
xpcom/ds/nsIStringEnumerator.idl
Normal file
25
xpcom/ds/nsIStringEnumerator.idl
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Used to enumerate over an ordered list of strings.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(50d3ef6c-9380-4f06-9fb2-95488f7d141c)]
|
||||
interface nsIStringEnumerator : nsISupports
|
||||
{
|
||||
boolean hasMore();
|
||||
AString getNext();
|
||||
};
|
||||
|
||||
[scriptable, uuid(9bdf1010-3695-4907-95ed-83d0410ec307)]
|
||||
interface nsIUTF8StringEnumerator : nsISupports
|
||||
{
|
||||
boolean hasMore();
|
||||
AUTF8String getNext();
|
||||
};
|
||||
|
||||
60
xpcom/ds/nsISupportsArray.idl
Normal file
60
xpcom/ds/nsISupportsArray.idl
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
|
||||
#include "nsICollection.idl"
|
||||
|
||||
/*
|
||||
* This entire interface is deprecated and should not be used.
|
||||
* See nsIArray and nsIMutableArray for the new implementations.
|
||||
*
|
||||
* http://groups.google.com/groups?q=nsisupportsarray+group:netscape.public.mozilla.xpcom&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=3D779491.3050506%40netscape.com&rnum=2
|
||||
* http://groups.google.com/groups?q=nsisupportsarray+group:netscape.public.mozilla.xpcom&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=al8412%245ab2%40ripley.netscape.com&rnum=8
|
||||
*/
|
||||
|
||||
%{C++
|
||||
|
||||
class nsIBidirectionalEnumerator;
|
||||
class nsISupportsArray;
|
||||
|
||||
#define NS_SUPPORTSARRAY_CID \
|
||||
{ /* bda17d50-0d6b-11d3-9331-00104ba0fd40 */ \
|
||||
0xbda17d50, \
|
||||
0x0d6b, \
|
||||
0x11d3, \
|
||||
{0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
|
||||
}
|
||||
#define NS_SUPPORTSARRAY_CONTRACTID "@mozilla.org/supports-array;1"
|
||||
|
||||
%}
|
||||
|
||||
[deprecated, scriptable, uuid(241addc8-3608-4e73-8083-2fd6fa09eba2)]
|
||||
interface nsISupportsArray : nsICollection {
|
||||
|
||||
[notxpcom] long IndexOf([const] in nsISupports aPossibleElement);
|
||||
|
||||
// xpcom-compatible versions
|
||||
long GetIndexOf(in nsISupports aPossibleElement);
|
||||
|
||||
[notxpcom] boolean InsertElementAt(in nsISupports aElement,
|
||||
in unsigned long aIndex);
|
||||
[notxpcom] boolean ReplaceElementAt(in nsISupports aElement,
|
||||
in unsigned long aIndex);
|
||||
|
||||
[notxpcom] boolean RemoveElementAt(in unsigned long aIndex);
|
||||
|
||||
// xpcom-compatible versions
|
||||
void DeleteElementAt(in unsigned long aIndex);
|
||||
|
||||
nsISupportsArray clone();
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
||||
// Construct and return a default implementation of nsISupportsArray:
|
||||
extern MOZ_MUST_USE nsresult
|
||||
NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult);
|
||||
|
||||
%}
|
||||
292
xpcom/ds/nsISupportsIterators.idl
Normal file
292
xpcom/ds/nsISupportsIterators.idl
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
/* nsISupportsIterators.idl --- IDL defining general purpose iterators */
|
||||
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
|
||||
/*
|
||||
...
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
[scriptable, uuid(7330650e-1dd2-11b2-a0c2-9ff86ee97bed)]
|
||||
interface nsIOutputIterator : nsISupports
|
||||
{
|
||||
/**
|
||||
* Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator.
|
||||
* The iterator and the underlying container or sequence cooperate to |Release()|
|
||||
* the replaced element, if any and if necessary, and to |AddRef()| the new element.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @param anElementToPut the element to place into the underlying container or sequence
|
||||
*/
|
||||
void putElement( in nsISupports anElementToPut );
|
||||
|
||||
/**
|
||||
* Advance this iterator to the next position in the underlying container or sequence.
|
||||
*/
|
||||
void stepForward();
|
||||
};
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
[scriptable, uuid(85585e12-1dd2-11b2-a930-f6929058269a)]
|
||||
interface nsIInputIterator : nsISupports
|
||||
{
|
||||
/**
|
||||
* Retrieve (and |AddRef()|) the element this iterator currently points to.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @result a new reference to the element this iterator currently points to (if any)
|
||||
*/
|
||||
nsISupports getElement();
|
||||
|
||||
/**
|
||||
* Advance this iterator to the next position in the underlying container or sequence.
|
||||
*/
|
||||
void stepForward();
|
||||
|
||||
/**
|
||||
* Test if |anotherIterator| points to the same position in the underlying container or sequence.
|
||||
*
|
||||
* The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence.
|
||||
*
|
||||
* @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence
|
||||
* @result true if |anotherIterator| points to the same position in the underlying container or sequence
|
||||
*/
|
||||
boolean isEqualTo( in nsISupports anotherIterator );
|
||||
|
||||
/**
|
||||
* Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points.
|
||||
* The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator.
|
||||
*
|
||||
* @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator
|
||||
*/
|
||||
nsISupports clone();
|
||||
};
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
[scriptable, uuid(8da01646-1dd2-11b2-98a7-c7009045be7e)]
|
||||
interface nsIForwardIterator : nsISupports
|
||||
{
|
||||
/**
|
||||
* Retrieve (and |AddRef()|) the element this iterator currently points to.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @result a new reference to the element this iterator currently points to (if any)
|
||||
*/
|
||||
nsISupports getElement();
|
||||
|
||||
/**
|
||||
* Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator.
|
||||
* The iterator and the underlying container or sequence cooperate to |Release()|
|
||||
* the replaced element, if any and if necessary, and to |AddRef()| the new element.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @param anElementToPut the element to place into the underlying container or sequence
|
||||
*/
|
||||
void putElement( in nsISupports anElementToPut );
|
||||
|
||||
/**
|
||||
* Advance this iterator to the next position in the underlying container or sequence.
|
||||
*/
|
||||
void stepForward();
|
||||
|
||||
/**
|
||||
* Test if |anotherIterator| points to the same position in the underlying container or sequence.
|
||||
*
|
||||
* The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence.
|
||||
*
|
||||
* @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence
|
||||
* @result true if |anotherIterator| points to the same position in the underlying container or sequence
|
||||
*/
|
||||
boolean isEqualTo( in nsISupports anotherIterator );
|
||||
|
||||
/**
|
||||
* Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points.
|
||||
* The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator.
|
||||
*
|
||||
* @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator
|
||||
*/
|
||||
nsISupports clone();
|
||||
};
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
[scriptable, uuid(948defaa-1dd1-11b2-89f6-8ce81f5ebda9)]
|
||||
interface nsIBidirectionalIterator : nsISupports
|
||||
{
|
||||
/**
|
||||
* Retrieve (and |AddRef()|) the element this iterator currently points to.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @result a new reference to the element this iterator currently points to (if any)
|
||||
*/
|
||||
nsISupports getElement();
|
||||
|
||||
/**
|
||||
* Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator.
|
||||
* The iterator and the underlying container or sequence cooperate to |Release()|
|
||||
* the replaced element, if any and if necessary, and to |AddRef()| the new element.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @param anElementToPut the element to place into the underlying container or sequence
|
||||
*/
|
||||
void putElement( in nsISupports anElementToPut );
|
||||
|
||||
/**
|
||||
* Advance this iterator to the next position in the underlying container or sequence.
|
||||
*/
|
||||
void stepForward();
|
||||
|
||||
/**
|
||||
* Move this iterator to the previous position in the underlying container or sequence.
|
||||
*/
|
||||
void stepBackward();
|
||||
|
||||
/**
|
||||
* Test if |anotherIterator| points to the same position in the underlying container or sequence.
|
||||
*
|
||||
* The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence.
|
||||
*
|
||||
* @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence
|
||||
* @result true if |anotherIterator| points to the same position in the underlying container or sequence
|
||||
*/
|
||||
boolean isEqualTo( in nsISupports anotherIterator );
|
||||
|
||||
/**
|
||||
* Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points.
|
||||
* The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator.
|
||||
*
|
||||
* @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator
|
||||
*/
|
||||
nsISupports clone();
|
||||
};
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
[scriptable, uuid(9bd6fdb0-1dd1-11b2-9101-d15375968230)]
|
||||
interface nsIRandomAccessIterator : nsISupports
|
||||
{
|
||||
/**
|
||||
* Retrieve (and |AddRef()|) the element this iterator currently points to.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @result a new reference to the element this iterator currently points to (if any)
|
||||
*/
|
||||
nsISupports getElement();
|
||||
|
||||
/**
|
||||
* Retrieve (and |AddRef()|) an element at some offset from where this iterator currently points.
|
||||
* The offset may be negative. |getElementAt(0)| is equivalent to |getElement()|.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @param anOffset a |0|-based offset from the position to which this iterator currently points
|
||||
* @result a new reference to the indicated element (if any)
|
||||
*/
|
||||
nsISupports getElementAt( in int32_t anOffset );
|
||||
|
||||
/**
|
||||
* Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator.
|
||||
* The iterator and the underlying container or sequence cooperate to |Release()|
|
||||
* the replaced element, if any and if necessary, and to |AddRef()| the new element.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @param anElementToPut the element to place into the underlying container or sequence
|
||||
*/
|
||||
void putElement( in nsISupports anElementToPut );
|
||||
|
||||
/**
|
||||
* Put |anElementToPut| into the underlying container or sequence at the position |anOffset| away from that currently pointed to by this iterator.
|
||||
* The iterator and the underlying container or sequence cooperate to |Release()|
|
||||
* the replaced element, if any and if necessary, and to |AddRef()| the new element.
|
||||
* |putElementAt(0, obj)| is equivalent to |putElement(obj)|.
|
||||
*
|
||||
* The result is undefined if this iterator currently points outside the
|
||||
* useful range of the underlying container or sequence.
|
||||
*
|
||||
* @param anOffset a |0|-based offset from the position to which this iterator currently points
|
||||
* @param anElementToPut the element to place into the underlying container or sequence
|
||||
*/
|
||||
void putElementAt( in int32_t anOffset, in nsISupports anElementToPut );
|
||||
|
||||
/**
|
||||
* Advance this iterator to the next position in the underlying container or sequence.
|
||||
*/
|
||||
void stepForward();
|
||||
|
||||
/**
|
||||
* Move this iterator by |anOffset| positions in the underlying container or sequence.
|
||||
* |anOffset| may be negative. |stepForwardBy(1)| is equivalent to |stepForward()|.
|
||||
* |stepForwardBy(0)| is a no-op.
|
||||
*
|
||||
* @param anOffset a |0|-based offset from the position to which this iterator currently points
|
||||
*/
|
||||
void stepForwardBy( in int32_t anOffset );
|
||||
|
||||
/**
|
||||
* Move this iterator to the previous position in the underlying container or sequence.
|
||||
*/
|
||||
void stepBackward();
|
||||
|
||||
/**
|
||||
* Move this iterator backwards by |anOffset| positions in the underlying container or sequence.
|
||||
* |anOffset| may be negative. |stepBackwardBy(1)| is equivalent to |stepBackward()|.
|
||||
* |stepBackwardBy(n)| is equivalent to |stepForwardBy(-n)|. |stepBackwardBy(0)| is a no-op.
|
||||
*
|
||||
* @param anOffset a |0|-based offset from the position to which this iterator currently points
|
||||
*/
|
||||
void stepBackwardBy( in int32_t anOffset );
|
||||
|
||||
/**
|
||||
* Test if |anotherIterator| points to the same position in the underlying container or sequence.
|
||||
*
|
||||
* The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence.
|
||||
*
|
||||
* @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence
|
||||
* @result true if |anotherIterator| points to the same position in the underlying container or sequence
|
||||
*/
|
||||
boolean isEqualTo( in nsISupports anotherIterator );
|
||||
|
||||
/**
|
||||
* Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points.
|
||||
* The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator.
|
||||
*
|
||||
* @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator
|
||||
*/
|
||||
nsISupports clone();
|
||||
};
|
||||
|
||||
%{C++
|
||||
%}
|
||||
235
xpcom/ds/nsISupportsPrimitives.idl
Normal file
235
xpcom/ds/nsISupportsPrimitives.idl
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
/* nsISupports wrappers for single primitive pieces of data. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Primitive base interface.
|
||||
*
|
||||
* These first three are pointer types and do data copying
|
||||
* using the nsIMemory. Be careful!
|
||||
*/
|
||||
|
||||
[scriptable, uuid(d0d4b136-1dd1-11b2-9371-f0727ef827c0)]
|
||||
interface nsISupportsPrimitive : nsISupports
|
||||
{
|
||||
const unsigned short TYPE_ID = 1;
|
||||
const unsigned short TYPE_CSTRING = 2;
|
||||
const unsigned short TYPE_STRING = 3;
|
||||
const unsigned short TYPE_PRBOOL = 4;
|
||||
const unsigned short TYPE_PRUINT8 = 5;
|
||||
const unsigned short TYPE_PRUINT16 = 6;
|
||||
const unsigned short TYPE_PRUINT32 = 7;
|
||||
const unsigned short TYPE_PRUINT64 = 8;
|
||||
const unsigned short TYPE_PRTIME = 9;
|
||||
const unsigned short TYPE_CHAR = 10;
|
||||
const unsigned short TYPE_PRINT16 = 11;
|
||||
const unsigned short TYPE_PRINT32 = 12;
|
||||
const unsigned short TYPE_PRINT64 = 13;
|
||||
const unsigned short TYPE_FLOAT = 14;
|
||||
const unsigned short TYPE_DOUBLE = 15;
|
||||
const unsigned short TYPE_VOID = 16;
|
||||
const unsigned short TYPE_INTERFACE_POINTER = 17;
|
||||
|
||||
readonly attribute unsigned short type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for nsID structures
|
||||
*/
|
||||
|
||||
[scriptable, uuid(d18290a0-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsID : nsISupportsPrimitive
|
||||
{
|
||||
attribute nsIDPtr data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for ASCII strings
|
||||
*/
|
||||
|
||||
[scriptable, uuid(d65ff270-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsCString : nsISupportsPrimitive
|
||||
{
|
||||
attribute ACString data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for Unicode strings
|
||||
*/
|
||||
|
||||
[scriptable, uuid(d79dc970-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsString : nsISupportsPrimitive
|
||||
{
|
||||
attribute AString data;
|
||||
wstring toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* The rest are truly primitive and are passed by value
|
||||
*/
|
||||
|
||||
/**
|
||||
* Scriptable storage for booleans
|
||||
*/
|
||||
|
||||
[scriptable, uuid(ddc3b490-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRBool : nsISupportsPrimitive
|
||||
{
|
||||
attribute boolean data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for 8-bit integers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(dec2e4e0-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRUint8 : nsISupportsPrimitive
|
||||
{
|
||||
attribute uint8_t data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for unsigned 16-bit integers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(dfacb090-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRUint16 : nsISupportsPrimitive
|
||||
{
|
||||
attribute uint16_t data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for unsigned 32-bit integers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e01dc470-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRUint32 : nsISupportsPrimitive
|
||||
{
|
||||
attribute uint32_t data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for 64-bit integers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e13567c0-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRUint64 : nsISupportsPrimitive
|
||||
{
|
||||
attribute uint64_t data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for NSPR date/time values
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e2563630-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRTime : nsISupportsPrimitive
|
||||
{
|
||||
attribute PRTime data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for single character values
|
||||
* (often used to store an ASCII character)
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e2b05e40-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsChar : nsISupportsPrimitive
|
||||
{
|
||||
attribute char data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for 16-bit integers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e30d94b0-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRInt16 : nsISupportsPrimitive
|
||||
{
|
||||
attribute int16_t data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for 32-bit integers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e36c5250-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRInt32 : nsISupportsPrimitive
|
||||
{
|
||||
attribute int32_t data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for 64-bit integers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(e3cb0ff0-4a1c-11d3-9890-006008962422)]
|
||||
interface nsISupportsPRInt64 : nsISupportsPrimitive
|
||||
{
|
||||
attribute int64_t data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for floating point numbers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(abeaa390-4ac0-11d3-baea-00805f8a5dd7)]
|
||||
interface nsISupportsFloat : nsISupportsPrimitive
|
||||
{
|
||||
attribute float data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for doubles
|
||||
*/
|
||||
|
||||
[scriptable, uuid(b32523a0-4ac0-11d3-baea-00805f8a5dd7)]
|
||||
interface nsISupportsDouble : nsISupportsPrimitive
|
||||
{
|
||||
attribute double data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for generic pointers
|
||||
*/
|
||||
|
||||
[scriptable, uuid(464484f0-568d-11d3-baf8-00805f8a5dd7)]
|
||||
interface nsISupportsVoid : nsISupportsPrimitive
|
||||
{
|
||||
[noscript] attribute voidPtr data;
|
||||
string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Scriptable storage for other XPCOM objects
|
||||
*/
|
||||
|
||||
[scriptable, uuid(995ea724-1dd1-11b2-9211-c21bdd3e7ed0)]
|
||||
interface nsISupportsInterfacePointer : nsISupportsPrimitive
|
||||
{
|
||||
attribute nsISupports data;
|
||||
attribute nsIDPtr dataIID;
|
||||
|
||||
string toString();
|
||||
};
|
||||
|
||||
|
||||
155
xpcom/ds/nsIVariant.idl
Normal file
155
xpcom/ds/nsIVariant.idl
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
/* The long avoided variant support for xpcom. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable,uuid(4d12e540-83d7-11d5-90ed-0010a4e73d9a)]
|
||||
interface nsIDataType : nsISupports
|
||||
{
|
||||
// These MUST match the declarations in xpt_struct.h.
|
||||
// Otherwise the world is likely to explode.
|
||||
// From xpt_struct.h ...
|
||||
const uint16_t VTYPE_INT8 = 0; // TD_INT8 = 0,
|
||||
const uint16_t VTYPE_INT16 = 1; // TD_INT16 = 1,
|
||||
const uint16_t VTYPE_INT32 = 2; // TD_INT32 = 2,
|
||||
const uint16_t VTYPE_INT64 = 3; // TD_INT64 = 3,
|
||||
const uint16_t VTYPE_UINT8 = 4; // TD_UINT8 = 4,
|
||||
const uint16_t VTYPE_UINT16 = 5; // TD_UINT16 = 5,
|
||||
const uint16_t VTYPE_UINT32 = 6; // TD_UINT32 = 6,
|
||||
const uint16_t VTYPE_UINT64 = 7; // TD_UINT64 = 7,
|
||||
const uint16_t VTYPE_FLOAT = 8; // TD_FLOAT = 8,
|
||||
const uint16_t VTYPE_DOUBLE = 9; // TD_DOUBLE = 9,
|
||||
const uint16_t VTYPE_BOOL = 10; // TD_BOOL = 10,
|
||||
const uint16_t VTYPE_CHAR = 11; // TD_CHAR = 11,
|
||||
const uint16_t VTYPE_WCHAR = 12; // TD_WCHAR = 12,
|
||||
const uint16_t VTYPE_VOID = 13; // TD_VOID = 13,
|
||||
const uint16_t VTYPE_ID = 14; // TD_PNSIID = 14,
|
||||
const uint16_t VTYPE_DOMSTRING = 15; // TD_DOMSTRING = 15,
|
||||
const uint16_t VTYPE_CHAR_STR = 16; // TD_PSTRING = 16,
|
||||
const uint16_t VTYPE_WCHAR_STR = 17; // TD_PWSTRING = 17,
|
||||
const uint16_t VTYPE_INTERFACE = 18; // TD_INTERFACE_TYPE = 18,
|
||||
const uint16_t VTYPE_INTERFACE_IS = 19; // TD_INTERFACE_IS_TYPE = 19,
|
||||
const uint16_t VTYPE_ARRAY = 20; // TD_ARRAY = 20,
|
||||
const uint16_t VTYPE_STRING_SIZE_IS = 21; // TD_PSTRING_SIZE_IS = 21,
|
||||
const uint16_t VTYPE_WSTRING_SIZE_IS = 22; // TD_PWSTRING_SIZE_IS = 22,
|
||||
const uint16_t VTYPE_UTF8STRING = 23; // TD_UTF8STRING = 23,
|
||||
const uint16_t VTYPE_CSTRING = 24; // TD_CSTRING = 24,
|
||||
const uint16_t VTYPE_ASTRING = 25; // TD_ASTRING = 25,
|
||||
const uint16_t VTYPE_EMPTY_ARRAY = 254;
|
||||
const uint16_t VTYPE_EMPTY = 255;
|
||||
};
|
||||
|
||||
/**
|
||||
* XPConnect has magic to transparently convert between nsIVariant and JS types.
|
||||
* We mark the interface [scriptable] so that JS can use methods
|
||||
* that refer to this interface. But we mark all the methods and attributes
|
||||
* [noscript] since any nsIVariant object will be automatically converted to a
|
||||
* JS type anyway.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(81e4c2de-acac-4ad6-901a-b5fb1b851a0d)]
|
||||
interface nsIVariant : nsISupports
|
||||
{
|
||||
[noscript] readonly attribute uint16_t dataType;
|
||||
|
||||
[noscript] uint8_t getAsInt8();
|
||||
[noscript] int16_t getAsInt16();
|
||||
[noscript] int32_t getAsInt32();
|
||||
[noscript] int64_t getAsInt64();
|
||||
[noscript] uint8_t getAsUint8();
|
||||
[noscript] uint16_t getAsUint16();
|
||||
[noscript] uint32_t getAsUint32();
|
||||
[noscript] uint64_t getAsUint64();
|
||||
[noscript] float getAsFloat();
|
||||
[noscript] double getAsDouble();
|
||||
[noscript] boolean getAsBool();
|
||||
[noscript] char getAsChar();
|
||||
[noscript] wchar getAsWChar();
|
||||
[notxpcom] nsresult getAsID(out nsID retval);
|
||||
[noscript] AString getAsAString();
|
||||
[noscript] DOMString getAsDOMString();
|
||||
[noscript] ACString getAsACString();
|
||||
[noscript] AUTF8String getAsAUTF8String();
|
||||
[noscript] string getAsString();
|
||||
[noscript] wstring getAsWString();
|
||||
[noscript] nsISupports getAsISupports();
|
||||
[noscript] jsval getAsJSVal();
|
||||
|
||||
[noscript] void getAsInterface(out nsIIDPtr iid,
|
||||
[iid_is(iid), retval] out nsQIResult iface);
|
||||
|
||||
[notxpcom] nsresult getAsArray(out uint16_t type, out nsIID iid,
|
||||
out uint32_t count, out voidPtr ptr);
|
||||
|
||||
[noscript] void getAsStringWithSize(out uint32_t size,
|
||||
[size_is(size), retval] out string str);
|
||||
|
||||
[noscript] void getAsWStringWithSize(out uint32_t size,
|
||||
[size_is(size), retval] out wstring str);
|
||||
};
|
||||
|
||||
/**
|
||||
* An object that implements nsIVariant may or may NOT also implement this
|
||||
* nsIWritableVariant.
|
||||
*
|
||||
* If the 'writable' attribute is false then attempts to call any of the 'set'
|
||||
* methods can be expected to fail. Setting the 'writable' attribute may or
|
||||
* may not succeed.
|
||||
*
|
||||
*/
|
||||
|
||||
[scriptable, uuid(5586a590-8c82-11d5-90f3-0010a4e73d9a)]
|
||||
interface nsIWritableVariant : nsIVariant
|
||||
{
|
||||
attribute boolean writable;
|
||||
|
||||
void setAsInt8(in uint8_t aValue);
|
||||
void setAsInt16(in int16_t aValue);
|
||||
void setAsInt32(in int32_t aValue);
|
||||
void setAsInt64(in int64_t aValue);
|
||||
void setAsUint8(in uint8_t aValue);
|
||||
void setAsUint16(in uint16_t aValue);
|
||||
void setAsUint32(in uint32_t aValue);
|
||||
void setAsUint64(in uint64_t aValue);
|
||||
void setAsFloat(in float aValue);
|
||||
void setAsDouble(in double aValue);
|
||||
void setAsBool(in boolean aValue);
|
||||
void setAsChar(in char aValue);
|
||||
void setAsWChar(in wchar aValue);
|
||||
void setAsID(in nsIDRef aValue);
|
||||
void setAsAString(in AString aValue);
|
||||
void setAsDOMString(in DOMString aValue);
|
||||
void setAsACString(in ACString aValue);
|
||||
void setAsAUTF8String(in AUTF8String aValue);
|
||||
void setAsString(in string aValue);
|
||||
void setAsWString(in wstring aValue);
|
||||
void setAsISupports(in nsISupports aValue);
|
||||
|
||||
void setAsInterface(in nsIIDRef iid,
|
||||
[iid_is(iid)] in nsQIResult iface);
|
||||
|
||||
[noscript] void setAsArray(in uint16_t type, in nsIIDPtr iid,
|
||||
in uint32_t count, in voidPtr ptr);
|
||||
|
||||
void setAsStringWithSize(in uint32_t size,
|
||||
[size_is(size)] in string str);
|
||||
|
||||
void setAsWStringWithSize(in uint32_t size,
|
||||
[size_is(size)] in wstring str);
|
||||
|
||||
void setAsVoid();
|
||||
void setAsEmpty();
|
||||
void setAsEmptyArray();
|
||||
|
||||
void setFromVariant(in nsIVariant aValue);
|
||||
};
|
||||
|
||||
%{C++
|
||||
// The contractID for the generic implementation built in to xpcom.
|
||||
#define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1"
|
||||
%}
|
||||
332
xpcom/ds/nsIWindowsRegKey.idl
Normal file
332
xpcom/ds/nsIWindowsRegKey.idl
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
native HKEY(HKEY);
|
||||
|
||||
/**
|
||||
* This interface is designed to provide scriptable access to the Windows
|
||||
* registry system ("With Great Power Comes Great Responsibility"). The
|
||||
* interface represents a single key in the registry.
|
||||
*
|
||||
* This interface is highly Win32 specific.
|
||||
*/
|
||||
[scriptable, uuid(2555b930-d64f-437e-9be7-0a2cb252c1f4)]
|
||||
interface nsIWindowsRegKey : nsISupports
|
||||
{
|
||||
/**
|
||||
* Root keys. The values for these keys correspond to the values from
|
||||
* WinReg.h in the MS Platform SDK. The ROOT_KEY_ prefix corresponds to the
|
||||
* HKEY_ prefix in the MS Platform SDK.
|
||||
*
|
||||
* This interface is not restricted to using only these root keys.
|
||||
*/
|
||||
const unsigned long ROOT_KEY_CLASSES_ROOT = 0x80000000;
|
||||
const unsigned long ROOT_KEY_CURRENT_USER = 0x80000001;
|
||||
const unsigned long ROOT_KEY_LOCAL_MACHINE = 0x80000002;
|
||||
|
||||
/**
|
||||
* Values for the mode parameter passed to the open and create methods.
|
||||
* The values defined here correspond to the REGSAM values defined in
|
||||
* WinNT.h in the MS Platform SDK, where ACCESS_ is replaced with KEY_.
|
||||
*
|
||||
* This interface is not restricted to using only these access types.
|
||||
*/
|
||||
const unsigned long ACCESS_BASIC = 0x00020000;
|
||||
const unsigned long ACCESS_QUERY_VALUE = 0x00000001;
|
||||
const unsigned long ACCESS_SET_VALUE = 0x00000002;
|
||||
const unsigned long ACCESS_CREATE_SUB_KEY = 0x00000004;
|
||||
const unsigned long ACCESS_ENUMERATE_SUB_KEYS = 0x00000008;
|
||||
const unsigned long ACCESS_NOTIFY = 0x00000010;
|
||||
const unsigned long ACCESS_READ = ACCESS_BASIC |
|
||||
ACCESS_QUERY_VALUE |
|
||||
ACCESS_ENUMERATE_SUB_KEYS |
|
||||
ACCESS_NOTIFY;
|
||||
const unsigned long ACCESS_WRITE = ACCESS_BASIC |
|
||||
ACCESS_SET_VALUE |
|
||||
ACCESS_CREATE_SUB_KEY;
|
||||
const unsigned long ACCESS_ALL = ACCESS_READ |
|
||||
ACCESS_WRITE;
|
||||
const unsigned long WOW64_32 = 0x00000200;
|
||||
const unsigned long WOW64_64 = 0x00000100;
|
||||
|
||||
|
||||
/**
|
||||
* Values for the type of a registry value. The numeric values of these
|
||||
* constants are taken directly from WinNT.h in the MS Platform SDK.
|
||||
* The Microsoft documentation should be consulted for the exact meaning of
|
||||
* these value types.
|
||||
*
|
||||
* This interface is somewhat restricted to using only these value types.
|
||||
* There is no method that is directly equivalent to RegQueryValueEx or
|
||||
* RegSetValueEx. In particular, this interface does not support the
|
||||
* REG_MULTI_SZ and REG_EXPAND_SZ value types. It is still possible to
|
||||
* enumerate values that have other types (i.e., getValueType may return a
|
||||
* type not defined below).
|
||||
*/
|
||||
const unsigned long TYPE_NONE = 0; // REG_NONE
|
||||
const unsigned long TYPE_STRING = 1; // REG_SZ
|
||||
const unsigned long TYPE_BINARY = 3; // REG_BINARY
|
||||
const unsigned long TYPE_INT = 4; // REG_DWORD
|
||||
const unsigned long TYPE_INT64 = 11; // REG_QWORD
|
||||
|
||||
/**
|
||||
* This attribute exposes the native HKEY and is available to provide C++
|
||||
* consumers with the flexibility of making other Windows registry API calls
|
||||
* that are not exposed via this interface.
|
||||
*
|
||||
* It is possible to initialize this object by setting an HKEY on it. In
|
||||
* that case, it is the responsibility of the consumer setting the HKEY to
|
||||
* ensure that it is a valid HKEY.
|
||||
*
|
||||
* WARNING: Setting the key does not close the old key.
|
||||
*/
|
||||
[noscript] attribute HKEY key;
|
||||
|
||||
/**
|
||||
* This method closes the key. If the key is already closed, then this
|
||||
* method does nothing.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* This method opens an existing key. This method fails if the key
|
||||
* does not exist.
|
||||
*
|
||||
* NOTE: On 32-bit Windows, it is valid to pass any HKEY as the rootKey
|
||||
* parameter of this function. However, for compatibility with 64-bit
|
||||
* Windows, that usage should probably be avoided in favor of openChild.
|
||||
*
|
||||
* @param rootKey
|
||||
* A root key defined above or any valid HKEY on 32-bit Windows.
|
||||
* @param relPath
|
||||
* A relative path from the given root key.
|
||||
* @param mode
|
||||
* Access mode, which is a bit-wise OR of the ACCESS_ values defined
|
||||
* above.
|
||||
*/
|
||||
void open(in unsigned long rootKey, in AString relPath, in unsigned long mode);
|
||||
|
||||
/**
|
||||
* This method opens an existing key or creates a new key.
|
||||
*
|
||||
* NOTE: On 32-bit Windows, it is valid to pass any HKEY as the rootKey
|
||||
* parameter of this function. However, for compatibility with 64-bit
|
||||
* Windows, that usage should probably be avoided in favor of createChild.
|
||||
*
|
||||
* @param rootKey
|
||||
* A root key defined above or any valid HKEY on 32-bit Windows.
|
||||
* @param relPath
|
||||
* A relative path from the given root key.
|
||||
* @param mode
|
||||
* Access mode, which is a bit-wise OR of the ACCESS_ values defined
|
||||
* above.
|
||||
*/
|
||||
void create(in unsigned long rootKey, in AString relPath, in unsigned long mode);
|
||||
|
||||
/**
|
||||
* This method opens a subkey relative to this key. This method fails if the
|
||||
* key does not exist.
|
||||
*
|
||||
* @return nsIWindowsRegKey for the newly opened subkey.
|
||||
*/
|
||||
nsIWindowsRegKey openChild(in AString relPath, in unsigned long mode);
|
||||
|
||||
/**
|
||||
* This method opens or creates a subkey relative to this key.
|
||||
*
|
||||
* @return nsIWindowsRegKey for the newly opened or created subkey.
|
||||
*/
|
||||
nsIWindowsRegKey createChild(in AString relPath, in unsigned long mode);
|
||||
|
||||
/**
|
||||
* This attribute returns the number of child keys.
|
||||
*/
|
||||
readonly attribute unsigned long childCount;
|
||||
|
||||
/**
|
||||
* This method returns the name of the n'th child key.
|
||||
*
|
||||
* @param index
|
||||
* The index of the requested child key.
|
||||
*/
|
||||
AString getChildName(in unsigned long index);
|
||||
|
||||
/**
|
||||
* This method checks to see if the key has a child by the given name.
|
||||
*
|
||||
* @param name
|
||||
* The name of the requested child key.
|
||||
*/
|
||||
boolean hasChild(in AString name);
|
||||
|
||||
/**
|
||||
* This attribute returns the number of values under this key.
|
||||
*/
|
||||
readonly attribute unsigned long valueCount;
|
||||
|
||||
/**
|
||||
* This method returns the name of the n'th value under this key.
|
||||
*
|
||||
* @param index
|
||||
* The index of the requested value.
|
||||
*/
|
||||
AString getValueName(in unsigned long index);
|
||||
|
||||
/**
|
||||
* This method checks to see if the key has a value by the given name.
|
||||
*
|
||||
* @param name
|
||||
* The name of the requested value.
|
||||
*/
|
||||
boolean hasValue(in AString name);
|
||||
|
||||
/**
|
||||
* This method removes a child key and all of its values. This method will
|
||||
* fail if the key has any children of its own.
|
||||
*
|
||||
* @param relPath
|
||||
* The relative path from this key to the key to be removed.
|
||||
*/
|
||||
void removeChild(in AString relPath);
|
||||
|
||||
/**
|
||||
* This method removes the value with the given name.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to be removed.
|
||||
*/
|
||||
void removeValue(in AString name);
|
||||
|
||||
/**
|
||||
* This method returns the type of the value with the given name. The return
|
||||
* value is one of the "TYPE_" constants defined above.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to query.
|
||||
*/
|
||||
unsigned long getValueType(in AString name);
|
||||
|
||||
/**
|
||||
* This method reads the string contents of the named value as a Unicode
|
||||
* string.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to query. This parameter can be the empty
|
||||
* string to request the key's default value.
|
||||
*/
|
||||
AString readStringValue(in AString name);
|
||||
|
||||
/**
|
||||
* This method reads the integer contents of the named value.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to query.
|
||||
*/
|
||||
unsigned long readIntValue(in AString name);
|
||||
|
||||
/**
|
||||
* This method reads the 64-bit integer contents of the named value.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to query.
|
||||
*/
|
||||
unsigned long long readInt64Value(in AString name);
|
||||
|
||||
/**
|
||||
* This method reads the binary contents of the named value under this key.
|
||||
*
|
||||
* JavaScript callers should take care with the result of this method since
|
||||
* it will be byte-expanded to form a JS string. (The binary data will be
|
||||
* treated as an ISO-Latin-1 character string, which it is not).
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to query.
|
||||
*/
|
||||
ACString readBinaryValue(in AString name);
|
||||
|
||||
/**
|
||||
* This method writes the unicode string contents of the named value. The
|
||||
* value will be created if it does not already exist.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to modify. This parameter can be the empty
|
||||
* string to modify the key's default value.
|
||||
* @param data
|
||||
* The data for the value to modify.
|
||||
*/
|
||||
void writeStringValue(in AString name, in AString data);
|
||||
|
||||
/**
|
||||
* This method writes the integer contents of the named value. The value
|
||||
* will be created if it does not already exist.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to modify.
|
||||
* @param data
|
||||
* The data for the value to modify.
|
||||
*/
|
||||
void writeIntValue(in AString name, in unsigned long data);
|
||||
|
||||
/**
|
||||
* This method writes the 64-bit integer contents of the named value. The
|
||||
* value will be created if it does not already exist.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to modify.
|
||||
* @param data
|
||||
* The data for the value to modify.
|
||||
*/
|
||||
void writeInt64Value(in AString name, in unsigned long long data);
|
||||
|
||||
/**
|
||||
* This method writes the binary contents of the named value. The value will
|
||||
* be created if it does not already exist.
|
||||
*
|
||||
* JavaScript callers should take care with the value passed to this method
|
||||
* since it will be truncated from a JS string (unicode) to a ISO-Latin-1
|
||||
* string. (The binary data will be treated as an ISO-Latin-1 character
|
||||
* string, which it is not). So, JavaScript callers should only pass
|
||||
* character values in the range \u0000 to \u00FF, or else data loss will
|
||||
* occur.
|
||||
*
|
||||
* @param name
|
||||
* The name of the value to modify.
|
||||
* @param data
|
||||
* The data for the value to modify.
|
||||
*/
|
||||
void writeBinaryValue(in AString name, in ACString data);
|
||||
|
||||
/**
|
||||
* This method starts watching the key to see if any of its values have
|
||||
* changed. The key must have been opened with mode including ACCESS_NOTIFY.
|
||||
* If recurse is true, then this key and any of its descendant keys are
|
||||
* watched. Otherwise, only this key is watched.
|
||||
*
|
||||
* @param recurse
|
||||
* Indicates whether or not to also watch child keys.
|
||||
*/
|
||||
void startWatching(in boolean recurse);
|
||||
|
||||
/**
|
||||
* This method stops any watching of the key initiated by a call to
|
||||
* startWatching. This method does nothing if the key is not being watched.
|
||||
*/
|
||||
void stopWatching();
|
||||
|
||||
/**
|
||||
* This method returns true if the key is being watched for changes (i.e.,
|
||||
* if startWatching() was called).
|
||||
*/
|
||||
boolean isWatching();
|
||||
|
||||
/**
|
||||
* This method returns true if the key has changed and false otherwise.
|
||||
* This method will always return false if startWatching was not called.
|
||||
*/
|
||||
boolean hasChanged();
|
||||
};
|
||||
27
xpcom/ds/nsIWritablePropertyBag.idl
Normal file
27
xpcom/ds/nsIWritablePropertyBag.idl
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
/* nsIVariant based writable Property Bag support. */
|
||||
|
||||
#include "nsIPropertyBag.idl"
|
||||
|
||||
[scriptable, uuid(96fc4671-eeb4-4823-9421-e50fb70ad353)]
|
||||
interface nsIWritablePropertyBag : nsIPropertyBag
|
||||
{
|
||||
/**
|
||||
* Set a property with the given name to the given value. If
|
||||
* a property already exists with the given name, it is
|
||||
* overwritten.
|
||||
*/
|
||||
void setProperty(in AString name, in nsIVariant value);
|
||||
|
||||
/**
|
||||
* Delete a property with the given name.
|
||||
* @throws NS_ERROR_FAILURE if a property with that name doesn't
|
||||
* exist.
|
||||
*/
|
||||
void deleteProperty(in AString name);
|
||||
};
|
||||
22
xpcom/ds/nsIWritablePropertyBag2.idl
Normal file
22
xpcom/ds/nsIWritablePropertyBag2.idl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* 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/. */
|
||||
|
||||
/* nsIVariant based Property Bag support. */
|
||||
|
||||
#include "nsIPropertyBag2.idl"
|
||||
|
||||
[scriptable, uuid(9cfd1587-360e-4957-a58f-4c2b1c5e7ed9)]
|
||||
interface nsIWritablePropertyBag2 : nsIPropertyBag2
|
||||
{
|
||||
void setPropertyAsInt32 (in AString prop, in int32_t value);
|
||||
void setPropertyAsUint32 (in AString prop, in uint32_t value);
|
||||
void setPropertyAsInt64 (in AString prop, in int64_t value);
|
||||
void setPropertyAsUint64 (in AString prop, in uint64_t value);
|
||||
void setPropertyAsDouble (in AString prop, in double value);
|
||||
void setPropertyAsAString (in AString prop, in AString value);
|
||||
void setPropertyAsACString (in AString prop, in ACString value);
|
||||
void setPropertyAsAUTF8String (in AString prop, in AUTF8String value);
|
||||
void setPropertyAsBool (in AString prop, in boolean value);
|
||||
void setPropertyAsInterface (in AString prop, in nsISupports value);
|
||||
};
|
||||
127
xpcom/ds/nsMathUtils.h
Normal file
127
xpcom/ds/nsMathUtils.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsMathUtils_h__
|
||||
#define nsMathUtils_h__
|
||||
|
||||
#include "nscore.h"
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
|
||||
#ifdef SOLARIS
|
||||
#include <ieeefp.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* round
|
||||
*/
|
||||
inline double
|
||||
NS_round(double aNum)
|
||||
{
|
||||
return aNum >= 0.0 ? floor(aNum + 0.5) : ceil(aNum - 0.5);
|
||||
}
|
||||
inline float
|
||||
NS_roundf(float aNum)
|
||||
{
|
||||
return aNum >= 0.0f ? floorf(aNum + 0.5f) : ceilf(aNum - 0.5f);
|
||||
}
|
||||
inline int32_t
|
||||
NS_lround(double aNum)
|
||||
{
|
||||
return aNum >= 0.0 ? int32_t(aNum + 0.5) : int32_t(aNum - 0.5);
|
||||
}
|
||||
|
||||
/* NS_roundup30 rounds towards infinity for positive and */
|
||||
/* negative numbers. */
|
||||
|
||||
#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
|
||||
inline int32_t NS_lroundup30(float x)
|
||||
{
|
||||
/* Code derived from Laurent de Soras' paper at */
|
||||
/* http://ldesoras.free.fr/doc/articles/rounding_en.pdf */
|
||||
|
||||
/* Rounding up on Windows is expensive using the float to */
|
||||
/* int conversion and the floor function. A faster */
|
||||
/* approach is to use f87 rounding while assuming the */
|
||||
/* default rounding mode of rounding to the nearest */
|
||||
/* integer. This rounding mode, however, actually rounds */
|
||||
/* to the nearest integer so we add the floating point */
|
||||
/* number to itself and add our rounding factor before */
|
||||
/* doing the conversion to an integer. We then do a right */
|
||||
/* shift of one bit on the integer to divide by two. */
|
||||
|
||||
/* This routine doesn't handle numbers larger in magnitude */
|
||||
/* than 2^30 but this is fine for NSToCoordRound because */
|
||||
/* Coords are limited to 2^30 in magnitude. */
|
||||
|
||||
static const double round_to_nearest = 0.5f;
|
||||
int i;
|
||||
|
||||
__asm {
|
||||
fld x ; load fp argument
|
||||
fadd st, st(0) ; double it
|
||||
fadd round_to_nearest ; add the rounding factor
|
||||
fistp dword ptr i ; convert the result to int
|
||||
}
|
||||
return i >> 1; /* divide by 2 */
|
||||
}
|
||||
#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
|
||||
|
||||
inline int32_t
|
||||
NS_lroundf(float aNum)
|
||||
{
|
||||
return aNum >= 0.0f ? int32_t(aNum + 0.5f) : int32_t(aNum - 0.5f);
|
||||
}
|
||||
|
||||
/*
|
||||
* hypot. We don't need a super accurate version of this, if a platform
|
||||
* turns up with none of the possibilities below it would be okay to fall
|
||||
* back to sqrt(x*x + y*y).
|
||||
*/
|
||||
inline double
|
||||
NS_hypot(double aNum1, double aNum2)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
return __builtin_hypot(aNum1, aNum2);
|
||||
#elif defined _WIN32
|
||||
return _hypot(aNum1, aNum2);
|
||||
#else
|
||||
return hypot(aNum1, aNum2);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a floating point number is finite (not +/-infinity and not a
|
||||
* NaN value).
|
||||
*/
|
||||
inline bool
|
||||
NS_finite(double aNum)
|
||||
{
|
||||
#ifdef WIN32
|
||||
// NOTE: '!!' casts an int to bool without spamming MSVC warning C4800.
|
||||
return !!_finite(aNum);
|
||||
#elif defined(XP_DARWIN)
|
||||
// Darwin has deprecated |finite| and recommends |isfinite|. The former is
|
||||
// not present in the iOS SDK.
|
||||
return std::isfinite(aNum);
|
||||
#else
|
||||
return finite(aNum);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result of the modulo of x by y using a floored division.
|
||||
* fmod(x, y) is using a truncated division.
|
||||
* The main difference is that the result of this method will have the sign of
|
||||
* y while the result of fmod(x, y) will have the sign of x.
|
||||
*/
|
||||
inline double
|
||||
NS_floorModulo(double aNum1, double aNum2)
|
||||
{
|
||||
return (aNum1 - aNum2 * floor(aNum1 / aNum2));
|
||||
}
|
||||
|
||||
#endif
|
||||
142
xpcom/ds/nsObserverList.cpp
Normal file
142
xpcom/ds/nsObserverList.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsObserverList.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
nsresult
|
||||
nsObserverList::AddObserver(nsIObserver* anObserver, bool ownsWeak)
|
||||
{
|
||||
NS_ASSERTION(anObserver, "Null input");
|
||||
|
||||
if (!ownsWeak) {
|
||||
ObserverRef* o = mObservers.AppendElement(anObserver);
|
||||
if (!o) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(anObserver);
|
||||
if (!weak) {
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
ObserverRef* o = mObservers.AppendElement(weak);
|
||||
if (!o) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsObserverList::RemoveObserver(nsIObserver* anObserver)
|
||||
{
|
||||
NS_ASSERTION(anObserver, "Null input");
|
||||
|
||||
if (mObservers.RemoveElement(static_cast<nsISupports*>(anObserver))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWeakReference> observerRef = do_GetWeakReference(anObserver);
|
||||
if (!observerRef) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mObservers.RemoveElement(observerRef)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator)
|
||||
{
|
||||
RefPtr<nsObserverEnumerator> e(new nsObserverEnumerator(this));
|
||||
e.forget(anEnumerator);
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverList::FillObserverArray(nsCOMArray<nsIObserver>& aArray)
|
||||
{
|
||||
aArray.SetCapacity(mObservers.Length());
|
||||
|
||||
nsTArray<ObserverRef> observers(mObservers);
|
||||
|
||||
for (int32_t i = observers.Length() - 1; i >= 0; --i) {
|
||||
if (observers[i].isWeakRef) {
|
||||
nsCOMPtr<nsIObserver> o(do_QueryReferent(observers[i].asWeak()));
|
||||
if (o) {
|
||||
aArray.AppendObject(o);
|
||||
} else {
|
||||
// the object has gone away, remove the weakref
|
||||
mObservers.RemoveElement(observers[i].asWeak());
|
||||
}
|
||||
} else {
|
||||
aArray.AppendObject(observers[i].asObserver());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverList::AppendStrongObservers(nsCOMArray<nsIObserver>& aArray)
|
||||
{
|
||||
aArray.SetCapacity(aArray.Length() + mObservers.Length());
|
||||
|
||||
for (int32_t i = mObservers.Length() - 1; i >= 0; --i) {
|
||||
if (!mObservers[i].isWeakRef) {
|
||||
aArray.AppendObject(mObservers[i].asObserver());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverList::NotifyObservers(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* someData)
|
||||
{
|
||||
nsCOMArray<nsIObserver> observers;
|
||||
FillObserverArray(observers);
|
||||
|
||||
for (int32_t i = 0; i < observers.Count(); ++i) {
|
||||
observers[i]->Observe(aSubject, aTopic, someData);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsObserverEnumerator, nsISimpleEnumerator)
|
||||
|
||||
nsObserverEnumerator::nsObserverEnumerator(nsObserverList* aObserverList)
|
||||
: mIndex(0)
|
||||
{
|
||||
aObserverList->FillObserverArray(mObservers);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverEnumerator::HasMoreElements(bool* aResult)
|
||||
{
|
||||
*aResult = (mIndex < mObservers.Count());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverEnumerator::GetNext(nsISupports** aResult)
|
||||
{
|
||||
if (mIndex == mObservers.Count()) {
|
||||
NS_ERROR("Enumerating after HasMoreElements returned false.");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = mObservers[mIndex]);
|
||||
++mIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
93
xpcom/ds/nsObserverList.h
Normal file
93
xpcom/ds/nsObserverList.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsObserverList_h___
|
||||
#define nsObserverList_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
struct ObserverRef
|
||||
{
|
||||
ObserverRef(const ObserverRef& aO) : isWeakRef(aO.isWeakRef), ref(aO.ref) {}
|
||||
explicit ObserverRef(nsIObserver* aObserver) : isWeakRef(false), ref(aObserver) {}
|
||||
explicit ObserverRef(nsIWeakReference* aWeak) : isWeakRef(true), ref(aWeak) {}
|
||||
|
||||
bool isWeakRef;
|
||||
nsCOMPtr<nsISupports> ref;
|
||||
|
||||
nsIObserver* asObserver()
|
||||
{
|
||||
NS_ASSERTION(!isWeakRef, "Isn't a strong ref.");
|
||||
return static_cast<nsIObserver*>((nsISupports*)ref);
|
||||
}
|
||||
|
||||
nsIWeakReference* asWeak()
|
||||
{
|
||||
NS_ASSERTION(isWeakRef, "Isn't a weak ref.");
|
||||
return static_cast<nsIWeakReference*>((nsISupports*)ref);
|
||||
}
|
||||
|
||||
bool operator==(nsISupports* aRhs) const { return ref == aRhs; }
|
||||
};
|
||||
|
||||
class nsObserverList : public nsCharPtrHashKey
|
||||
{
|
||||
friend class nsObserverService;
|
||||
|
||||
public:
|
||||
explicit nsObserverList(const char* aKey) : nsCharPtrHashKey(aKey)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsObserverList);
|
||||
}
|
||||
|
||||
~nsObserverList()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsObserverList);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE nsresult AddObserver(nsIObserver* aObserver, bool aOwnsWeak);
|
||||
MOZ_MUST_USE nsresult RemoveObserver(nsIObserver* aObserver);
|
||||
|
||||
void NotifyObservers(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aSomeData);
|
||||
void GetObserverList(nsISimpleEnumerator** aEnumerator);
|
||||
|
||||
// Fill an array with the observers of this category.
|
||||
// The array is filled in last-added-first order.
|
||||
void FillObserverArray(nsCOMArray<nsIObserver>& aArray);
|
||||
|
||||
// Like FillObserverArray(), but only for strongly held observers.
|
||||
void AppendStrongObservers(nsCOMArray<nsIObserver>& aArray);
|
||||
|
||||
private:
|
||||
nsTArray<ObserverRef> mObservers;
|
||||
};
|
||||
|
||||
class nsObserverEnumerator final : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
explicit nsObserverEnumerator(nsObserverList* aObserverList);
|
||||
|
||||
private:
|
||||
~nsObserverEnumerator() {}
|
||||
|
||||
int32_t mIndex; // Counts up from 0
|
||||
nsCOMArray<nsIObserver> mObservers;
|
||||
};
|
||||
|
||||
#endif /* nsObserverList_h___ */
|
||||
312
xpcom/ds/nsObserverService.cpp
Normal file
312
xpcom/ds/nsObserverService.cpp
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsObserverService.h"
|
||||
#include "nsObserverList.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/net/NeckoCommon.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#define NOTIFY_GLOBAL_OBSERVERS
|
||||
|
||||
// Log module for nsObserverService logging...
|
||||
//
|
||||
// To enable logging (see prlog.h for full details):
|
||||
//
|
||||
// set MOZ_LOG=ObserverService:5
|
||||
// set MOZ_LOG_FILE=service.log
|
||||
//
|
||||
// This enables LogLevel::Debug level information and places all output in
|
||||
// the file service.log.
|
||||
static mozilla::LazyLogModule sObserverServiceLog("ObserverService");
|
||||
#define LOG(x) MOZ_LOG(sObserverServiceLog, mozilla::LogLevel::Debug, x)
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize)
|
||||
{
|
||||
struct SuspectObserver
|
||||
{
|
||||
SuspectObserver(const char* aTopic, size_t aReferentCount)
|
||||
: mTopic(aTopic)
|
||||
, mReferentCount(aReferentCount)
|
||||
{}
|
||||
const char* mTopic;
|
||||
size_t mReferentCount;
|
||||
};
|
||||
|
||||
size_t totalNumStrong = 0;
|
||||
size_t totalNumWeakAlive = 0;
|
||||
size_t totalNumWeakDead = 0;
|
||||
nsTArray<SuspectObserver> suspectObservers;
|
||||
|
||||
for (auto iter = mObserverTopicTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsObserverList* observerList = iter.Get();
|
||||
if (!observerList) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t topicNumStrong = 0;
|
||||
size_t topicNumWeakAlive = 0;
|
||||
size_t topicNumWeakDead = 0;
|
||||
|
||||
nsTArray<ObserverRef>& observers = observerList->mObservers;
|
||||
for (uint32_t i = 0; i < observers.Length(); i++) {
|
||||
if (observers[i].isWeakRef) {
|
||||
nsCOMPtr<nsIObserver> observerRef(
|
||||
do_QueryReferent(observers[i].asWeak()));
|
||||
if (observerRef) {
|
||||
topicNumWeakAlive++;
|
||||
} else {
|
||||
topicNumWeakDead++;
|
||||
}
|
||||
} else {
|
||||
topicNumStrong++;
|
||||
}
|
||||
}
|
||||
|
||||
totalNumStrong += topicNumStrong;
|
||||
totalNumWeakAlive += topicNumWeakAlive;
|
||||
totalNumWeakDead += topicNumWeakDead;
|
||||
|
||||
// Keep track of topics that have a suspiciously large number
|
||||
// of referents (symptom of leaks).
|
||||
size_t topicTotal = topicNumStrong + topicNumWeakAlive + topicNumWeakDead;
|
||||
if (topicTotal > kSuspectReferentCount) {
|
||||
SuspectObserver suspect(observerList->GetKey(), topicTotal);
|
||||
suspectObservers.AppendElement(suspect);
|
||||
}
|
||||
}
|
||||
|
||||
// These aren't privacy-sensitive and so don't need anonymizing.
|
||||
for (uint32_t i = 0; i < suspectObservers.Length(); i++) {
|
||||
SuspectObserver& suspect = suspectObservers[i];
|
||||
nsPrintfCString suspectPath("observer-service-suspect/referent(topic=%s)",
|
||||
suspect.mTopic);
|
||||
aHandleReport->Callback(
|
||||
/* process */ EmptyCString(),
|
||||
suspectPath, KIND_OTHER, UNITS_COUNT, suspect.mReferentCount,
|
||||
NS_LITERAL_CSTRING("A topic with a suspiciously large number of "
|
||||
"referents. This may be symptomatic of a leak "
|
||||
"if the number of referents is high with "
|
||||
"respect to the number of windows."),
|
||||
aData);
|
||||
}
|
||||
|
||||
MOZ_COLLECT_REPORT(
|
||||
"observer-service/referent/strong", KIND_OTHER, UNITS_COUNT,
|
||||
totalNumStrong,
|
||||
"The number of strong references held by the observer service.");
|
||||
|
||||
MOZ_COLLECT_REPORT(
|
||||
"observer-service/referent/weak/alive", KIND_OTHER, UNITS_COUNT,
|
||||
totalNumWeakAlive,
|
||||
"The number of weak references held by the observer service that are "
|
||||
"still alive.");
|
||||
|
||||
MOZ_COLLECT_REPORT(
|
||||
"observer-service/referent/weak/dead", KIND_OTHER, UNITS_COUNT,
|
||||
totalNumWeakDead,
|
||||
"The number of weak references held by the observer service that are "
|
||||
"dead.");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsObserverService Implementation
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsObserverService,
|
||||
nsIObserverService,
|
||||
nsObserverService,
|
||||
nsIMemoryReporter)
|
||||
|
||||
nsObserverService::nsObserverService()
|
||||
: mShuttingDown(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsObserverService::~nsObserverService(void)
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverService::RegisterReporter()
|
||||
{
|
||||
RegisterWeakMemoryReporter(this);
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverService::Shutdown()
|
||||
{
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
|
||||
mShuttingDown = true;
|
||||
|
||||
mObserverTopicTable.Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsObserverService::Create(nsISupports* aOuter, const nsIID& aIID,
|
||||
void** aInstancePtr)
|
||||
{
|
||||
LOG(("nsObserverService::Create()"));
|
||||
|
||||
RefPtr<nsObserverService> os = new nsObserverService();
|
||||
|
||||
if (!os) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// The memory reporter can not be immediately registered here because
|
||||
// the nsMemoryReporterManager may attempt to get the nsObserverService
|
||||
// during initialization, causing a recursive GetService.
|
||||
NS_DispatchToCurrentThread(NewRunnableMethod(os, &nsObserverService::RegisterReporter));
|
||||
|
||||
return os->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
#define NS_ENSURE_VALIDCALL \
|
||||
if (!NS_IsMainThread()) { \
|
||||
MOZ_CRASH("Using observer service off the main thread!"); \
|
||||
return NS_ERROR_UNEXPECTED; \
|
||||
} \
|
||||
if (mShuttingDown) { \
|
||||
NS_ERROR("Using observer service after XPCOM shutdown!"); \
|
||||
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; \
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverService::AddObserver(nsIObserver* aObserver, const char* aTopic,
|
||||
bool aOwnsWeak)
|
||||
{
|
||||
LOG(("nsObserverService::AddObserver(%p: %s)",
|
||||
(void*)aObserver, aTopic));
|
||||
|
||||
NS_ENSURE_VALIDCALL
|
||||
if (NS_WARN_IF(!aObserver) || NS_WARN_IF(!aTopic)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Specifically allow http-on-opening-request in the child process;
|
||||
// see bug 1269765.
|
||||
if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8) &&
|
||||
strcmp(aTopic, "http-on-opening-request")) {
|
||||
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
|
||||
error->Init(NS_LITERAL_STRING("http-on-* observers only work in the parent process"),
|
||||
EmptyString(), EmptyString(), 0, 0,
|
||||
nsIScriptError::warningFlag, "chrome javascript");
|
||||
console->LogMessage(error);
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsObserverList* observerList = mObserverTopicTable.PutEntry(aTopic);
|
||||
if (!observerList) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return observerList->AddObserver(aObserver, aOwnsWeak);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverService::RemoveObserver(nsIObserver* aObserver, const char* aTopic)
|
||||
{
|
||||
LOG(("nsObserverService::RemoveObserver(%p: %s)",
|
||||
(void*)aObserver, aTopic));
|
||||
NS_ENSURE_VALIDCALL
|
||||
if (NS_WARN_IF(!aObserver) || NS_WARN_IF(!aTopic)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsObserverList* observerList = mObserverTopicTable.GetEntry(aTopic);
|
||||
if (!observerList) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* This death grip is to protect against stupid consumers who call
|
||||
RemoveObserver from their Destructor, see bug 485834/bug 325392. */
|
||||
nsCOMPtr<nsIObserver> kungFuDeathGrip(aObserver);
|
||||
return observerList->RemoveObserver(aObserver);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverService::EnumerateObservers(const char* aTopic,
|
||||
nsISimpleEnumerator** anEnumerator)
|
||||
{
|
||||
NS_ENSURE_VALIDCALL
|
||||
if (NS_WARN_IF(!anEnumerator) || NS_WARN_IF(!aTopic)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsObserverList* observerList = mObserverTopicTable.GetEntry(aTopic);
|
||||
if (!observerList) {
|
||||
return NS_NewEmptyEnumerator(anEnumerator);
|
||||
}
|
||||
|
||||
observerList->GetObserverList(anEnumerator);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Enumerate observers of aTopic and call Observe on each.
|
||||
NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aSomeData)
|
||||
{
|
||||
LOG(("nsObserverService::NotifyObservers(%s)", aTopic));
|
||||
|
||||
NS_ENSURE_VALIDCALL
|
||||
if (NS_WARN_IF(!aTopic)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsObserverList* observerList = mObserverTopicTable.GetEntry(aTopic);
|
||||
if (observerList) {
|
||||
observerList->NotifyObservers(aSubject, aTopic, aSomeData);
|
||||
}
|
||||
|
||||
#ifdef NOTIFY_GLOBAL_OBSERVERS
|
||||
observerList = mObserverTopicTable.GetEntry("*");
|
||||
if (observerList) {
|
||||
observerList->NotifyObservers(aSubject, aTopic, aSomeData);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverService::UnmarkGrayStrongObservers()
|
||||
{
|
||||
NS_ENSURE_VALIDCALL
|
||||
|
||||
nsCOMArray<nsIObserver> strongObservers;
|
||||
for (auto iter = mObserverTopicTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsObserverList* aObserverList = iter.Get();
|
||||
if (aObserverList) {
|
||||
aObserverList->AppendStrongObservers(strongObservers);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < strongObservers.Length(); ++i) {
|
||||
xpc_TryUnmarkWrappedGrayObject(strongObservers[i]);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
55
xpcom/ds/nsObserverService.h
Normal file
55
xpcom/ds/nsObserverService.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsObserverService_h___
|
||||
#define nsObserverService_h___
|
||||
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsObserverList.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// {D07F5195-E3D1-11d2-8ACD-00105A1B8860}
|
||||
#define NS_OBSERVERSERVICE_CID \
|
||||
{ 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } }
|
||||
|
||||
class nsIMemoryReporter;
|
||||
|
||||
class nsObserverService final
|
||||
: public nsIObserverService
|
||||
, public nsIMemoryReporter
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_OBSERVERSERVICE_CID)
|
||||
|
||||
nsObserverService();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVERSERVICE
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
void Shutdown();
|
||||
|
||||
static MOZ_MUST_USE nsresult Create(nsISupports* aOuter, const nsIID& aIID,
|
||||
void** aInstancePtr);
|
||||
|
||||
// Unmark any strongly held observers implemented in JS so the cycle
|
||||
// collector will not traverse them.
|
||||
NS_IMETHOD UnmarkGrayStrongObservers();
|
||||
|
||||
private:
|
||||
~nsObserverService(void);
|
||||
void RegisterReporter();
|
||||
|
||||
static const size_t kSuspectReferentCount = 100;
|
||||
bool mShuttingDown;
|
||||
nsTHashtable<nsObserverList> mObserverTopicTable;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsObserverService, NS_OBSERVERSERVICE_CID)
|
||||
|
||||
#endif /* nsObserverService_h___ */
|
||||
666
xpcom/ds/nsPersistentProperties.cpp
Normal file
666
xpcom/ds/nsPersistentProperties.cpp
Normal file
|
|
@ -0,0 +1,666 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsID.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsUnicharInputStream.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#define PL_ARENA_CONST_ALIGN_MASK 3
|
||||
#include "nsPersistentProperties.h"
|
||||
#include "nsIProperties.h"
|
||||
|
||||
struct PropertyTableEntry : public PLDHashEntryHdr
|
||||
{
|
||||
// both of these are arena-allocated
|
||||
const char* mKey;
|
||||
const char16_t* mValue;
|
||||
};
|
||||
|
||||
static char16_t*
|
||||
ArenaStrdup(const nsAFlatString& aString, PLArenaPool* aArena)
|
||||
{
|
||||
void* mem;
|
||||
// add one to include the null terminator
|
||||
int32_t len = (aString.Length() + 1) * sizeof(char16_t);
|
||||
PL_ARENA_ALLOCATE(mem, aArena, len);
|
||||
NS_ASSERTION(mem, "Couldn't allocate space!\n");
|
||||
if (mem) {
|
||||
memcpy(mem, aString.get(), len);
|
||||
}
|
||||
return static_cast<char16_t*>(mem);
|
||||
}
|
||||
|
||||
static char*
|
||||
ArenaStrdup(const nsAFlatCString& aString, PLArenaPool* aArena)
|
||||
{
|
||||
void* mem;
|
||||
// add one to include the null terminator
|
||||
int32_t len = (aString.Length() + 1) * sizeof(char);
|
||||
PL_ARENA_ALLOCATE(mem, aArena, len);
|
||||
NS_ASSERTION(mem, "Couldn't allocate space!\n");
|
||||
if (mem) {
|
||||
memcpy(mem, aString.get(), len);
|
||||
}
|
||||
return static_cast<char*>(mem);
|
||||
}
|
||||
|
||||
static const struct PLDHashTableOps property_HashTableOps = {
|
||||
PLDHashTable::HashStringKey,
|
||||
PLDHashTable::MatchStringKey,
|
||||
PLDHashTable::MoveEntryStub,
|
||||
PLDHashTable::ClearEntryStub,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
//
|
||||
// parser stuff
|
||||
//
|
||||
enum EParserState
|
||||
{
|
||||
eParserState_AwaitingKey,
|
||||
eParserState_Key,
|
||||
eParserState_AwaitingValue,
|
||||
eParserState_Value,
|
||||
eParserState_Comment
|
||||
};
|
||||
|
||||
enum EParserSpecial
|
||||
{
|
||||
eParserSpecial_None, // not parsing a special character
|
||||
eParserSpecial_Escaped, // awaiting a special character
|
||||
eParserSpecial_Unicode // parsing a \Uxxx value
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS nsPropertiesParser
|
||||
{
|
||||
public:
|
||||
explicit nsPropertiesParser(nsIPersistentProperties* aProps)
|
||||
: mHaveMultiLine(false)
|
||||
, mState(eParserState_AwaitingKey)
|
||||
, mProps(aProps)
|
||||
{
|
||||
}
|
||||
|
||||
void FinishValueState(nsAString& aOldValue)
|
||||
{
|
||||
static const char trimThese[] = " \t";
|
||||
mKey.Trim(trimThese, false, true);
|
||||
|
||||
// This is really ugly hack but it should be fast
|
||||
char16_t backup_char;
|
||||
uint32_t minLength = mMinLength;
|
||||
if (minLength) {
|
||||
backup_char = mValue[minLength - 1];
|
||||
mValue.SetCharAt('x', minLength - 1);
|
||||
}
|
||||
mValue.Trim(trimThese, false, true);
|
||||
if (minLength) {
|
||||
mValue.SetCharAt(backup_char, minLength - 1);
|
||||
}
|
||||
|
||||
mProps->SetStringProperty(NS_ConvertUTF16toUTF8(mKey), mValue, aOldValue);
|
||||
mSpecialState = eParserSpecial_None;
|
||||
WaitForKey();
|
||||
}
|
||||
|
||||
EParserState GetState() { return mState; }
|
||||
|
||||
static nsresult SegmentWriter(nsIUnicharInputStream* aStream,
|
||||
void* aClosure,
|
||||
const char16_t* aFromSegment,
|
||||
uint32_t aToOffset,
|
||||
uint32_t aCount,
|
||||
uint32_t* aWriteCount);
|
||||
|
||||
nsresult ParseBuffer(const char16_t* aBuffer, uint32_t aBufferLength);
|
||||
|
||||
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
|
||||
|
||||
void WaitForKey()
|
||||
{
|
||||
mState = eParserState_AwaitingKey;
|
||||
}
|
||||
|
||||
void EnterKeyState()
|
||||
{
|
||||
mKey.Truncate();
|
||||
mState = eParserState_Key;
|
||||
}
|
||||
|
||||
void WaitForValue()
|
||||
{
|
||||
mState = eParserState_AwaitingValue;
|
||||
}
|
||||
|
||||
void EnterValueState()
|
||||
{
|
||||
mValue.Truncate();
|
||||
mMinLength = 0;
|
||||
mState = eParserState_Value;
|
||||
mSpecialState = eParserSpecial_None;
|
||||
}
|
||||
|
||||
void EnterCommentState()
|
||||
{
|
||||
mState = eParserState_Comment;
|
||||
}
|
||||
|
||||
nsAutoString mKey;
|
||||
nsAutoString mValue;
|
||||
|
||||
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
|
||||
uint32_t mMinLength; // limit right trimming at the end to not trim
|
||||
// escaped whitespaces
|
||||
EParserState mState;
|
||||
// if we see a '\' then we enter this special state
|
||||
EParserSpecial mSpecialState;
|
||||
nsCOMPtr<nsIPersistentProperties> mProps;
|
||||
};
|
||||
|
||||
inline bool
|
||||
IsWhiteSpace(char16_t aChar)
|
||||
{
|
||||
return (aChar == ' ') || (aChar == '\t') ||
|
||||
(aChar == '\r') || (aChar == '\n');
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsEOL(char16_t aChar)
|
||||
{
|
||||
return (aChar == '\r') || (aChar == '\n');
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
MOZ_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;
|
||||
|
||||
switch (aChar) {
|
||||
// the easy characters - \t, \n, and so forth
|
||||
case 't':
|
||||
mValue += char16_t('\t');
|
||||
mMinLength = mValue.Length();
|
||||
break;
|
||||
case 'n':
|
||||
mValue += char16_t('\n');
|
||||
mMinLength = mValue.Length();
|
||||
break;
|
||||
case 'r':
|
||||
mValue += char16_t('\r');
|
||||
mMinLength = mValue.Length();
|
||||
break;
|
||||
case '\\':
|
||||
mValue += char16_t('\\');
|
||||
break;
|
||||
|
||||
// switch to unicode mode!
|
||||
case 'u':
|
||||
case 'U':
|
||||
mSpecialState = eParserSpecial_Unicode;
|
||||
mUnicodeValuesRead = 0;
|
||||
mUnicodeValue = 0;
|
||||
break;
|
||||
|
||||
// a \ immediately followed by a newline means we're going multiline
|
||||
case '\r':
|
||||
case '\n':
|
||||
mHaveMultiLine = true;
|
||||
mMultiLineCanSkipN = (aChar == '\r');
|
||||
mSpecialState = eParserSpecial_None;
|
||||
break;
|
||||
|
||||
default:
|
||||
// don't recognize the character, so just append it
|
||||
mValue += aChar;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// we're in the middle of parsing a 4-character unicode value
|
||||
// like \u5f39
|
||||
case eParserSpecial_Unicode:
|
||||
if ('0' <= aChar && aChar <= '9') {
|
||||
mUnicodeValue =
|
||||
(mUnicodeValue << 4) | (aChar - '0');
|
||||
} else if ('a' <= aChar && aChar <= 'f') {
|
||||
mUnicodeValue =
|
||||
(mUnicodeValue << 4) | (aChar - 'a' + 0x0a);
|
||||
} else if ('A' <= aChar && aChar <= 'F') {
|
||||
mUnicodeValue =
|
||||
(mUnicodeValue << 4) | (aChar - 'A' + 0x0a);
|
||||
} else {
|
||||
// non-hex character. Append what we have, and move on.
|
||||
mValue += mUnicodeValue;
|
||||
mMinLength = mValue.Length();
|
||||
mSpecialState = eParserSpecial_None;
|
||||
|
||||
// leave aTokenStart at this unknown character, so it gets appended
|
||||
aTokenStart = aCur;
|
||||
|
||||
// ensure parsing this non-hex character again
|
||||
return false;
|
||||
}
|
||||
|
||||
if (++mUnicodeValuesRead >= 4) {
|
||||
aTokenStart = aCur + 1;
|
||||
mSpecialState = eParserSpecial_None;
|
||||
mValue += mUnicodeValue;
|
||||
mMinLength = mValue.Length();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPropertiesParser::SegmentWriter(nsIUnicharInputStream* aStream,
|
||||
void* aClosure,
|
||||
const char16_t* aFromSegment,
|
||||
uint32_t aToOffset,
|
||||
uint32_t aCount,
|
||||
uint32_t* aWriteCount)
|
||||
{
|
||||
nsPropertiesParser* parser = static_cast<nsPropertiesParser*>(aClosure);
|
||||
parser->ParseBuffer(aFromSegment, aCount);
|
||||
|
||||
*aWriteCount = aCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
else if (!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
|
||||
else if (!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..
|
||||
else if (mState == eParserState_Key && tokenStart) {
|
||||
mKey += Substring(tokenStart, cur);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPersistentProperties::nsPersistentProperties()
|
||||
: mIn(nullptr)
|
||||
, mTable(&property_HashTableOps, sizeof(PropertyTableEntry), 16)
|
||||
{
|
||||
PL_INIT_ARENA_POOL(&mArena, "PersistentPropertyArena", 2048);
|
||||
}
|
||||
|
||||
nsPersistentProperties::~nsPersistentProperties()
|
||||
{
|
||||
PL_FinishArenaPool(&mArena);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPersistentProperties::Create(nsISupports* aOuter, REFNSIID aIID,
|
||||
void** aResult)
|
||||
{
|
||||
if (aOuter) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
RefPtr<nsPersistentProperties> props = new nsPersistentProperties();
|
||||
return props->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPersistentProperties, nsIPersistentProperties, nsIProperties)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::Load(nsIInputStream* aIn)
|
||||
{
|
||||
nsresult rv = NS_NewUnicharInputStream(aIn, getter_AddRefs(mIn));
|
||||
|
||||
if (rv != NS_OK) {
|
||||
NS_WARNING("Error creating UnicharInputStream");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsPropertiesParser parser(this);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::SetStringProperty(const nsACString& aKey,
|
||||
const nsAString& aNewValue,
|
||||
nsAString& aOldValue)
|
||||
{
|
||||
const nsAFlatCString& flatKey = PromiseFlatCString(aKey);
|
||||
auto entry = static_cast<PropertyTableEntry*>
|
||||
(mTable.Add(flatKey.get()));
|
||||
|
||||
if (entry->mKey) {
|
||||
aOldValue = entry->mValue;
|
||||
NS_WARNING(nsPrintfCString("the property %s already exists",
|
||||
flatKey.get()).get());
|
||||
} else {
|
||||
aOldValue.Truncate();
|
||||
}
|
||||
|
||||
entry->mKey = ArenaStrdup(flatKey, &mArena);
|
||||
entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::Save(nsIOutputStream* aOut, const nsACString& aHeader)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::GetStringProperty(const nsACString& aKey,
|
||||
nsAString& aValue)
|
||||
{
|
||||
const nsAFlatCString& flatKey = PromiseFlatCString(aKey);
|
||||
|
||||
auto entry = static_cast<PropertyTableEntry*>(mTable.Search(flatKey.get()));
|
||||
if (!entry) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aValue = entry->mValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult)
|
||||
{
|
||||
nsCOMArray<nsIPropertyElement> props;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_NewArrayEnumerator(aResult, props);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XXX Some day we'll unify the nsIPersistentProperties interface with
|
||||
// nsIProperties, but until now...
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::Get(const char* aProp, const nsIID& aUUID,
|
||||
void** aResult)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::Set(const char* aProp, nsISupports* value)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::Undefine(const char* aProp)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::Has(const char* aProp, bool* aResult)
|
||||
{
|
||||
*aResult = !!mTable.Search(aProp);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPersistentProperties::GetKeys(uint32_t* aCount, char*** aKeys)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// PropertyElement
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
nsPropertyElement::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
{
|
||||
if (aOuter) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
RefPtr<nsPropertyElement> propElem = new nsPropertyElement();
|
||||
return propElem->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPropertyElement, nsIPropertyElement)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPropertyElement::GetKey(nsACString& aReturnKey)
|
||||
{
|
||||
aReturnKey = mKey;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPropertyElement::GetValue(nsAString& aReturnValue)
|
||||
{
|
||||
aReturnValue = mValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPropertyElement::SetKey(const nsACString& aKey)
|
||||
{
|
||||
mKey = aKey;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPropertyElement::SetValue(const nsAString& aValue)
|
||||
{
|
||||
mValue = aValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
67
xpcom/ds/nsPersistentProperties.h
Normal file
67
xpcom/ds/nsPersistentProperties.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsPersistentProperties_h___
|
||||
#define nsPersistentProperties_h___
|
||||
|
||||
#include "nsIPersistentProperties2.h"
|
||||
#include "PLDHashTable.h"
|
||||
#include "plarena.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIUnicharInputStream;
|
||||
|
||||
class nsPersistentProperties final : public nsIPersistentProperties
|
||||
{
|
||||
public:
|
||||
nsPersistentProperties();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIPROPERTIES
|
||||
NS_DECL_NSIPERSISTENTPROPERTIES
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
private:
|
||||
~nsPersistentProperties();
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIUnicharInputStream> mIn;
|
||||
|
||||
PLDHashTable mTable;
|
||||
PLArenaPool mArena;
|
||||
};
|
||||
|
||||
class nsPropertyElement final : public nsIPropertyElement
|
||||
{
|
||||
public:
|
||||
nsPropertyElement()
|
||||
{
|
||||
}
|
||||
|
||||
nsPropertyElement(const nsACString& aKey, const nsAString& aValue)
|
||||
: mKey(aKey)
|
||||
, mValue(aValue)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPROPERTYELEMENT
|
||||
|
||||
static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
private:
|
||||
~nsPropertyElement() {}
|
||||
|
||||
protected:
|
||||
nsCString mKey;
|
||||
nsString mValue;
|
||||
};
|
||||
|
||||
#endif /* nsPersistentProperties_h___ */
|
||||
99
xpcom/ds/nsProperties.cpp
Normal file
99
xpcom/ds/nsProperties.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsProperties.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMPL_AGGREGATED(nsProperties)
|
||||
NS_INTERFACE_MAP_BEGIN_AGGREGATED(nsProperties)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIProperties)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProperties::Get(const char* prop, const nsIID& uuid, void** result)
|
||||
{
|
||||
if (NS_WARN_IF(!prop)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> value;
|
||||
if (!nsProperties_HashBase::Get(prop, getter_AddRefs(value))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return (value) ? value->QueryInterface(uuid, result) : NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProperties::Set(const char* prop, nsISupports* value)
|
||||
{
|
||||
if (NS_WARN_IF(!prop)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
Put(prop, value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProperties::Undefine(const char* prop)
|
||||
{
|
||||
if (NS_WARN_IF(!prop)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> value;
|
||||
if (!nsProperties_HashBase::Get(prop, getter_AddRefs(value))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
Remove(prop);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProperties::Has(const char* prop, bool* result)
|
||||
{
|
||||
if (NS_WARN_IF(!prop)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> value;
|
||||
*result = nsProperties_HashBase::Get(prop, getter_AddRefs(value));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProperties::GetKeys(uint32_t* aCount, char*** aKeys)
|
||||
{
|
||||
if (NS_WARN_IF(!aCount) || NS_WARN_IF(!aKeys)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
uint32_t count = Count();
|
||||
char** keys = (char**)moz_xmalloc(count * sizeof(char*));
|
||||
uint32_t j = 0;
|
||||
|
||||
for (auto iter = this->Iter(); !iter.Done(); iter.Next()) {
|
||||
const char* key = iter.Key();
|
||||
keys[j] = strdup(key);
|
||||
|
||||
if (!keys[j]) {
|
||||
// Free 'em all
|
||||
for (uint32_t i = 0; i < j; i++) {
|
||||
free(keys[i]);
|
||||
}
|
||||
free(keys);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
*aCount = count;
|
||||
*aKeys = keys;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
39
xpcom/ds/nsProperties.h
Normal file
39
xpcom/ds/nsProperties.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsProperties_h___
|
||||
#define nsProperties_h___
|
||||
|
||||
#include "nsIProperties.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsAgg.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#define NS_PROPERTIES_CID \
|
||||
{ /* 4de2bc90-b1bf-11d3-93b6-00104ba0fd40 */ \
|
||||
0x4de2bc90, \
|
||||
0xb1bf, \
|
||||
0x11d3, \
|
||||
{0x93, 0xb6, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
|
||||
}
|
||||
|
||||
typedef nsInterfaceHashtable<nsCharPtrHashKey,
|
||||
nsISupports> nsProperties_HashBase;
|
||||
|
||||
class nsProperties final
|
||||
: public nsIProperties
|
||||
, public nsProperties_HashBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_AGGREGATED
|
||||
NS_DECL_NSIPROPERTIES
|
||||
|
||||
explicit nsProperties(nsISupports *aOuter) { NS_INIT_AGGREGATED(aOuter); }
|
||||
~nsProperties() {}
|
||||
};
|
||||
|
||||
#endif /* nsProperties_h___ */
|
||||
53
xpcom/ds/nsStaticAtom.h
Normal file
53
xpcom/ds/nsStaticAtom.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsStaticAtom_h__
|
||||
#define nsStaticAtom_h__
|
||||
|
||||
#include "nsIAtom.h"
|
||||
#include "nsStringBuffer.h"
|
||||
|
||||
#define NS_STATIC_ATOM(buffer_name, atom_ptr) \
|
||||
{ (nsStringBuffer*) &buffer_name, atom_ptr }
|
||||
|
||||
#define NS_STATIC_ATOM_BUFFER(buffer_name, str_data) \
|
||||
static nsFakeStringBuffer<sizeof(str_data)> buffer_name = \
|
||||
{ 1, sizeof(str_data) * sizeof(char16_t), (u"" str_data) };
|
||||
|
||||
/**
|
||||
* Holds data used to initialize large number of atoms during startup. Use
|
||||
* the above macros to initialize these structs. They should never be accessed
|
||||
* directly other than from AtomTable.cpp
|
||||
*/
|
||||
struct nsStaticAtom
|
||||
{
|
||||
// mStringBuffer points to the string buffer for a permanent atom, and is
|
||||
// therefore safe as a non-owning reference.
|
||||
nsStringBuffer* MOZ_NON_OWNING_REF mStringBuffer;
|
||||
nsIAtom** mAtom;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a struct with the same binary layout as a nsStringBuffer.
|
||||
*/
|
||||
template<uint32_t size>
|
||||
struct nsFakeStringBuffer
|
||||
{
|
||||
int32_t mRefCnt;
|
||||
uint32_t mSize;
|
||||
char16_t mStringData[size];
|
||||
};
|
||||
|
||||
// Register an array of static atoms with the atom table
|
||||
template<uint32_t N>
|
||||
void
|
||||
NS_RegisterStaticAtoms(const nsStaticAtom (&aAtoms)[N])
|
||||
{
|
||||
extern void RegisterStaticAtoms(const nsStaticAtom*, uint32_t aAtomCount);
|
||||
RegisterStaticAtoms(aAtoms, N);
|
||||
}
|
||||
|
||||
#endif
|
||||
201
xpcom/ds/nsStaticNameTable.cpp
Normal file
201
xpcom/ds/nsStaticNameTable.cpp
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* Class to manage lookup of static names in a table. */
|
||||
|
||||
#include "nsCRT.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
#define PL_ARENA_CONST_ALIGN_MASK 3
|
||||
#include "nsStaticNameTable.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
struct NameTableKey
|
||||
{
|
||||
NameTableKey(const nsDependentCString aNameArray[],
|
||||
const nsAFlatCString* aKeyStr)
|
||||
: mNameArray(aNameArray)
|
||||
, mIsUnichar(false)
|
||||
{
|
||||
mKeyStr.m1b = aKeyStr;
|
||||
}
|
||||
|
||||
NameTableKey(const nsDependentCString aNameArray[],
|
||||
const nsAFlatString* aKeyStr)
|
||||
: mNameArray(aNameArray)
|
||||
, mIsUnichar(true)
|
||||
{
|
||||
mKeyStr.m2b = aKeyStr;
|
||||
}
|
||||
|
||||
const nsDependentCString* mNameArray;
|
||||
union
|
||||
{
|
||||
const nsAFlatCString* m1b;
|
||||
const nsAFlatString* m2b;
|
||||
} mKeyStr;
|
||||
bool mIsUnichar;
|
||||
};
|
||||
|
||||
struct NameTableEntry : public PLDHashEntryHdr
|
||||
{
|
||||
int32_t mIndex;
|
||||
};
|
||||
|
||||
static bool
|
||||
matchNameKeysCaseInsensitive(const PLDHashEntryHdr* aHdr, const void* aVoidKey)
|
||||
{
|
||||
auto entry = static_cast<const NameTableEntry*>(aHdr);
|
||||
auto key = static_cast<const NameTableKey*>(aVoidKey);
|
||||
const nsDependentCString* name = &key->mNameArray[entry->mIndex];
|
||||
|
||||
return key->mIsUnichar
|
||||
? key->mKeyStr.m2b->LowerCaseEqualsASCII(name->get(), name->Length())
|
||||
: key->mKeyStr.m1b->LowerCaseEqualsASCII(name->get(), name->Length());
|
||||
}
|
||||
|
||||
/*
|
||||
* caseInsensitiveHashKey is just like PLDHashTable::HashStringKey except it
|
||||
* uses (*s & ~0x20) instead of simply *s. This means that "aFOO" and
|
||||
* "afoo" and "aFoo" will all hash to the same thing. It also means
|
||||
* that some strings that aren't case-insensensitively equal will hash
|
||||
* to the same value, but it's just a hash function so it doesn't
|
||||
* matter.
|
||||
*/
|
||||
static PLDHashNumber
|
||||
caseInsensitiveStringHashKey(const void* aKey)
|
||||
{
|
||||
PLDHashNumber h = 0;
|
||||
const NameTableKey* tableKey = static_cast<const NameTableKey*>(aKey);
|
||||
if (tableKey->mIsUnichar) {
|
||||
for (const char16_t* s = tableKey->mKeyStr.m2b->get();
|
||||
*s != '\0';
|
||||
s++) {
|
||||
h = AddToHash(h, *s & ~0x20);
|
||||
}
|
||||
} else {
|
||||
for (const unsigned char* s = reinterpret_cast<const unsigned char*>(
|
||||
tableKey->mKeyStr.m1b->get());
|
||||
*s != '\0';
|
||||
s++) {
|
||||
h = AddToHash(h, *s & ~0x20);
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static const struct PLDHashTableOps nametable_CaseInsensitiveHashTableOps = {
|
||||
caseInsensitiveStringHashKey,
|
||||
matchNameKeysCaseInsensitive,
|
||||
PLDHashTable::MoveEntryStub,
|
||||
PLDHashTable::ClearEntryStub,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
nsStaticCaseInsensitiveNameTable::nsStaticCaseInsensitiveNameTable(
|
||||
const char* const aNames[], int32_t aLength)
|
||||
: mNameArray(nullptr)
|
||||
, mNameTable(&nametable_CaseInsensitiveHashTableOps,
|
||||
sizeof(NameTableEntry), aLength)
|
||||
, mNullStr("")
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsStaticCaseInsensitiveNameTable);
|
||||
|
||||
MOZ_ASSERT(aNames, "null name table");
|
||||
MOZ_ASSERT(aLength, "0 length");
|
||||
|
||||
mNameArray = (nsDependentCString*)
|
||||
moz_xmalloc(aLength * sizeof(nsDependentCString));
|
||||
|
||||
for (int32_t index = 0; index < aLength; ++index) {
|
||||
const char* raw = aNames[index];
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// verify invariants of contents
|
||||
nsAutoCString temp1(raw);
|
||||
nsDependentCString temp2(raw);
|
||||
ToLowerCase(temp1);
|
||||
MOZ_ASSERT(temp1.Equals(temp2), "upper case char in table");
|
||||
MOZ_ASSERT(nsCRT::IsAscii(raw),
|
||||
"non-ascii string in table -- "
|
||||
"case-insensitive matching won't work right");
|
||||
}
|
||||
#endif
|
||||
// use placement-new to initialize the string object
|
||||
nsDependentCString* strPtr = &mNameArray[index];
|
||||
new (strPtr) nsDependentCString(raw);
|
||||
|
||||
NameTableKey key(mNameArray, strPtr);
|
||||
|
||||
auto entry = static_cast<NameTableEntry*>(mNameTable.Add(&key, fallible));
|
||||
if (!entry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the entry already exists it's unlikely but possible that its index is
|
||||
// zero, in which case this assertion won't fail. But if the index is
|
||||
// non-zero (highly likely) then it will fail. In other words, this
|
||||
// assertion is likely but not guaranteed to detect if an entry is already
|
||||
// used.
|
||||
MOZ_ASSERT(entry->mIndex == 0, "Entry already exists!");
|
||||
|
||||
entry->mIndex = index;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
mNameTable.MarkImmutable();
|
||||
#endif
|
||||
}
|
||||
|
||||
nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable()
|
||||
{
|
||||
// manually call the destructor on placement-new'ed objects
|
||||
for (uint32_t index = 0; index < mNameTable.EntryCount(); index++) {
|
||||
mNameArray[index].~nsDependentCString();
|
||||
}
|
||||
free((void*)mNameArray);
|
||||
MOZ_COUNT_DTOR(nsStaticCaseInsensitiveNameTable);
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsStaticCaseInsensitiveNameTable::Lookup(const nsACString& aName)
|
||||
{
|
||||
NS_ASSERTION(mNameArray, "not inited");
|
||||
|
||||
const nsAFlatCString& str = PromiseFlatCString(aName);
|
||||
|
||||
NameTableKey key(mNameArray, &str);
|
||||
auto entry = static_cast<NameTableEntry*>(mNameTable.Search(&key));
|
||||
|
||||
return entry ? entry->mIndex : nsStaticCaseInsensitiveNameTable::NOT_FOUND;
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsStaticCaseInsensitiveNameTable::Lookup(const nsAString& aName)
|
||||
{
|
||||
NS_ASSERTION(mNameArray, "not inited");
|
||||
|
||||
const nsAFlatString& str = PromiseFlatString(aName);
|
||||
|
||||
NameTableKey key(mNameArray, &str);
|
||||
auto entry = static_cast<NameTableEntry*>(mNameTable.Search(&key));
|
||||
|
||||
return entry ? entry->mIndex : nsStaticCaseInsensitiveNameTable::NOT_FOUND;
|
||||
}
|
||||
|
||||
const nsAFlatCString&
|
||||
nsStaticCaseInsensitiveNameTable::GetStringValue(int32_t aIndex)
|
||||
{
|
||||
NS_ASSERTION(mNameArray, "not inited");
|
||||
|
||||
if ((NOT_FOUND < aIndex) && ((uint32_t)aIndex < mNameTable.EntryCount())) {
|
||||
return mNameArray[aIndex];
|
||||
}
|
||||
return mNullStr;
|
||||
}
|
||||
49
xpcom/ds/nsStaticNameTable.h
Normal file
49
xpcom/ds/nsStaticNameTable.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* Classes to manage lookup of static names in a table. */
|
||||
|
||||
#ifndef nsStaticNameTable_h___
|
||||
#define nsStaticNameTable_h___
|
||||
|
||||
#include "PLDHashTable.h"
|
||||
#include "nsString.h"
|
||||
|
||||
/* This class supports case insensitive lookup.
|
||||
*
|
||||
* It differs from atom tables:
|
||||
* - It supports case insensitive lookup.
|
||||
* - It has minimal footprint by not copying the string table.
|
||||
* - It does no locking.
|
||||
* - It returns zero based indexes and const nsCString& as required by its
|
||||
* callers in the parser.
|
||||
* - It is not an xpcom interface - meant for fast lookup in static tables.
|
||||
*
|
||||
* ***REQUIREMENTS***
|
||||
* - It *requires* that all entries in the table be lowercase only.
|
||||
* - It *requires* that the table of strings be in memory that lives at least
|
||||
* as long as this table object - typically a static string array.
|
||||
*/
|
||||
|
||||
class nsStaticCaseInsensitiveNameTable
|
||||
{
|
||||
public:
|
||||
enum { NOT_FOUND = -1 };
|
||||
|
||||
int32_t Lookup(const nsACString& aName);
|
||||
int32_t Lookup(const nsAString& aName);
|
||||
const nsAFlatCString& GetStringValue(int32_t aIndex);
|
||||
|
||||
nsStaticCaseInsensitiveNameTable(const char* const aNames[], int32_t aLength);
|
||||
~nsStaticCaseInsensitiveNameTable();
|
||||
|
||||
private:
|
||||
nsDependentCString* mNameArray;
|
||||
PLDHashTable mNameTable;
|
||||
nsDependentCString mNullStr;
|
||||
};
|
||||
|
||||
#endif /* nsStaticNameTable_h___ */
|
||||
262
xpcom/ds/nsStringEnumerator.cpp
Normal file
262
xpcom/ds/nsStringEnumerator.cpp
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
|
||||
#include "nsStringEnumerator.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsSupportsPrimitives.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
//
|
||||
// nsStringEnumerator
|
||||
//
|
||||
|
||||
class nsStringEnumerator final
|
||||
: public nsIStringEnumerator
|
||||
, public nsIUTF8StringEnumerator
|
||||
, public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
nsStringEnumerator(const nsTArray<nsString>* aArray, bool aOwnsArray)
|
||||
: mArray(aArray)
|
||||
, mIndex(0)
|
||||
, mOwnsArray(aOwnsArray)
|
||||
, mIsUnicode(true)
|
||||
{}
|
||||
|
||||
nsStringEnumerator(const nsTArray<nsCString>* aArray, bool aOwnsArray)
|
||||
: mCArray(aArray)
|
||||
, mIndex(0)
|
||||
, mOwnsArray(aOwnsArray)
|
||||
, mIsUnicode(false)
|
||||
{}
|
||||
|
||||
nsStringEnumerator(const nsTArray<nsString>* aArray, nsISupports* aOwner)
|
||||
: mArray(aArray)
|
||||
, mIndex(0)
|
||||
, mOwner(aOwner)
|
||||
, mOwnsArray(false)
|
||||
, mIsUnicode(true)
|
||||
{}
|
||||
|
||||
nsStringEnumerator(const nsTArray<nsCString>* aArray, nsISupports* aOwner)
|
||||
: mCArray(aArray)
|
||||
, mIndex(0)
|
||||
, mOwner(aOwner)
|
||||
, mOwnsArray(false)
|
||||
, mIsUnicode(false)
|
||||
{}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIUTF8STRINGENUMERATOR
|
||||
|
||||
// have to declare nsIStringEnumerator manually, because of
|
||||
// overlapping method names
|
||||
NS_IMETHOD GetNext(nsAString& aResult) override;
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
private:
|
||||
~nsStringEnumerator()
|
||||
{
|
||||
if (mOwnsArray) {
|
||||
// const-casting is safe here, because the NS_New*
|
||||
// constructors make sure mOwnsArray is consistent with
|
||||
// the constness of the objects
|
||||
if (mIsUnicode) {
|
||||
delete const_cast<nsTArray<nsString>*>(mArray);
|
||||
} else {
|
||||
delete const_cast<nsTArray<nsCString>*>(mCArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
const nsTArray<nsString>* mArray;
|
||||
const nsTArray<nsCString>* mCArray;
|
||||
};
|
||||
|
||||
inline uint32_t Count()
|
||||
{
|
||||
return mIsUnicode ? mArray->Length() : mCArray->Length();
|
||||
}
|
||||
|
||||
uint32_t mIndex;
|
||||
|
||||
// the owner allows us to hold a strong reference to the object
|
||||
// that owns the array. Having a non-null value in mOwner implies
|
||||
// that mOwnsArray is false, because we rely on the real owner
|
||||
// to release the array
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
bool mOwnsArray;
|
||||
bool mIsUnicode;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsStringEnumerator,
|
||||
nsIStringEnumerator,
|
||||
nsIUTF8StringEnumerator,
|
||||
nsISimpleEnumerator)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStringEnumerator::HasMore(bool* aResult)
|
||||
{
|
||||
*aResult = mIndex < Count();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStringEnumerator::HasMoreElements(bool* aResult)
|
||||
{
|
||||
return HasMore(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStringEnumerator::GetNext(nsISupports** aResult)
|
||||
{
|
||||
if (mIsUnicode) {
|
||||
nsSupportsString* stringImpl = new nsSupportsString();
|
||||
if (!stringImpl) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
stringImpl->SetData(mArray->ElementAt(mIndex++));
|
||||
*aResult = stringImpl;
|
||||
} else {
|
||||
nsSupportsCString* cstringImpl = new nsSupportsCString();
|
||||
if (!cstringImpl) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
cstringImpl->SetData(mCArray->ElementAt(mIndex++));
|
||||
*aResult = cstringImpl;
|
||||
}
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStringEnumerator::GetNext(nsAString& aResult)
|
||||
{
|
||||
if (NS_WARN_IF(mIndex >= Count())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mIsUnicode) {
|
||||
aResult = mArray->ElementAt(mIndex++);
|
||||
} else {
|
||||
CopyUTF8toUTF16(mCArray->ElementAt(mIndex++), aResult);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStringEnumerator::GetNext(nsACString& aResult)
|
||||
{
|
||||
if (NS_WARN_IF(mIndex >= Count())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mIsUnicode) {
|
||||
CopyUTF16toUTF8(mArray->ElementAt(mIndex++), aResult);
|
||||
} else {
|
||||
aResult = mCArray->ElementAt(mIndex++);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline nsresult
|
||||
StringEnumeratorTail(T** aResult)
|
||||
{
|
||||
if (!*aResult) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// constructors
|
||||
//
|
||||
|
||||
nsresult
|
||||
NS_NewStringEnumerator(nsIStringEnumerator** aResult,
|
||||
const nsTArray<nsString>* aArray, nsISupports* aOwner)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aResult = new nsStringEnumerator(aArray, aOwner);
|
||||
return StringEnumeratorTail(aResult);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult,
|
||||
const nsTArray<nsCString>* aArray,
|
||||
nsISupports* aOwner)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aResult = new nsStringEnumerator(aArray, aOwner);
|
||||
return StringEnumeratorTail(aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult,
|
||||
nsTArray<nsString>* aArray)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aResult = new nsStringEnumerator(aArray, true);
|
||||
return StringEnumeratorTail(aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult,
|
||||
nsTArray<nsCString>* aArray)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aResult = new nsStringEnumerator(aArray, true);
|
||||
return StringEnumeratorTail(aResult);
|
||||
}
|
||||
|
||||
// const ones internally just forward to the non-const equivalents
|
||||
nsresult
|
||||
NS_NewStringEnumerator(nsIStringEnumerator** aResult,
|
||||
const nsTArray<nsString>* aArray)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aResult = new nsStringEnumerator(aArray, false);
|
||||
return StringEnumeratorTail(aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult,
|
||||
const nsTArray<nsCString>* aArray)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aResult = new nsStringEnumerator(aArray, false);
|
||||
return StringEnumeratorTail(aResult);
|
||||
}
|
||||
|
||||
91
xpcom/ds/nsStringEnumerator.h
Normal file
91
xpcom/ds/nsStringEnumerator.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsIStringEnumerator.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
|
||||
// nsIStringEnumerator/nsIUTF8StringEnumerator implementations
|
||||
//
|
||||
// Currently all implementations support both interfaces. The
|
||||
// constructors below provide the most common interface for the given
|
||||
// type (i.e. nsIStringEnumerator for char16_t* strings, and so
|
||||
// forth) but any resulting enumerators can be queried to the other
|
||||
// type. Internally, the enumerators will hold onto the type that was
|
||||
// passed in and do conversion if GetNext() for the other type of
|
||||
// string is called.
|
||||
|
||||
// There are a few different types of enumerators:
|
||||
|
||||
//
|
||||
// These enumerators hold a pointer to the array. Be careful
|
||||
// because modifying the array may confuse the iterator, especially if
|
||||
// you insert or remove elements in the middle of the array.
|
||||
//
|
||||
|
||||
// The non-adopting enumerator requires that the array sticks around
|
||||
// at least as long as the enumerator does. These are for constant
|
||||
// string arrays that the enumerator does not own, this could be used
|
||||
// in VERY specialized cases such as when the provider KNOWS that the
|
||||
// string enumerator will be consumed immediately, or will at least
|
||||
// outlast the array.
|
||||
// For example:
|
||||
//
|
||||
// nsTArray<nsCString> array;
|
||||
// array.AppendCString("abc");
|
||||
// array.AppendCString("def");
|
||||
// NS_NewStringEnumerator(&enumerator, &array, true);
|
||||
//
|
||||
// // call some internal method which iterates the enumerator
|
||||
// InternalMethod(enumerator);
|
||||
// NS_RELEASE(enumerator);
|
||||
//
|
||||
MOZ_MUST_USE nsresult
|
||||
NS_NewStringEnumerator(nsIStringEnumerator** aResult,
|
||||
const nsTArray<nsString>* aArray,
|
||||
nsISupports* aOwner);
|
||||
MOZ_MUST_USE nsresult
|
||||
NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult,
|
||||
const nsTArray<nsCString>* aArray);
|
||||
|
||||
MOZ_MUST_USE nsresult
|
||||
NS_NewStringEnumerator(nsIStringEnumerator** aResult,
|
||||
const nsTArray<nsString>* aArray);
|
||||
|
||||
// Adopting string enumerators assume ownership of the array and will
|
||||
// call |operator delete| on the array when the enumerator is destroyed
|
||||
// this is useful when the provider creates an array solely for the
|
||||
// purpose of creating the enumerator.
|
||||
// For example:
|
||||
//
|
||||
// nsTArray<nsCString>* array = new nsTArray<nsCString>;
|
||||
// array->AppendString("abcd");
|
||||
// NS_NewAdoptingStringEnumerator(&result, array);
|
||||
MOZ_MUST_USE nsresult
|
||||
NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult,
|
||||
nsTArray<nsString>* aArray);
|
||||
|
||||
MOZ_MUST_USE nsresult
|
||||
NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult,
|
||||
nsTArray<nsCString>* aArray);
|
||||
|
||||
|
||||
// these versions take a refcounted "owner" which will be addreffed
|
||||
// when the enumerator is created, and destroyed when the enumerator
|
||||
// is released. This allows providers to give non-owning pointers to
|
||||
// ns*StringArray member variables without worrying about lifetime
|
||||
// issues
|
||||
// For example:
|
||||
//
|
||||
// nsresult MyClass::Enumerate(nsIUTF8StringEnumerator** aResult) {
|
||||
// mCategoryList->AppendString("abcd");
|
||||
// return NS_NewStringEnumerator(aResult, mCategoryList, this);
|
||||
// }
|
||||
//
|
||||
MOZ_MUST_USE nsresult
|
||||
NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult,
|
||||
const nsTArray<nsCString>* aArray,
|
||||
nsISupports* aOwner);
|
||||
264
xpcom/ds/nsSupportsArray.cpp
Normal file
264
xpcom/ds/nsSupportsArray.cpp
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsSupportsArray.h"
|
||||
#include "nsSupportsArrayEnumerator.h"
|
||||
|
||||
// Disable deprecation warnings generated by nsISupportsArray and associated
|
||||
// classes.
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4996)
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsQueryElementAt::operator()(const nsIID& aIID, void** aResult) const
|
||||
{
|
||||
nsresult status =
|
||||
mCollection ? mCollection->QueryElementAt(mIndex, aIID, aResult) :
|
||||
NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (mErrorPtr) {
|
||||
*mErrorPtr = status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
nsSupportsArray::nsSupportsArray()
|
||||
{
|
||||
}
|
||||
|
||||
nsSupportsArray::~nsSupportsArray()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSupportsArray::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
{
|
||||
if (aOuter) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupportsArray> it = new nsSupportsArray();
|
||||
|
||||
return it->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsArray, nsIArray, nsISupportsArray, nsICollection,
|
||||
nsISerializable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Read(nsIObjectInputStream* aStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
uint32_t newArraySize;
|
||||
rv = aStream->Read32(&newArraySize);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t count;
|
||||
rv = aStream->Read32(&count);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ASSERTION(count <= newArraySize, "overlarge mCount!");
|
||||
if (count > newArraySize) {
|
||||
count = newArraySize;
|
||||
}
|
||||
|
||||
// Don't clear out our array until we know we have enough space for the new
|
||||
// one and have successfully copied everything out of the stream.
|
||||
nsCOMArray<nsISupports> tmp;
|
||||
tmp.SetCapacity(newArraySize);
|
||||
tmp.SetCount(count);
|
||||
|
||||
auto elems = tmp.Elements();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
rv = aStream->ReadObject(true, &elems[i]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Now clear out existing refs and replace with the new array.
|
||||
mArray.Clear();
|
||||
mArray.SwapElements(tmp);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aStream->Write32(mArray.Capacity());
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = aStream->Write32(mArray.Length());
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mArray.Length(); i++) {
|
||||
rv = aStream->WriteObject(mArray[i], true);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::GetElementAt(uint32_t aIndex, nsISupports** aOutPtr)
|
||||
{
|
||||
nsCOMPtr<nsISupports> elm = mArray.SafeElementAt(aIndex);
|
||||
elm.forget(aOutPtr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(int32_t)
|
||||
nsSupportsArray::IndexOf(const nsISupports* aPossibleElement)
|
||||
{
|
||||
// nsCOMArray takes a non-const param, but it just passes through to
|
||||
// nsTArray which takes a const param.
|
||||
return mArray.IndexOf(const_cast<nsISupports*>(aPossibleElement));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
nsSupportsArray::InsertElementAt(nsISupports* aElement, uint32_t aIndex)
|
||||
{
|
||||
return mArray.InsertObjectAt(aElement, aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
nsSupportsArray::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex)
|
||||
{
|
||||
// nsCOMArray::ReplaceObjectAt will grow the array if necessary. Instead
|
||||
// we do the bounds check and only replace if it's in range.
|
||||
if (aIndex < mArray.Length()) {
|
||||
mArray.ReplaceElementAt(aIndex, aElement);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
nsSupportsArray::RemoveElementAt(uint32_t aIndex)
|
||||
{
|
||||
return mArray.RemoveObjectAt(aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::RemoveElement(nsISupports* aElement)
|
||||
{
|
||||
return mArray.RemoveObject(aElement) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Clear(void)
|
||||
{
|
||||
mArray.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::DeprecatedEnumerate(nsIEnumerator** aResult)
|
||||
{
|
||||
RefPtr<nsSupportsArrayEnumerator> e = new nsSupportsArrayEnumerator(this);
|
||||
e.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Clone(nsISupportsArray** aResult)
|
||||
{
|
||||
nsCOMPtr<nsISupportsArray> newArray;
|
||||
nsresult rv = NS_NewISupportsArray(getter_AddRefs(newArray));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mArray.Length(); i++) {
|
||||
// AppendElement does an odd cast of bool to nsresult, we just cast back
|
||||
// here.
|
||||
if (!(bool)newArray->AppendElement(mArray[i])) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
newArray.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult)
|
||||
{
|
||||
nsresult rv;
|
||||
rv = nsSupportsArray::Create(nullptr, NS_GET_IID(nsISupportsArray),
|
||||
(void**)aInstancePtrResult);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* nsIArray adapters.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::GetLength(uint32_t* aLength) {
|
||||
return Count(aLength);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::QueryElementAt(uint32_t aIndex, const nsIID& aIID, void** aResult)
|
||||
{
|
||||
nsISupports* element = mArray.SafeElementAt(aIndex);
|
||||
if (element) {
|
||||
return element->QueryInterface(aIID, aResult);
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::IndexOf(uint32_t aStartIndex, nsISupports* aElement, uint32_t* aResult)
|
||||
{
|
||||
int32_t idx = mArray.IndexOf(aElement, aStartIndex);
|
||||
if (idx < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aResult = static_cast<uint32_t>(idx);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Enumerate(nsISimpleEnumerator** aResult)
|
||||
{
|
||||
return NS_NewArrayEnumerator(aResult, this);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
107
xpcom/ds/nsSupportsArray.h
Normal file
107
xpcom/ds/nsSupportsArray.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsSupportsArray_h__
|
||||
#define nsSupportsArray_h__
|
||||
|
||||
#include "nsIArray.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
|
||||
// Disable deprecation warnings generated by nsISupportsArray and associated
|
||||
// classes.
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4996)
|
||||
#endif
|
||||
|
||||
#include "nsISupportsArray.h"
|
||||
|
||||
class nsSupportsArray final : public nsISupportsArray,
|
||||
public nsIArray
|
||||
{
|
||||
~nsSupportsArray(void); // nonvirtual since we're not subclassed
|
||||
|
||||
public:
|
||||
nsSupportsArray(void);
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
|
||||
// nsICollection methods:
|
||||
NS_IMETHOD Count(uint32_t* aResult) override
|
||||
{
|
||||
*aResult = mArray.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD GetElementAt(uint32_t aIndex, nsISupports** aResult) override;
|
||||
MOZ_MUST_USE NS_IMETHOD
|
||||
SetElementAt(uint32_t aIndex, nsISupports* aValue) override
|
||||
{
|
||||
return ReplaceElementAt(aValue, aIndex) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
MOZ_MUST_USE NS_IMETHOD AppendElement(nsISupports* aElement) override
|
||||
{
|
||||
// XXX Invalid cast of bool to nsresult (bug 778110)
|
||||
return (nsresult)InsertElementAt(aElement, mArray.Length())/* ? NS_OK : NS_ERROR_FAILURE*/;
|
||||
}
|
||||
// XXX this is badly named - should be RemoveFirstElement
|
||||
MOZ_MUST_USE NS_IMETHOD RemoveElement(nsISupports* aElement) override;
|
||||
NS_IMETHOD DeprecatedEnumerate(nsIEnumerator** aResult) override;
|
||||
NS_IMETHOD Clear(void) override;
|
||||
|
||||
// nsISupportsArray methods:
|
||||
NS_IMETHOD_(int32_t) IndexOf(const nsISupports* aPossibleElement) override;
|
||||
|
||||
NS_IMETHOD GetIndexOf(nsISupports* aPossibleElement, int32_t* aResult) override
|
||||
{
|
||||
*aResult = IndexOf(aPossibleElement);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE NS_IMETHOD_(bool)
|
||||
InsertElementAt(nsISupports* aElement, uint32_t aIndex) override;
|
||||
|
||||
MOZ_MUST_USE NS_IMETHOD_(bool)
|
||||
ReplaceElementAt(nsISupports* aElement, uint32_t aIndex) override;
|
||||
|
||||
MOZ_MUST_USE NS_IMETHOD_(bool)
|
||||
RemoveElementAt(uint32_t aIndex) override;
|
||||
|
||||
MOZ_MUST_USE NS_IMETHOD DeleteElementAt(uint32_t aIndex) override
|
||||
{
|
||||
return (RemoveElementAt(aIndex) ? NS_OK : NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE NS_IMETHOD Clone(nsISupportsArray** aResult) override;
|
||||
|
||||
/**
|
||||
* nsIArray adapters.
|
||||
*/
|
||||
NS_DECL_NSIARRAY
|
||||
|
||||
private:
|
||||
// Copy constructors are not allowed
|
||||
explicit nsSupportsArray(const nsISupportsArray& aOther);
|
||||
|
||||
nsCOMArray<nsISupports> mArray;
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // nsSupportsArray_h__
|
||||
131
xpcom/ds/nsSupportsArrayEnumerator.cpp
Normal file
131
xpcom/ds/nsSupportsArrayEnumerator.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsSupportsArrayEnumerator.h"
|
||||
|
||||
// Disable deprecation warnings generated by nsISupportsArray and associated
|
||||
// classes.
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4996)
|
||||
#endif
|
||||
|
||||
#include "nsISupportsArray.h"
|
||||
|
||||
nsSupportsArrayEnumerator::nsSupportsArrayEnumerator(nsISupportsArray* array)
|
||||
: mArray(array)
|
||||
, mCursor(0)
|
||||
{
|
||||
NS_ASSERTION(array, "null array");
|
||||
}
|
||||
|
||||
nsSupportsArrayEnumerator::~nsSupportsArrayEnumerator()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsArrayEnumerator, nsIBidirectionalEnumerator,
|
||||
nsIEnumerator)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::First()
|
||||
{
|
||||
mCursor = 0;
|
||||
uint32_t cnt;
|
||||
nsresult rv = mArray->Count(&cnt);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
int32_t end = (int32_t)cnt;
|
||||
if (mCursor < end) {
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::Next()
|
||||
{
|
||||
uint32_t cnt;
|
||||
nsresult rv = mArray->Count(&cnt);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
int32_t end = (int32_t)cnt;
|
||||
if (mCursor < end) { // don't count upward forever
|
||||
mCursor++;
|
||||
}
|
||||
if (mCursor < end) {
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::CurrentItem(nsISupports** aItem)
|
||||
{
|
||||
NS_ASSERTION(aItem, "null out parameter");
|
||||
uint32_t cnt;
|
||||
nsresult rv = mArray->Count(&cnt);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (mCursor >= 0 && mCursor < (int32_t)cnt) {
|
||||
return mArray->GetElementAt(mCursor, aItem);
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::IsDone()
|
||||
{
|
||||
uint32_t cnt;
|
||||
nsresult rv = mArray->Count(&cnt);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
// XXX This is completely incompatible with the meaning of nsresult.
|
||||
// NS_ENUMERATOR_FALSE is defined to be 1. (bug 778111)
|
||||
return (mCursor >= 0 && mCursor < (int32_t)cnt)
|
||||
? (nsresult)NS_ENUMERATOR_FALSE : NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::Last()
|
||||
{
|
||||
uint32_t cnt;
|
||||
nsresult rv = mArray->Count(&cnt);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
mCursor = cnt - 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::Prev()
|
||||
{
|
||||
if (mCursor >= 0) {
|
||||
--mCursor;
|
||||
}
|
||||
if (mCursor >= 0) {
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
56
xpcom/ds/nsSupportsArrayEnumerator.h
Normal file
56
xpcom/ds/nsSupportsArrayEnumerator.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsSupportsArrayEnumerator_h___
|
||||
#define nsSupportsArrayEnumerator_h___
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// Disable deprecation warnings generated by nsISupportsArray and associated
|
||||
// classes.
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4996)
|
||||
#endif
|
||||
|
||||
#include "nsIEnumerator.h"
|
||||
|
||||
class nsISupportsArray;
|
||||
|
||||
class nsSupportsArrayEnumerator final : public nsIBidirectionalEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit nsSupportsArrayEnumerator(nsISupportsArray* aArray);
|
||||
|
||||
// nsIEnumerator methods:
|
||||
NS_DECL_NSIENUMERATOR
|
||||
|
||||
// nsIBidirectionalEnumerator methods:
|
||||
NS_DECL_NSIBIDIRECTIONALENUMERATOR
|
||||
|
||||
private:
|
||||
~nsSupportsArrayEnumerator();
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsISupportsArray> mArray;
|
||||
int32_t mCursor;
|
||||
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // __nsSupportsArrayEnumerator_h
|
||||
|
||||
849
xpcom/ds/nsSupportsPrimitives.cpp
Normal file
849
xpcom/ds/nsSupportsPrimitives.cpp
Normal file
|
|
@ -0,0 +1,849 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "nsSupportsPrimitives.h"
|
||||
#include "nsMemory.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include <algorithm>
|
||||
|
||||
template<typename T>
|
||||
static char*
|
||||
DataToString(const char* aFormat, T aData)
|
||||
{
|
||||
static const int size = 32;
|
||||
char buf[size];
|
||||
|
||||
int len = SprintfLiteral(buf, aFormat, aData);
|
||||
MOZ_ASSERT(len >= 0);
|
||||
|
||||
return static_cast<char*>(nsMemory::Clone(buf, std::min(len + 1, size) *
|
||||
sizeof(char)));
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsID, nsISupportsID, nsISupportsPrimitive)
|
||||
|
||||
nsSupportsID::nsSupportsID()
|
||||
: mData(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsID::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_ID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsID::GetData(nsID** aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
|
||||
if (mData) {
|
||||
*aData = static_cast<nsID*>(nsMemory::Clone(mData, sizeof(nsID)));
|
||||
} else {
|
||||
*aData = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsID::SetData(const nsID* aData)
|
||||
{
|
||||
if (mData) {
|
||||
free(mData);
|
||||
}
|
||||
|
||||
if (aData) {
|
||||
mData = static_cast<nsID*>(nsMemory::Clone(aData, sizeof(nsID)));
|
||||
} else {
|
||||
mData = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsID::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
|
||||
if (mData) {
|
||||
*aResult = mData->ToString();
|
||||
} else {
|
||||
static const char nullStr[] = "null";
|
||||
*aResult = static_cast<char*>(nsMemory::Clone(nullStr, sizeof(nullStr)));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* nsSupportsCString
|
||||
*****************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsCString, nsISupportsCString,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsCString::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_CSTRING;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsCString::GetData(nsACString& aData)
|
||||
{
|
||||
aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsCString::ToString(char** aResult)
|
||||
{
|
||||
*aResult = ToNewCString(mData);
|
||||
if (!*aResult) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsCString::SetData(const nsACString& aData)
|
||||
{
|
||||
bool ok = mData.Assign(aData, mozilla::fallible);
|
||||
if (!ok) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* nsSupportsString
|
||||
*****************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsString, nsISupportsString,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsString::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_STRING;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsString::GetData(nsAString& aData)
|
||||
{
|
||||
aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsString::ToString(char16_t** aResult)
|
||||
{
|
||||
*aResult = ToNewUnicode(mData);
|
||||
if (!*aResult) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsString::SetData(const nsAString& aData)
|
||||
{
|
||||
bool ok = mData.Assign(aData, mozilla::fallible);
|
||||
if (!ok) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRBool, nsISupportsPRBool,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRBool::nsSupportsPRBool()
|
||||
: mData(false)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRBool::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRBOOL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRBool::GetData(bool* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRBool::SetData(bool aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRBool::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
const char* str = mData ? "true" : "false";
|
||||
*aResult = static_cast<char*>(nsMemory::Clone(str, (strlen(str) + 1) *
|
||||
sizeof(char)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRUint8, nsISupportsPRUint8,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRUint8::nsSupportsPRUint8()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint8::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRUINT8;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint8::GetData(uint8_t* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint8::SetData(uint8_t aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint8::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%u", static_cast<unsigned int>(mData));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRUint16, nsISupportsPRUint16,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRUint16::nsSupportsPRUint16()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint16::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRUINT16;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint16::GetData(uint16_t* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint16::SetData(uint16_t aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint16::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%u", static_cast<unsigned int>(mData));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRUint32, nsISupportsPRUint32,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRUint32::nsSupportsPRUint32()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint32::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRUINT32;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint32::GetData(uint32_t* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint32::SetData(uint32_t aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint32::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%u", mData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRUint64, nsISupportsPRUint64,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRUint64::nsSupportsPRUint64()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint64::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRUINT64;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint64::GetData(uint64_t* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint64::SetData(uint64_t aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRUint64::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%llu", mData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRTime, nsISupportsPRTime,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRTime::nsSupportsPRTime()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRTime::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRTIME;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRTime::GetData(PRTime* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRTime::SetData(PRTime aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRTime::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%" PRIu64, mData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsChar, nsISupportsChar,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsChar::nsSupportsChar()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsChar::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_CHAR;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsChar::GetData(char* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsChar::SetData(char aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsChar::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = static_cast<char*>(moz_xmalloc(2 * sizeof(char)));
|
||||
*aResult[0] = mData;
|
||||
*aResult[1] = '\0';
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRInt16, nsISupportsPRInt16,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRInt16::nsSupportsPRInt16()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt16::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRINT16;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt16::GetData(int16_t* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt16::SetData(int16_t aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt16::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%d", static_cast<int>(mData));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRInt32, nsISupportsPRInt32,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRInt32::nsSupportsPRInt32()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt32::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRINT32;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt32::GetData(int32_t* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt32::SetData(int32_t aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt32::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%d", mData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsPRInt64, nsISupportsPRInt64,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsPRInt64::nsSupportsPRInt64()
|
||||
: mData(0)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt64::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_PRINT64;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt64::GetData(int64_t* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt64::SetData(int64_t aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsPRInt64::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%" PRId64, mData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsFloat, nsISupportsFloat,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsFloat::nsSupportsFloat()
|
||||
: mData(float(0.0))
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsFloat::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_FLOAT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsFloat::GetData(float* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsFloat::SetData(float aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsFloat::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%f", static_cast<double>(mData));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsDouble, nsISupportsDouble,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsDouble::nsSupportsDouble()
|
||||
: mData(double(0.0))
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsDouble::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_DOUBLE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsDouble::GetData(double* aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsDouble::SetData(double aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsDouble::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
*aResult = DataToString("%f", mData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsVoid, nsISupportsVoid,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsVoid::nsSupportsVoid()
|
||||
: mData(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsVoid::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_VOID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsVoid::GetData(void** aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsVoid::SetData(void* aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsVoid::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
static const char str[] = "[raw data]";
|
||||
*aResult = static_cast<char*>(nsMemory::Clone(str, sizeof(str)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsInterfacePointer,
|
||||
nsISupportsInterfacePointer,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsInterfacePointer::nsSupportsInterfacePointer()
|
||||
: mIID(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
nsSupportsInterfacePointer::~nsSupportsInterfacePointer()
|
||||
{
|
||||
if (mIID) {
|
||||
free(mIID);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsInterfacePointer::GetType(uint16_t* aType)
|
||||
{
|
||||
NS_ASSERTION(aType, "Bad pointer");
|
||||
*aType = TYPE_INTERFACE_POINTER;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsInterfacePointer::GetData(nsISupports** aData)
|
||||
{
|
||||
NS_ASSERTION(aData, "Bad pointer");
|
||||
*aData = mData;
|
||||
NS_IF_ADDREF(*aData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsInterfacePointer::SetData(nsISupports* aData)
|
||||
{
|
||||
mData = aData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsInterfacePointer::GetDataIID(nsID** aIID)
|
||||
{
|
||||
NS_ASSERTION(aIID, "Bad pointer");
|
||||
|
||||
if (mIID) {
|
||||
*aIID = static_cast<nsID*>(nsMemory::Clone(mIID, sizeof(nsID)));
|
||||
} else {
|
||||
*aIID = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsInterfacePointer::SetDataIID(const nsID* aIID)
|
||||
{
|
||||
if (mIID) {
|
||||
free(mIID);
|
||||
}
|
||||
|
||||
if (aIID) {
|
||||
mIID = static_cast<nsID*>(nsMemory::Clone(aIID, sizeof(nsID)));
|
||||
} else {
|
||||
mIID = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsInterfacePointer::ToString(char** aResult)
|
||||
{
|
||||
NS_ASSERTION(aResult, "Bad pointer");
|
||||
|
||||
static const char str[] = "[interface pointer]";
|
||||
// jband sez: think about asking nsIInterfaceInfoManager whether
|
||||
// the interface has a known human-readable name
|
||||
*aResult = static_cast<char*>(nsMemory::Clone(str, sizeof(str)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsDependentCString, nsISupportsCString,
|
||||
nsISupportsPrimitive)
|
||||
|
||||
nsSupportsDependentCString::nsSupportsDependentCString(const char* aStr)
|
||||
: mData(aStr)
|
||||
{ }
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsDependentCString::GetType(uint16_t* aType)
|
||||
{
|
||||
if (NS_WARN_IF(!aType)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aType = TYPE_CSTRING;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsDependentCString::GetData(nsACString& aData)
|
||||
{
|
||||
aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsDependentCString::ToString(char** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!aResult)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aResult = ToNewCString(mData);
|
||||
if (!*aResult) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsDependentCString::SetData(const nsACString& aData)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
327
xpcom/ds/nsSupportsPrimitives.h
Normal file
327
xpcom/ds/nsSupportsPrimitives.h
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsSupportsPrimitives_h__
|
||||
#define nsSupportsPrimitives_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsSupportsID final : public nsISupportsID
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSID
|
||||
|
||||
nsSupportsID();
|
||||
|
||||
private:
|
||||
~nsSupportsID() {}
|
||||
|
||||
nsID* mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsCString final : public nsISupportsCString
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSCSTRING
|
||||
|
||||
nsSupportsCString() {}
|
||||
|
||||
private:
|
||||
~nsSupportsCString() {}
|
||||
|
||||
nsCString mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsString final : public nsISupportsString
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSSTRING
|
||||
|
||||
nsSupportsString() {}
|
||||
|
||||
private:
|
||||
~nsSupportsString() {}
|
||||
|
||||
nsString mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRBool final : public nsISupportsPRBool
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRBOOL
|
||||
|
||||
nsSupportsPRBool();
|
||||
|
||||
private:
|
||||
~nsSupportsPRBool() {}
|
||||
|
||||
bool mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRUint8 final : public nsISupportsPRUint8
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRUINT8
|
||||
|
||||
nsSupportsPRUint8();
|
||||
|
||||
private:
|
||||
~nsSupportsPRUint8() {}
|
||||
|
||||
uint8_t mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRUint16 final : public nsISupportsPRUint16
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRUINT16
|
||||
|
||||
nsSupportsPRUint16();
|
||||
|
||||
private:
|
||||
~nsSupportsPRUint16() {}
|
||||
|
||||
uint16_t mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRUint32 final : public nsISupportsPRUint32
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRUINT32
|
||||
|
||||
nsSupportsPRUint32();
|
||||
|
||||
private:
|
||||
~nsSupportsPRUint32() {}
|
||||
|
||||
uint32_t mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRUint64 final : public nsISupportsPRUint64
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRUINT64
|
||||
|
||||
nsSupportsPRUint64();
|
||||
|
||||
private:
|
||||
~nsSupportsPRUint64() {}
|
||||
|
||||
uint64_t mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRTime final : public nsISupportsPRTime
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRTIME
|
||||
|
||||
nsSupportsPRTime();
|
||||
|
||||
private:
|
||||
~nsSupportsPRTime() {}
|
||||
|
||||
PRTime mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsChar final : public nsISupportsChar
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSCHAR
|
||||
|
||||
nsSupportsChar();
|
||||
|
||||
private:
|
||||
~nsSupportsChar() {}
|
||||
|
||||
char mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRInt16 final : public nsISupportsPRInt16
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRINT16
|
||||
|
||||
nsSupportsPRInt16();
|
||||
|
||||
private:
|
||||
~nsSupportsPRInt16() {}
|
||||
|
||||
int16_t mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRInt32 final : public nsISupportsPRInt32
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRINT32
|
||||
|
||||
nsSupportsPRInt32();
|
||||
|
||||
private:
|
||||
~nsSupportsPRInt32() {}
|
||||
|
||||
int32_t mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsPRInt64 final : public nsISupportsPRInt64
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSPRINT64
|
||||
|
||||
nsSupportsPRInt64();
|
||||
|
||||
private:
|
||||
~nsSupportsPRInt64() {}
|
||||
|
||||
int64_t mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsFloat final : public nsISupportsFloat
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSFLOAT
|
||||
|
||||
nsSupportsFloat();
|
||||
|
||||
private:
|
||||
~nsSupportsFloat() {}
|
||||
|
||||
float mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsDouble final : public nsISupportsDouble
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSDOUBLE
|
||||
|
||||
nsSupportsDouble();
|
||||
|
||||
private:
|
||||
~nsSupportsDouble() {}
|
||||
|
||||
double mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsVoid final : public nsISupportsVoid
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSVOID
|
||||
|
||||
nsSupportsVoid();
|
||||
|
||||
private:
|
||||
~nsSupportsVoid() {}
|
||||
|
||||
void* mData;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
class nsSupportsInterfacePointer final : public nsISupportsInterfacePointer
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSINTERFACEPOINTER
|
||||
|
||||
nsSupportsInterfacePointer();
|
||||
|
||||
private:
|
||||
~nsSupportsInterfacePointer();
|
||||
|
||||
nsCOMPtr<nsISupports> mData;
|
||||
nsID* mIID;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/**
|
||||
* Wraps a static const char* buffer for use with nsISupportsCString
|
||||
*
|
||||
* Only use this class with static buffers, or arena-allocated buffers of
|
||||
* permanent lifetime!
|
||||
*/
|
||||
class nsSupportsDependentCString final : public nsISupportsCString
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSCSTRING
|
||||
|
||||
explicit nsSupportsDependentCString(const char* aStr);
|
||||
|
||||
private:
|
||||
~nsSupportsDependentCString() {}
|
||||
|
||||
nsDependentCString mData;
|
||||
};
|
||||
|
||||
#endif /* nsSupportsPrimitives_h__ */
|
||||
2220
xpcom/ds/nsVariant.cpp
Normal file
2220
xpcom/ds/nsVariant.cpp
Normal file
File diff suppressed because it is too large
Load diff
229
xpcom/ds/nsVariant.h
Normal file
229
xpcom/ds/nsVariant.h
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsVariant_h
|
||||
#define nsVariant_h
|
||||
|
||||
#include "nsIVariant.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
/**
|
||||
* Map the nsAUTF8String, nsUTF8String classes to the nsACString and
|
||||
* nsCString classes respectively for now. These defines need to be removed
|
||||
* once Jag lands his nsUTF8String implementation.
|
||||
*/
|
||||
#define nsAUTF8String nsACString
|
||||
#define nsUTF8String nsCString
|
||||
#define PromiseFlatUTF8String PromiseFlatCString
|
||||
|
||||
/**
|
||||
* nsDiscriminatedUnion is a class that nsIVariant implementors can use
|
||||
* to hold the underlying data.
|
||||
*/
|
||||
|
||||
class nsDiscriminatedUnion
|
||||
{
|
||||
public:
|
||||
|
||||
nsDiscriminatedUnion() : mType(nsIDataType::VTYPE_EMPTY) {}
|
||||
nsDiscriminatedUnion(const nsDiscriminatedUnion&) = delete;
|
||||
nsDiscriminatedUnion(nsDiscriminatedUnion&&) = delete;
|
||||
|
||||
~nsDiscriminatedUnion() { Cleanup(); }
|
||||
|
||||
nsDiscriminatedUnion& operator=(const nsDiscriminatedUnion&) = delete;
|
||||
nsDiscriminatedUnion& operator=(nsDiscriminatedUnion&&) = delete;
|
||||
|
||||
void Cleanup();
|
||||
|
||||
uint16_t GetType() const { return mType; }
|
||||
|
||||
MOZ_MUST_USE nsresult ConvertToInt8(uint8_t* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToInt16(int16_t* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToInt32(int32_t* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToInt64(int64_t* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToUint8(uint8_t* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToUint16(uint16_t* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToUint32(uint32_t* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToUint64(uint64_t* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToFloat(float* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToDouble(double* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToBool(bool* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToChar(char* aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToWChar(char16_t* aResult) const;
|
||||
|
||||
MOZ_MUST_USE nsresult ConvertToID(nsID* aResult) const;
|
||||
|
||||
MOZ_MUST_USE nsresult ConvertToAString(nsAString& aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToAUTF8String(nsAUTF8String& aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToACString(nsACString& aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToString(char** aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToWString(char16_t** aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToStringWithSize(uint32_t* aSize, char** aStr) const;
|
||||
MOZ_MUST_USE nsresult ConvertToWStringWithSize(uint32_t* aSize, char16_t** aStr) const;
|
||||
|
||||
MOZ_MUST_USE nsresult ConvertToISupports(nsISupports** aResult) const;
|
||||
MOZ_MUST_USE nsresult ConvertToInterface(nsIID** aIID, void** aInterface) const;
|
||||
MOZ_MUST_USE nsresult ConvertToArray(uint16_t* aType, nsIID* aIID,
|
||||
uint32_t* aCount, void** aPtr) const;
|
||||
|
||||
MOZ_MUST_USE nsresult SetFromVariant(nsIVariant* aValue);
|
||||
|
||||
void SetFromInt8(uint8_t aValue);
|
||||
void SetFromInt16(int16_t aValue);
|
||||
void SetFromInt32(int32_t aValue);
|
||||
void SetFromInt64(int64_t aValue);
|
||||
void SetFromUint8(uint8_t aValue);
|
||||
void SetFromUint16(uint16_t aValue);
|
||||
void SetFromUint32(uint32_t aValue);
|
||||
void SetFromUint64(uint64_t aValue);
|
||||
void SetFromFloat(float aValue);
|
||||
void SetFromDouble(double aValue);
|
||||
void SetFromBool(bool aValue);
|
||||
void SetFromChar(char aValue);
|
||||
void SetFromWChar(char16_t aValue);
|
||||
void SetFromID(const nsID& aValue);
|
||||
void SetFromAString(const nsAString& aValue);
|
||||
void SetFromDOMString(const nsAString& aValue);
|
||||
void SetFromAUTF8String(const nsAUTF8String& aValue);
|
||||
void SetFromACString(const nsACString& aValue);
|
||||
MOZ_MUST_USE nsresult SetFromString(const char* aValue);
|
||||
MOZ_MUST_USE nsresult SetFromWString(const char16_t* aValue);
|
||||
void SetFromISupports(nsISupports* aValue);
|
||||
void SetFromInterface(const nsIID& aIID, nsISupports* aValue);
|
||||
MOZ_MUST_USE nsresult SetFromArray(uint16_t aType, const nsIID* aIID,
|
||||
uint32_t aCount, void* aValue);
|
||||
MOZ_MUST_USE nsresult SetFromStringWithSize(uint32_t aSize,
|
||||
const char* aValue);
|
||||
MOZ_MUST_USE nsresult SetFromWStringWithSize(uint32_t aSize,
|
||||
const char16_t* aValue);
|
||||
|
||||
// Like SetFromWStringWithSize, but leaves the string uninitialized. It does
|
||||
// does write the null-terminator.
|
||||
void AllocateWStringWithSize(uint32_t aSize);
|
||||
|
||||
void SetToVoid();
|
||||
void SetToEmpty();
|
||||
void SetToEmptyArray();
|
||||
|
||||
void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
|
||||
|
||||
private:
|
||||
MOZ_MUST_USE nsresult
|
||||
ToManageableNumber(nsDiscriminatedUnion* aOutData) const;
|
||||
void FreeArray();
|
||||
MOZ_MUST_USE bool String2ID(nsID* aPid) const;
|
||||
MOZ_MUST_USE nsresult ToString(nsACString& aOutString) const;
|
||||
|
||||
public:
|
||||
union
|
||||
{
|
||||
int8_t mInt8Value;
|
||||
int16_t mInt16Value;
|
||||
int32_t mInt32Value;
|
||||
int64_t mInt64Value;
|
||||
uint8_t mUint8Value;
|
||||
uint16_t mUint16Value;
|
||||
uint32_t mUint32Value;
|
||||
uint64_t mUint64Value;
|
||||
float mFloatValue;
|
||||
double mDoubleValue;
|
||||
bool mBoolValue;
|
||||
char mCharValue;
|
||||
char16_t mWCharValue;
|
||||
nsIID mIDValue;
|
||||
nsAString* mAStringValue;
|
||||
nsAUTF8String* mUTF8StringValue;
|
||||
nsACString* mCStringValue;
|
||||
struct
|
||||
{
|
||||
// This is an owning reference that cannot be an nsCOMPtr because
|
||||
// nsDiscriminatedUnion needs to be POD. AddRef/Release are manually
|
||||
// called on this.
|
||||
nsISupports* MOZ_OWNING_REF mInterfaceValue;
|
||||
nsIID mInterfaceID;
|
||||
} iface;
|
||||
struct
|
||||
{
|
||||
nsIID mArrayInterfaceID;
|
||||
void* mArrayValue;
|
||||
uint32_t mArrayCount;
|
||||
uint16_t mArrayType;
|
||||
} array;
|
||||
struct
|
||||
{
|
||||
char* mStringValue;
|
||||
uint32_t mStringLength;
|
||||
} str;
|
||||
struct
|
||||
{
|
||||
char16_t* mWStringValue;
|
||||
uint32_t mWStringLength;
|
||||
} wstr;
|
||||
} u;
|
||||
uint16_t mType;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsVariant implements the generic variant support. The xpcom module registers
|
||||
* a factory (see NS_VARIANT_CONTRACTID in nsIVariant.idl) that will create
|
||||
* these objects. They are created 'empty' and 'writable'.
|
||||
*
|
||||
* nsIVariant users won't usually need to see this class.
|
||||
*/
|
||||
class nsVariantBase : public nsIWritableVariant
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIVARIANT
|
||||
NS_DECL_NSIWRITABLEVARIANT
|
||||
|
||||
nsVariantBase();
|
||||
|
||||
protected:
|
||||
~nsVariantBase() {};
|
||||
|
||||
nsDiscriminatedUnion mData;
|
||||
bool mWritable;
|
||||
};
|
||||
|
||||
class nsVariant final : public nsVariantBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsVariant() {};
|
||||
|
||||
private:
|
||||
~nsVariant() {};
|
||||
};
|
||||
|
||||
class nsVariantCC final : public nsVariantBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsVariantCC)
|
||||
|
||||
nsVariantCC() {};
|
||||
|
||||
private:
|
||||
~nsVariantCC() {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Users of nsIVariant should be using the contractID and not this CID.
|
||||
* - see NS_VARIANT_CONTRACTID in nsIVariant.idl.
|
||||
*/
|
||||
|
||||
#define NS_VARIANT_CID \
|
||||
{ /* 0D6EA1D0-879C-11d5-90EF-0010A4E73D9A */ \
|
||||
0xd6ea1d0, \
|
||||
0x879c, \
|
||||
0x11d5, \
|
||||
{0x90, 0xef, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a}}
|
||||
|
||||
#endif // nsVariant_h
|
||||
110
xpcom/ds/nsWhitespaceTokenizer.h
Normal file
110
xpcom/ds/nsWhitespaceTokenizer.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __nsWhitespaceTokenizer_h
|
||||
#define __nsWhitespaceTokenizer_h
|
||||
|
||||
#include "mozilla/RangedPtr.h"
|
||||
#include "nsDependentSubstring.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
template<typename DependentSubstringType, bool IsWhitespace(char16_t)>
|
||||
class nsTWhitespaceTokenizer
|
||||
{
|
||||
typedef typename DependentSubstringType::char_type CharType;
|
||||
typedef typename DependentSubstringType::substring_type SubstringType;
|
||||
|
||||
public:
|
||||
explicit nsTWhitespaceTokenizer(const SubstringType& aSource)
|
||||
: mIter(aSource.Data(), aSource.Length())
|
||||
, mEnd(aSource.Data() + aSource.Length(), aSource.Data(),
|
||||
aSource.Length())
|
||||
, mWhitespaceBeforeFirstToken(false)
|
||||
, mWhitespaceAfterCurrentToken(false)
|
||||
{
|
||||
while (mIter < mEnd && IsWhitespace(*mIter)) {
|
||||
mWhitespaceBeforeFirstToken = true;
|
||||
++mIter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any more tokens are available.
|
||||
*/
|
||||
bool hasMoreTokens() const
|
||||
{
|
||||
return mIter < mEnd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if there is whitespace prior to the first token.
|
||||
*/
|
||||
bool whitespaceBeforeFirstToken() const
|
||||
{
|
||||
return mWhitespaceBeforeFirstToken;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if there is any whitespace after the current token.
|
||||
* This is always true unless we're reading the last token.
|
||||
*/
|
||||
bool whitespaceAfterCurrentToken() const
|
||||
{
|
||||
return mWhitespaceAfterCurrentToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next token.
|
||||
*/
|
||||
const DependentSubstringType nextToken()
|
||||
{
|
||||
const mozilla::RangedPtr<const CharType> tokenStart = mIter;
|
||||
while (mIter < mEnd && !IsWhitespace(*mIter)) {
|
||||
++mIter;
|
||||
}
|
||||
const mozilla::RangedPtr<const CharType> tokenEnd = mIter;
|
||||
mWhitespaceAfterCurrentToken = false;
|
||||
while (mIter < mEnd && IsWhitespace(*mIter)) {
|
||||
mWhitespaceAfterCurrentToken = true;
|
||||
++mIter;
|
||||
}
|
||||
return Substring(tokenStart.get(), tokenEnd.get());
|
||||
}
|
||||
|
||||
private:
|
||||
mozilla::RangedPtr<const CharType> mIter;
|
||||
const mozilla::RangedPtr<const CharType> mEnd;
|
||||
bool mWhitespaceBeforeFirstToken;
|
||||
bool mWhitespaceAfterCurrentToken;
|
||||
};
|
||||
|
||||
template<bool IsWhitespace(char16_t) = NS_IsAsciiWhitespace>
|
||||
class nsWhitespaceTokenizerTemplate
|
||||
: public nsTWhitespaceTokenizer<nsDependentSubstring, IsWhitespace>
|
||||
{
|
||||
public:
|
||||
explicit nsWhitespaceTokenizerTemplate(const nsSubstring& aSource)
|
||||
: nsTWhitespaceTokenizer<nsDependentSubstring, IsWhitespace>(aSource)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef nsWhitespaceTokenizerTemplate<> nsWhitespaceTokenizer;
|
||||
|
||||
template<bool IsWhitespace(char16_t) = NS_IsAsciiWhitespace>
|
||||
class nsCWhitespaceTokenizerTemplate
|
||||
: public nsTWhitespaceTokenizer<nsDependentCSubstring, IsWhitespace>
|
||||
{
|
||||
public:
|
||||
explicit nsCWhitespaceTokenizerTemplate(const nsCSubstring& aSource)
|
||||
: nsTWhitespaceTokenizer<nsDependentCSubstring, IsWhitespace>(aSource)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef nsCWhitespaceTokenizerTemplate<> nsCWhitespaceTokenizer;
|
||||
|
||||
#endif /* __nsWhitespaceTokenizer_h */
|
||||
579
xpcom/ds/nsWindowsRegKey.cpp
Normal file
579
xpcom/ds/nsWindowsRegKey.cpp
Normal file
|
|
@ -0,0 +1,579 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
#include <stdlib.h>
|
||||
#include "nsWindowsRegKey.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// According to MSDN, the following limits apply (in characters excluding room
|
||||
// for terminating null character):
|
||||
#define MAX_KEY_NAME_LEN 255
|
||||
#define MAX_VALUE_NAME_LEN 16383
|
||||
|
||||
class nsWindowsRegKey final : public nsIWindowsRegKey
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIWINDOWSREGKEY
|
||||
|
||||
nsWindowsRegKey()
|
||||
: mKey(nullptr)
|
||||
, mWatchEvent(nullptr)
|
||||
, mWatchRecursive(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
~nsWindowsRegKey()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
HKEY mKey;
|
||||
HANDLE mWatchEvent;
|
||||
BOOL mWatchRecursive;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsWindowsRegKey, nsIWindowsRegKey)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::GetKey(HKEY* aKey)
|
||||
{
|
||||
*aKey = mKey;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::SetKey(HKEY aKey)
|
||||
{
|
||||
// We do not close the older aKey!
|
||||
StopWatching();
|
||||
|
||||
mKey = aKey;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::Close()
|
||||
{
|
||||
StopWatching();
|
||||
|
||||
if (mKey) {
|
||||
RegCloseKey(mKey);
|
||||
mKey = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::Open(uint32_t aRootKey, const nsAString& aPath,
|
||||
uint32_t aMode)
|
||||
{
|
||||
Close();
|
||||
|
||||
LONG rv = RegOpenKeyExW((HKEY)(intptr_t)aRootKey,
|
||||
PromiseFlatString(aPath).get(), 0, (REGSAM)aMode,
|
||||
&mKey);
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::Create(uint32_t aRootKey, const nsAString& aPath,
|
||||
uint32_t aMode)
|
||||
{
|
||||
Close();
|
||||
|
||||
DWORD disposition;
|
||||
LONG rv = RegCreateKeyExW((HKEY)(intptr_t)aRootKey,
|
||||
PromiseFlatString(aPath).get(), 0, nullptr,
|
||||
REG_OPTION_NON_VOLATILE, (REGSAM)aMode, nullptr,
|
||||
&mKey, &disposition);
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::OpenChild(const nsAString& aPath, uint32_t aMode,
|
||||
nsIWindowsRegKey** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWindowsRegKey> child = new nsWindowsRegKey();
|
||||
|
||||
nsresult rv = child->Open((uintptr_t)mKey, aPath, aMode);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
child.swap(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::CreateChild(const nsAString& aPath, uint32_t aMode,
|
||||
nsIWindowsRegKey** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWindowsRegKey> child = new nsWindowsRegKey();
|
||||
|
||||
nsresult rv = child->Create((uintptr_t)mKey, aPath, aMode);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
child.swap(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::GetChildCount(uint32_t* aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
DWORD numSubKeys;
|
||||
LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, &numSubKeys,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
if (rv != ERROR_SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aResult = numSubKeys;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::GetChildName(uint32_t aIndex, nsAString& aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
FILETIME lastWritten;
|
||||
|
||||
wchar_t nameBuf[MAX_KEY_NAME_LEN + 1];
|
||||
DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]);
|
||||
|
||||
LONG rv = RegEnumKeyExW(mKey, aIndex, nameBuf, &nameLen, nullptr, nullptr,
|
||||
nullptr, &lastWritten);
|
||||
if (rv != ERROR_SUCCESS) {
|
||||
return NS_ERROR_NOT_AVAILABLE; // XXX what's the best error code here?
|
||||
}
|
||||
|
||||
aResult.Assign(nameBuf, nameLen);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::HasChild(const nsAString& aName, bool* aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Check for the existence of a child key by opening the key with minimal
|
||||
// rights. Perhaps there is a more efficient way to do this?
|
||||
|
||||
HKEY key;
|
||||
LONG rv = RegOpenKeyExW(mKey, PromiseFlatString(aName).get(), 0,
|
||||
STANDARD_RIGHTS_READ, &key);
|
||||
|
||||
if ((*aResult = (rv == ERROR_SUCCESS && key))) {
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::GetValueCount(uint32_t* aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
DWORD numValues;
|
||||
LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &numValues, nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
if (rv != ERROR_SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aResult = numValues;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::GetValueName(uint32_t aIndex, nsAString& aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
wchar_t nameBuf[MAX_VALUE_NAME_LEN];
|
||||
DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]);
|
||||
|
||||
LONG rv = RegEnumValueW(mKey, aIndex, nameBuf, &nameLen, nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
if (rv != ERROR_SUCCESS) {
|
||||
return NS_ERROR_NOT_AVAILABLE; // XXX what's the best error code here?
|
||||
}
|
||||
|
||||
aResult.Assign(nameBuf, nameLen);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::HasValue(const nsAString& aName, bool* aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LONG rv = RegQueryValueExW(mKey, PromiseFlatString(aName).get(), 0, nullptr,
|
||||
nullptr, nullptr);
|
||||
|
||||
*aResult = (rv == ERROR_SUCCESS);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::RemoveChild(const nsAString& aName)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LONG rv = RegDeleteKeyW(mKey, PromiseFlatString(aName).get());
|
||||
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::RemoveValue(const nsAString& aName)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LONG rv = RegDeleteValueW(mKey, PromiseFlatString(aName).get());
|
||||
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::GetValueType(const nsAString& aName, uint32_t* aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LONG rv = RegQueryValueExW(mKey, PromiseFlatString(aName).get(), 0,
|
||||
(LPDWORD)aResult, nullptr, nullptr);
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::ReadStringValue(const nsAString& aName, nsAString& aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
DWORD type, size;
|
||||
|
||||
const nsString& flatName = PromiseFlatString(aName);
|
||||
|
||||
LONG rv = RegQueryValueExW(mKey, flatName.get(), 0, &type, nullptr, &size);
|
||||
if (rv != ERROR_SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// This must be a string type in order to fetch the value as a string.
|
||||
// We're being a bit forgiving here by allowing types other than REG_SZ.
|
||||
if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// The buffer size must be a multiple of 2.
|
||||
if (size % 2 != 0) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
aResult.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// |size| may or may not include the terminating null character.
|
||||
DWORD resultLen = size / 2;
|
||||
|
||||
if (!aResult.SetLength(resultLen, mozilla::fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAString::iterator begin;
|
||||
aResult.BeginWriting(begin);
|
||||
|
||||
rv = RegQueryValueExW(mKey, flatName.get(), 0, &type, (LPBYTE)begin.get(),
|
||||
&size);
|
||||
|
||||
if (!aResult.CharAt(resultLen - 1)) {
|
||||
// The string passed to us had a null terminator in the final position.
|
||||
aResult.Truncate(resultLen - 1);
|
||||
}
|
||||
|
||||
// Expand the environment variables if needed
|
||||
if (type == REG_EXPAND_SZ) {
|
||||
const nsString& flatSource = PromiseFlatString(aResult);
|
||||
resultLen = ExpandEnvironmentStringsW(flatSource.get(), nullptr, 0);
|
||||
if (resultLen > 1) {
|
||||
nsAutoString expandedResult;
|
||||
// |resultLen| includes the terminating null character
|
||||
--resultLen;
|
||||
if (!expandedResult.SetLength(resultLen, mozilla::fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAString::iterator begin;
|
||||
expandedResult.BeginWriting(begin);
|
||||
|
||||
resultLen = ExpandEnvironmentStringsW(flatSource.get(),
|
||||
wwc(begin.get()),
|
||||
resultLen + 1);
|
||||
if (resultLen <= 0) {
|
||||
rv = ERROR_UNKNOWN_FEATURE;
|
||||
aResult.Truncate();
|
||||
} else {
|
||||
rv = ERROR_SUCCESS;
|
||||
aResult = expandedResult;
|
||||
}
|
||||
} else if (resultLen == 1) {
|
||||
// It apparently expands to nothing (just a null terminator).
|
||||
aResult.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::ReadIntValue(const nsAString& aName, uint32_t* aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
DWORD size = sizeof(*aResult);
|
||||
LONG rv = RegQueryValueExW(mKey, PromiseFlatString(aName).get(), 0, nullptr,
|
||||
(LPBYTE)aResult, &size);
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::ReadInt64Value(const nsAString& aName, uint64_t* aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
DWORD size = sizeof(*aResult);
|
||||
LONG rv = RegQueryValueExW(mKey, PromiseFlatString(aName).get(), 0, nullptr,
|
||||
(LPBYTE)aResult, &size);
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::ReadBinaryValue(const nsAString& aName, nsACString& aResult)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
DWORD size;
|
||||
LONG rv = RegQueryValueExW(mKey, PromiseFlatString(aName).get(), 0,
|
||||
nullptr, nullptr, &size);
|
||||
|
||||
if (rv != ERROR_SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
aResult.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aResult.SetLength(size, mozilla::fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsACString::iterator begin;
|
||||
aResult.BeginWriting(begin);
|
||||
|
||||
rv = RegQueryValueExW(mKey, PromiseFlatString(aName).get(), 0, nullptr,
|
||||
(LPBYTE)begin.get(), &size);
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::WriteStringValue(const nsAString& aName,
|
||||
const nsAString& aValue)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Need to indicate complete size of buffer including null terminator.
|
||||
const nsString& flatValue = PromiseFlatString(aValue);
|
||||
|
||||
LONG rv = RegSetValueExW(mKey, PromiseFlatString(aName).get(), 0, REG_SZ,
|
||||
(const BYTE*)flatValue.get(),
|
||||
(flatValue.Length() + 1) * sizeof(char16_t));
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::WriteIntValue(const nsAString& aName, uint32_t aValue)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LONG rv = RegSetValueExW(mKey, PromiseFlatString(aName).get(), 0, REG_DWORD,
|
||||
(const BYTE*)&aValue, sizeof(aValue));
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::WriteInt64Value(const nsAString& aName, uint64_t aValue)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LONG rv = RegSetValueExW(mKey, PromiseFlatString(aName).get(), 0, REG_QWORD,
|
||||
(const BYTE*)&aValue, sizeof(aValue));
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::WriteBinaryValue(const nsAString& aName,
|
||||
const nsACString& aValue)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
const nsCString& flatValue = PromiseFlatCString(aValue);
|
||||
LONG rv = RegSetValueExW(mKey, PromiseFlatString(aName).get(), 0, REG_BINARY,
|
||||
(const BYTE*)flatValue.get(), flatValue.Length());
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::StartWatching(bool aRecurse)
|
||||
{
|
||||
if (NS_WARN_IF(!mKey)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (mWatchEvent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mWatchEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!mWatchEvent) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
DWORD filter = REG_NOTIFY_CHANGE_NAME |
|
||||
REG_NOTIFY_CHANGE_ATTRIBUTES |
|
||||
REG_NOTIFY_CHANGE_LAST_SET |
|
||||
REG_NOTIFY_CHANGE_SECURITY;
|
||||
|
||||
LONG rv = RegNotifyChangeKeyValue(mKey, aRecurse, filter, mWatchEvent, TRUE);
|
||||
if (rv != ERROR_SUCCESS) {
|
||||
StopWatching();
|
||||
// On older versions of Windows, this call is not implemented, so simply
|
||||
// return NS_OK in those cases and pretend that the watching is happening.
|
||||
return (rv == ERROR_CALL_NOT_IMPLEMENTED) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mWatchRecursive = aRecurse;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::StopWatching()
|
||||
{
|
||||
if (mWatchEvent) {
|
||||
CloseHandle(mWatchEvent);
|
||||
mWatchEvent = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::HasChanged(bool* aResult)
|
||||
{
|
||||
if (mWatchEvent && WaitForSingleObject(mWatchEvent, 0) == WAIT_OBJECT_0) {
|
||||
// An event only gets signaled once, then it's done, so we have to set up
|
||||
// another event to watch.
|
||||
StopWatching();
|
||||
StartWatching(mWatchRecursive);
|
||||
*aResult = true;
|
||||
} else {
|
||||
*aResult = false;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsRegKey::IsWatching(bool* aResult)
|
||||
{
|
||||
*aResult = (mWatchEvent != nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
NS_NewWindowsRegKey(nsIWindowsRegKey** aResult)
|
||||
{
|
||||
RefPtr<nsWindowsRegKey> key = new nsWindowsRegKey();
|
||||
key.forget(aResult);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
nsWindowsRegKeyConstructor(nsISupports* aDelegate, const nsIID& aIID,
|
||||
void** aResult)
|
||||
{
|
||||
if (aDelegate) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWindowsRegKey> key;
|
||||
NS_NewWindowsRegKey(getter_AddRefs(key));
|
||||
return key->QueryInterface(aIID, aResult);
|
||||
}
|
||||
43
xpcom/ds/nsWindowsRegKey.h
Normal file
43
xpcom/ds/nsWindowsRegKey.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsWindowsRegKey_h__
|
||||
#define nsWindowsRegKey_h__
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "nsIWindowsRegKey.h"
|
||||
|
||||
/**
|
||||
* This ContractID may be used to instantiate a windows registry key object
|
||||
* via the XPCOM component manager.
|
||||
*/
|
||||
#define NS_WINDOWSREGKEY_CONTRACTID "@mozilla.org/windows-registry-key;1"
|
||||
|
||||
/**
|
||||
* This function may be used to instantiate a windows registry key object prior
|
||||
* to XPCOM being initialized.
|
||||
*/
|
||||
extern "C" void NS_NewWindowsRegKey(nsIWindowsRegKey** aResult);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef IMPL_LIBXUL
|
||||
|
||||
// a53bc624-d577-4839-b8ec-bb5040a52ff4
|
||||
#define NS_WINDOWSREGKEY_CID \
|
||||
{ 0xa53bc624, 0xd577, 0x4839, \
|
||||
{ 0xb8, 0xec, 0xbb, 0x50, 0x40, 0xa5, 0x2f, 0xf4 } }
|
||||
|
||||
extern MOZ_MUST_USE nsresult nsWindowsRegKeyConstructor(nsISupports* aOuter,
|
||||
const nsIID& aIID,
|
||||
void** aResult);
|
||||
|
||||
#endif // IMPL_LIBXUL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // nsWindowsRegKey_h__
|
||||
Loading…
Add table
Add a link
Reference in a new issue