gecko-dev/xpcom/ds/nsINIParserImpl.cpp
Dave Townsend 204fe23163 Bug 1484844: Make nsINIParser mutable. r=froydnj
In order to implement profile-per-install we need a mutable INI parser in early
startup. The current one is implemented in JavaScript and thus not available.
This makes the current read-only C++ INI parser mutable and removes the
JavaScript implementation.

It turns out that the two different implementations of nsIINIParserFactory and
nsIINIParser behaved slightly differently but only in ways that the single test
cared about so I've adjusted things a little to make it work.

The existing C++ implementation did not do validity checks on arguments, this
adds that making empty sections and values illegal.

Differential Revision: https://phabricator.services.mozilla.com/D3851

--HG--
rename : xpcom/tests/unit/test_iniProcessor.js => xpcom/tests/unit/test_iniParser.js
extra : source : 524941c8ed0e048ee51be1bd11082b41428ef490
extra : amend_source : 2de6cef5be97448a41733bedda29d6af34aed27a
2017-10-12 14:20:57 -07:00

182 lines
4.3 KiB
C++

/* -*- 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
, public nsIINIParserWriter
{
~nsINIParserImpl() {}
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIINIPARSER
NS_DECL_NSIINIPARSERWRITER
nsresult Init(nsIFile* aINIFile) { return mParser.Init(aINIFile); }
private:
nsINIParser mParser;
bool ContainsNull(const nsACString& aStr);
};
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;
}
if (aINIFile) {
nsresult rv = p->Init(aINIFile);
if (NS_FAILED(rv)) {
return rv;
}
}
p.forget(aResult);
return NS_OK;
}
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,
nsIINIParserWriter)
bool
nsINIParserImpl::ContainsNull(const nsACString& aStr) {
return aStr.CountChar('\0') > 0;
}
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)
{
if (ContainsNull(aSection)) {
return NS_ERROR_INVALID_ARG;
}
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)
{
if (ContainsNull(aSection) || ContainsNull(aKey)) {
return NS_ERROR_INVALID_ARG;
}
return mParser.GetString(PromiseFlatCString(aSection).get(),
PromiseFlatCString(aKey).get(),
aResult);
}
NS_IMETHODIMP
nsINIParserImpl::SetString(const nsACString& aSection,
const nsACString& aKey,
const nsACString& aValue)
{
if (ContainsNull(aSection) || ContainsNull(aKey) || ContainsNull(aValue)) {
return NS_ERROR_INVALID_ARG;
}
return mParser.SetString(PromiseFlatCString(aSection).get(),
PromiseFlatCString(aKey).get(),
PromiseFlatCString(aValue).get());
}
NS_IMETHODIMP
nsINIParserImpl::WriteFile(nsIFile* aINIFile)
{
return mParser.WriteToFile(aINIFile);
}