bug 116149: simple name-value pair DB

r=yokoyama@netscape.com, sr=brendan@mozilla.org
This commit is contained in:
bstell%ix.netcom.com 2002-02-16 08:11:25 +00:00
Родитель 0839760747
Коммит b3e9de2a76
4 изменённых файлов: 1096 добавлений и 0 удалений

Просмотреть файл

@ -41,6 +41,7 @@ EXPORTS = \
nsPoint.h \
nsSize.h \
nsMargin.h \
nsNameValuePairDB.h \
nsTransform2D.h \
nsIRenderingContext.h \
nsRenderingContextImpl.h \

Просмотреть файл

@ -93,6 +93,7 @@ CPPSRCS = \
nsDeviceContext.cpp \
nsFont.cpp \
nsFontList.cpp \
nsNameValuePairDB.cpp \
nsRenderingContextImpl.cpp \
nsRect.cpp \
nsTransform2D.cpp \

Просмотреть файл

@ -0,0 +1,547 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Stell <bstell@ix.netcom.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nspr.h"
#include "nsCOMPtr.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsIFileSpec.h"
#include "nsNameValuePairDB.h"
#include "nsLocalFileUnix.h"
#define NVPDB_VERSION_MAJOR 1
#define NVPDB_VERSION_MINOR 0
#define NVPDB_VERSION_MAINTENANCE 0
#ifdef DEBUG
# define NVPDB_PRINTF(x) \
PR_BEGIN_MACRO \
printf x ; \
printf(", %s %d\n", __FILE__, __LINE__); \
PR_END_MACRO
#else
# define NVPDB_PRINTF(x)
#endif
PRBool
nsNameValuePairDB::CheckHeader()
{
const char *name, *value;
int num, major, minor, maintenance;
PRBool foundVersion = PR_FALSE;
if (!mFile)
return PR_FALSE;
if (fseek(mFile, 0L, SEEK_SET) != 0)
return PR_FALSE;
mCurrentGroup = 0;
mAtEndOfGroup = PR_FALSE;
while (GetNextElement(&name, &value) > 0) {
if (*name == '\0') // ignore comments
continue;
if (strcmp(name, "Version")==0) {
foundVersion = PR_TRUE;
num = sscanf(value, "%d.%d.%d", &major, &minor, &maintenance);
if (num != 3) {
NVPDB_PRINTF(("failed to parse version number (%s)", value));
return PR_FALSE;
}
// NVPDB_VERSION_MAJOR
// It is presumed that major versions are not backwards compatibile.
if (major != NVPDB_VERSION_MAJOR) {
NVPDB_PRINTF(("version major %d != %d", major, NVPDB_VERSION_MAJOR));
return PR_FALSE;
}
// NVPDB_VERSION_MINOR
// It is presumed that minor versions are backwards compatible
// but will have additional features.
// Put any tests related to minor versions here.
// NVPDB_VERSION_MAINTENANCE
// It is presumed that maintenance versions are backwards compatible,
// have no new features, but can have bug fixes.
// Put any tests related to maintenance versions here.
mMajorNum = major;
mMinorNum = minor;
mMaintenanceNum = maintenance;
}
}
return foundVersion;
}
//
// Re-get an element. Used if the element is bigger than
// the buffer that was first passed in
//
// PRInt32 GetCurrentElement(const char** aName, const char** aValue,
// char *aBuffer, PRUint32 aBufferLen);
//
// to implement this the GetNextElement methods need to save
// the file position so this routine can seek backward to it.
//
PRInt32
nsNameValuePairDB::GetNextElement(const char** aName, const char** aValue)
{
return GetNextElement(aName, aValue, mBuf, sizeof(mBuf));
}
//
// Get the next element
//
// returns 1 if complete element read
// return 0 on end of file
// returns a negative number on error
// if error < -NVPDB_MIN_BUFLEN
// then the value is the negative of the needed buffer len
//
//
PRInt32
nsNameValuePairDB::GetNextElement(const char** aName, const char** aValue,
char *aBuffer, PRUint32 aBufferLen)
{
char *line, *name, *value;
unsigned int num;
int len;
unsigned int groupNum;
*aName = "";
*aValue = "";
if (aBufferLen < NVPDB_MIN_BUFLEN) {
return NVPDB_BUFFER_TOO_SMALL;
}
if (mAtEndOfGroup) {
return NVPDB_END_OF_GROUP;
}
//
// Get a line
//
line = fgets(aBuffer, aBufferLen, mFile);
if (!line) {
if (feof(mFile)) { // end of file
mAtEndOfGroup = PR_TRUE;
mAtEndOfCatalog = PR_TRUE;
return NVPDB_END_OF_FILE;
}
return NVPDB_FILE_IO_ERROR;
}
//
// Check we got a complete line
//
len = strlen(line);
NS_ASSERTION(len!=0, "an empty string is invalid");
if (len == 0)
return NVPDB_GARBLED_LINE;
if (line[len-1] != '\n') {
len++; // space for the line terminator
while (1) {
int val = getc(mFile);
if (val == EOF)
return -len;
len++;
if (val == '\n')
return -len;
}
}
len--;
line[len] = '\0';
//NVPDB_PRINTF(("line = (%s)", line));
//
// Check the group number
//
num = sscanf(line, "%u", &groupNum);
if ((num != 1) || (groupNum != (unsigned)mCurrentGroup))
return NVPDB_END_OF_GROUP;
//
// Get the name
//
name = strchr(line, ' ');
if ((!name) || (name[1]=='\0'))
return NVPDB_GARBLED_LINE;
name++;
//
// If it is a comment
// return a blank name (strlen(*aName)==0)
// return the comment in the value field
//
if (*name == '#') {
*aValue = name;
return 1;
}
//
// Get the value
//
value = strchr(name, '=');
if (!value)
return NVPDB_GARBLED_LINE;
*value = '\0';
value++;
//
// Check for end of group
//
if (strcmp(name,"end")==0) {
mAtEndOfGroup = PR_TRUE;
return NVPDB_END_OF_GROUP;
}
//
// Got the name and value
//
*aName = name;
*aValue = value;
return 1;
}
PRBool
nsNameValuePairDB::GetNextGroup(const char** aType)
{
return GetNextGroup(aType, nsnull, 0);
}
PRBool
nsNameValuePairDB::GetNextGroup(const char** aType, const char* aName)
{
return GetNextGroup(aType, aName, strlen(aName));
}
PRBool
nsNameValuePairDB::GetNextGroup(const char** aType, const char* aName, int aLen)
{
const char *name, *value;
long pos = 0;
*aType = "";
if (mAtEndOfCatalog)
return PR_FALSE;
//
// Move to end of current Group
//
while (GetNextElement(&name, &value) > 0)
continue;
mCurrentGroup++;
mAtEndOfGroup = PR_FALSE;
// save current pos in case this in not the desired type
// and we need to backup
if (aName)
pos = ftell(mFile);
// check if there are more Groups
if (GetNextElement(&name, &value) <= 0) {
mAtEndOfGroup = PR_TRUE;
mAtEndOfCatalog = PR_TRUE;
return PR_FALSE;
}
if (strcmp(name,"begin"))
goto GetNext_Error;
// check if this is the desired type
if (aName) {
if (strncmp(value,aName,aLen)) {
fseek(mFile, pos, SEEK_SET);
mCurrentGroup--;
mAtEndOfGroup = PR_TRUE;
return PR_FALSE;
}
}
*aType = value;
return PR_TRUE;
GetNext_Error:
mError = PR_TRUE;
NVPDB_PRINTF(("GetNext_Error"));
return PR_FALSE;
}
nsNameValuePairDB::nsNameValuePairDB()
{
mFile = nsnull;
mBuf[0] = '\0';
mMajorNum = 0;
mMinorNum = 0;
mMaintenanceNum = 0;
mCurrentGroup = 0;
mAtEndOfGroup = PR_FALSE;
mAtEndOfCatalog = PR_FALSE;
mError = PR_FALSE;
}
nsNameValuePairDB::~nsNameValuePairDB()
{
if (mFile) {
fclose(mFile);
mFile = nsnull;
}
}
PRBool
nsNameValuePairDB::OpenForRead(const nsACString & aCatalogName)
{
nsresult result;
nsCOMPtr<nsILocalFile> local_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID,
&result);
if (NS_FAILED(result))
goto error_return;
local_file->InitWithPath(PromiseFlatCString(aCatalogName).get());
local_file->OpenANSIFileDesc("r", &mFile);
if (mFile && CheckHeader())
return PR_TRUE;
error_return:
mError = PR_TRUE;
NVPDB_PRINTF(("OpenForRead error"));
return PR_FALSE;
}
PRBool
nsNameValuePairDB::OpenTmpForWrite(const nsACString& aCatalogName)
{
nsCAutoString name(aCatalogName);
name.Append(".tmp");
nsresult result;
nsCOMPtr<nsILocalFile> local_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID,
&result);
if (NS_FAILED(result))
return PR_FALSE;
local_file->InitWithPath(name.get());
local_file->OpenANSIFileDesc("w+", &mFile);
if (mFile == nsnull)
return PR_FALSE;
// Write the header
mAtEndOfGroup = PR_TRUE;
mCurrentGroup = -1;
PutStartGroup("Header");
char buf[64];
PutElement("", "########################################");
PutElement("", "# #");
PutElement("", "# Name Value Pair DB #");
PutElement("", "# #");
PutElement("", "# This is a program generated file #");
PutElement("", "# #");
PutElement("", "# Do not edit #");
PutElement("", "# #");
PutElement("", "########################################");
PR_snprintf(buf, sizeof(buf), "%d.%d.%d", NVPDB_VERSION_MAJOR,
NVPDB_VERSION_MINOR, NVPDB_VERSION_MAINTENANCE);
PutElement("Version", buf);
PutEndGroup("Header");
return PR_TRUE;
}
PRBool
nsNameValuePairDB::PutElement(const char* aName, const char* aValue)
{
if (mAtEndOfGroup) {
mError = PR_TRUE;
NVPDB_PRINTF(("PutElement_Error"));
return PR_FALSE;
}
if ((!*aName) && (*aValue == '#'))
fprintf(mFile, "%u %s\n", mCurrentGroup, aValue);
else
fprintf(mFile, "%u %s=%s\n", mCurrentGroup, aName, aValue);
#ifdef DEBUG
fflush(mFile);
#endif
return PR_TRUE;
}
PRBool
nsNameValuePairDB::PutEndGroup(const char* aType)
{
if (mAtEndOfGroup) {
mError = PR_TRUE;
NVPDB_PRINTF(("PutEndGroup_Error"));
return PR_FALSE;
}
mAtEndOfGroup = PR_TRUE;
fprintf(mFile, "%u end=%s\n", mCurrentGroup, aType);
#ifdef DEBUG
fflush(mFile);
#endif
return PR_TRUE;
}
PRBool
nsNameValuePairDB::PutStartGroup(const char* aType)
{
if (!mAtEndOfGroup) {
mError = PR_TRUE;
NVPDB_PRINTF(("PutStartGroup_Error"));
#ifdef DEBUG
fflush(mFile);
#endif
return PR_FALSE;
}
mAtEndOfGroup = PR_FALSE;
mCurrentGroup++;
fprintf(mFile, "%u begin=%s\n", mCurrentGroup, aType);
#ifdef DEBUG
fflush(mFile);
#endif
return PR_TRUE;
}
PRBool
nsNameValuePairDB::RenameTmp(const char* aCatalogName)
{
nsresult rv;
nsCOMPtr<nsILocalFile> dir;
PRBool exists = PR_FALSE;
nsCAutoString old_name(aCatalogName);
nsDependentCString current_name(aCatalogName);
nsCAutoString tmp_name(aCatalogName);
nsCAutoString old_name_tail;
nsCAutoString current_name_tail;
nsCOMPtr<nsILocalFile> old_file;
nsCOMPtr<nsILocalFile> current_file;
nsCOMPtr<nsILocalFile> tmp_file;
nsCAutoString parent_dir;
nsXPIDLCString parent_path;
nsXPIDLCString cur_path;
//
// Split the parent dir and file name
//
PRInt32 slash = 0, last_slash = -1;
nsCAutoString fontDirName(aCatalogName);
// RFindChar not coded so do it by hand
while ((slash=fontDirName.FindChar('/', slash))>=0) {
last_slash = slash;
slash++;
}
if (last_slash < 0)
goto Rename_Error;
fontDirName.Left(parent_dir, last_slash);
dir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
goto Rename_Error;
dir->InitWithPath(parent_dir.get());
dir->GetPath(getter_Copies(parent_path));
if (!mAtEndOfGroup || mError)
goto Rename_Error;
//
// check that we have a tmp copy
//
tmp_name.Append(".tmp");
tmp_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
goto Rename_Error;
tmp_file->InitWithPath(tmp_name.get());
tmp_file->Exists(&exists);
if (!exists)
goto Rename_Error;
//
// get rid of any old copy
//
old_name.Append(".old");
old_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
goto Rename_Error;
old_file->InitWithPath(old_name.get());
//
// Check we have a current copy
//
current_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
goto Rename_Error;
current_file->InitWithPath(current_name.get());
current_file->Exists(&exists);
if (exists) {
//
// Rename the current copy to old
//
current_file->GetPath(getter_Copies(cur_path));
old_name.Right(old_name_tail, old_name.Length() - last_slash - 1);
rv = current_file->MoveTo(dir, old_name_tail.get());
if (NS_FAILED(rv))
goto Rename_Error;
}
//
// Rename the tmp to current
//
current_name.Right(current_name_tail, current_name.Length() - last_slash - 1);
rv = tmp_file->MoveTo(dir, current_name_tail.get());
if (NS_FAILED(rv))
goto Rename_Error;
//
// remove the previous copy
//
if (exists) {
old_file->Remove(PR_FALSE);
}
return PR_TRUE;
Rename_Error:
mError = PR_TRUE;
NVPDB_PRINTF(("Rename_Error"));
return PR_FALSE;
}

Просмотреть файл

@ -0,0 +1,547 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Stell <bstell@ix.netcom.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nspr.h"
#include "nsCOMPtr.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsIFileSpec.h"
#include "nsNameValuePairDB.h"
#include "nsLocalFileUnix.h"
#define NVPDB_VERSION_MAJOR 1
#define NVPDB_VERSION_MINOR 0
#define NVPDB_VERSION_MAINTENANCE 0
#ifdef DEBUG
# define NVPDB_PRINTF(x) \
PR_BEGIN_MACRO \
printf x ; \
printf(", %s %d\n", __FILE__, __LINE__); \
PR_END_MACRO
#else
# define NVPDB_PRINTF(x)
#endif
PRBool
nsNameValuePairDB::CheckHeader()
{
const char *name, *value;
int num, major, minor, maintenance;
PRBool foundVersion = PR_FALSE;
if (!mFile)
return PR_FALSE;
if (fseek(mFile, 0L, SEEK_SET) != 0)
return PR_FALSE;
mCurrentGroup = 0;
mAtEndOfGroup = PR_FALSE;
while (GetNextElement(&name, &value) > 0) {
if (*name == '\0') // ignore comments
continue;
if (strcmp(name, "Version")==0) {
foundVersion = PR_TRUE;
num = sscanf(value, "%d.%d.%d", &major, &minor, &maintenance);
if (num != 3) {
NVPDB_PRINTF(("failed to parse version number (%s)", value));
return PR_FALSE;
}
// NVPDB_VERSION_MAJOR
// It is presumed that major versions are not backwards compatibile.
if (major != NVPDB_VERSION_MAJOR) {
NVPDB_PRINTF(("version major %d != %d", major, NVPDB_VERSION_MAJOR));
return PR_FALSE;
}
// NVPDB_VERSION_MINOR
// It is presumed that minor versions are backwards compatible
// but will have additional features.
// Put any tests related to minor versions here.
// NVPDB_VERSION_MAINTENANCE
// It is presumed that maintenance versions are backwards compatible,
// have no new features, but can have bug fixes.
// Put any tests related to maintenance versions here.
mMajorNum = major;
mMinorNum = minor;
mMaintenanceNum = maintenance;
}
}
return foundVersion;
}
//
// Re-get an element. Used if the element is bigger than
// the buffer that was first passed in
//
// PRInt32 GetCurrentElement(const char** aName, const char** aValue,
// char *aBuffer, PRUint32 aBufferLen);
//
// to implement this the GetNextElement methods need to save
// the file position so this routine can seek backward to it.
//
PRInt32
nsNameValuePairDB::GetNextElement(const char** aName, const char** aValue)
{
return GetNextElement(aName, aValue, mBuf, sizeof(mBuf));
}
//
// Get the next element
//
// returns 1 if complete element read
// return 0 on end of file
// returns a negative number on error
// if error < -NVPDB_MIN_BUFLEN
// then the value is the negative of the needed buffer len
//
//
PRInt32
nsNameValuePairDB::GetNextElement(const char** aName, const char** aValue,
char *aBuffer, PRUint32 aBufferLen)
{
char *line, *name, *value;
unsigned int num;
int len;
unsigned int groupNum;
*aName = "";
*aValue = "";
if (aBufferLen < NVPDB_MIN_BUFLEN) {
return NVPDB_BUFFER_TOO_SMALL;
}
if (mAtEndOfGroup) {
return NVPDB_END_OF_GROUP;
}
//
// Get a line
//
line = fgets(aBuffer, aBufferLen, mFile);
if (!line) {
if (feof(mFile)) { // end of file
mAtEndOfGroup = PR_TRUE;
mAtEndOfCatalog = PR_TRUE;
return NVPDB_END_OF_FILE;
}
return NVPDB_FILE_IO_ERROR;
}
//
// Check we got a complete line
//
len = strlen(line);
NS_ASSERTION(len!=0, "an empty string is invalid");
if (len == 0)
return NVPDB_GARBLED_LINE;
if (line[len-1] != '\n') {
len++; // space for the line terminator
while (1) {
int val = getc(mFile);
if (val == EOF)
return -len;
len++;
if (val == '\n')
return -len;
}
}
len--;
line[len] = '\0';
//NVPDB_PRINTF(("line = (%s)", line));
//
// Check the group number
//
num = sscanf(line, "%u", &groupNum);
if ((num != 1) || (groupNum != (unsigned)mCurrentGroup))
return NVPDB_END_OF_GROUP;
//
// Get the name
//
name = strchr(line, ' ');
if ((!name) || (name[1]=='\0'))
return NVPDB_GARBLED_LINE;
name++;
//
// If it is a comment
// return a blank name (strlen(*aName)==0)
// return the comment in the value field
//
if (*name == '#') {
*aValue = name;
return 1;
}
//
// Get the value
//
value = strchr(name, '=');
if (!value)
return NVPDB_GARBLED_LINE;
*value = '\0';
value++;
//
// Check for end of group
//
if (strcmp(name,"end")==0) {
mAtEndOfGroup = PR_TRUE;
return NVPDB_END_OF_GROUP;
}
//
// Got the name and value
//
*aName = name;
*aValue = value;
return 1;
}
PRBool
nsNameValuePairDB::GetNextGroup(const char** aType)
{
return GetNextGroup(aType, nsnull, 0);
}
PRBool
nsNameValuePairDB::GetNextGroup(const char** aType, const char* aName)
{
return GetNextGroup(aType, aName, strlen(aName));
}
PRBool
nsNameValuePairDB::GetNextGroup(const char** aType, const char* aName, int aLen)
{
const char *name, *value;
long pos = 0;
*aType = "";
if (mAtEndOfCatalog)
return PR_FALSE;
//
// Move to end of current Group
//
while (GetNextElement(&name, &value) > 0)
continue;
mCurrentGroup++;
mAtEndOfGroup = PR_FALSE;
// save current pos in case this in not the desired type
// and we need to backup
if (aName)
pos = ftell(mFile);
// check if there are more Groups
if (GetNextElement(&name, &value) <= 0) {
mAtEndOfGroup = PR_TRUE;
mAtEndOfCatalog = PR_TRUE;
return PR_FALSE;
}
if (strcmp(name,"begin"))
goto GetNext_Error;
// check if this is the desired type
if (aName) {
if (strncmp(value,aName,aLen)) {
fseek(mFile, pos, SEEK_SET);
mCurrentGroup--;
mAtEndOfGroup = PR_TRUE;
return PR_FALSE;
}
}
*aType = value;
return PR_TRUE;
GetNext_Error:
mError = PR_TRUE;
NVPDB_PRINTF(("GetNext_Error"));
return PR_FALSE;
}
nsNameValuePairDB::nsNameValuePairDB()
{
mFile = nsnull;
mBuf[0] = '\0';
mMajorNum = 0;
mMinorNum = 0;
mMaintenanceNum = 0;
mCurrentGroup = 0;
mAtEndOfGroup = PR_FALSE;
mAtEndOfCatalog = PR_FALSE;
mError = PR_FALSE;
}
nsNameValuePairDB::~nsNameValuePairDB()
{
if (mFile) {
fclose(mFile);
mFile = nsnull;
}
}
PRBool
nsNameValuePairDB::OpenForRead(const nsACString & aCatalogName)
{
nsresult result;
nsCOMPtr<nsILocalFile> local_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID,
&result);
if (NS_FAILED(result))
goto error_return;
local_file->InitWithPath(PromiseFlatCString(aCatalogName).get());
local_file->OpenANSIFileDesc("r", &mFile);
if (mFile && CheckHeader())
return PR_TRUE;
error_return:
mError = PR_TRUE;
NVPDB_PRINTF(("OpenForRead error"));
return PR_FALSE;
}
PRBool
nsNameValuePairDB::OpenTmpForWrite(const nsACString& aCatalogName)
{
nsCAutoString name(aCatalogName);
name.Append(".tmp");
nsresult result;
nsCOMPtr<nsILocalFile> local_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID,
&result);
if (NS_FAILED(result))
return PR_FALSE;
local_file->InitWithPath(name.get());
local_file->OpenANSIFileDesc("w+", &mFile);
if (mFile == nsnull)
return PR_FALSE;
// Write the header
mAtEndOfGroup = PR_TRUE;
mCurrentGroup = -1;
PutStartGroup("Header");
char buf[64];
PutElement("", "########################################");
PutElement("", "# #");
PutElement("", "# Name Value Pair DB #");
PutElement("", "# #");
PutElement("", "# This is a program generated file #");
PutElement("", "# #");
PutElement("", "# Do not edit #");
PutElement("", "# #");
PutElement("", "########################################");
PR_snprintf(buf, sizeof(buf), "%d.%d.%d", NVPDB_VERSION_MAJOR,
NVPDB_VERSION_MINOR, NVPDB_VERSION_MAINTENANCE);
PutElement("Version", buf);
PutEndGroup("Header");
return PR_TRUE;
}
PRBool
nsNameValuePairDB::PutElement(const char* aName, const char* aValue)
{
if (mAtEndOfGroup) {
mError = PR_TRUE;
NVPDB_PRINTF(("PutElement_Error"));
return PR_FALSE;
}
if ((!*aName) && (*aValue == '#'))
fprintf(mFile, "%u %s\n", mCurrentGroup, aValue);
else
fprintf(mFile, "%u %s=%s\n", mCurrentGroup, aName, aValue);
#ifdef DEBUG
fflush(mFile);
#endif
return PR_TRUE;
}
PRBool
nsNameValuePairDB::PutEndGroup(const char* aType)
{
if (mAtEndOfGroup) {
mError = PR_TRUE;
NVPDB_PRINTF(("PutEndGroup_Error"));
return PR_FALSE;
}
mAtEndOfGroup = PR_TRUE;
fprintf(mFile, "%u end=%s\n", mCurrentGroup, aType);
#ifdef DEBUG
fflush(mFile);
#endif
return PR_TRUE;
}
PRBool
nsNameValuePairDB::PutStartGroup(const char* aType)
{
if (!mAtEndOfGroup) {
mError = PR_TRUE;
NVPDB_PRINTF(("PutStartGroup_Error"));
#ifdef DEBUG
fflush(mFile);
#endif
return PR_FALSE;
}
mAtEndOfGroup = PR_FALSE;
mCurrentGroup++;
fprintf(mFile, "%u begin=%s\n", mCurrentGroup, aType);
#ifdef DEBUG
fflush(mFile);
#endif
return PR_TRUE;
}
PRBool
nsNameValuePairDB::RenameTmp(const char* aCatalogName)
{
nsresult rv;
nsCOMPtr<nsILocalFile> dir;
PRBool exists = PR_FALSE;
nsCAutoString old_name(aCatalogName);
nsDependentCString current_name(aCatalogName);
nsCAutoString tmp_name(aCatalogName);
nsCAutoString old_name_tail;
nsCAutoString current_name_tail;
nsCOMPtr<nsILocalFile> old_file;
nsCOMPtr<nsILocalFile> current_file;
nsCOMPtr<nsILocalFile> tmp_file;
nsCAutoString parent_dir;
nsXPIDLCString parent_path;
nsXPIDLCString cur_path;
//
// Split the parent dir and file name
//
PRInt32 slash = 0, last_slash = -1;
nsCAutoString fontDirName(aCatalogName);
// RFindChar not coded so do it by hand
while ((slash=fontDirName.FindChar('/', slash))>=0) {
last_slash = slash;
slash++;
}
if (last_slash < 0)
goto Rename_Error;
fontDirName.Left(parent_dir, last_slash);
dir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
goto Rename_Error;
dir->InitWithPath(parent_dir.get());
dir->GetPath(getter_Copies(parent_path));
if (!mAtEndOfGroup || mError)
goto Rename_Error;
//
// check that we have a tmp copy
//
tmp_name.Append(".tmp");
tmp_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
goto Rename_Error;
tmp_file->InitWithPath(tmp_name.get());
tmp_file->Exists(&exists);
if (!exists)
goto Rename_Error;
//
// get rid of any old copy
//
old_name.Append(".old");
old_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
goto Rename_Error;
old_file->InitWithPath(old_name.get());
//
// Check we have a current copy
//
current_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
goto Rename_Error;
current_file->InitWithPath(current_name.get());
current_file->Exists(&exists);
if (exists) {
//
// Rename the current copy to old
//
current_file->GetPath(getter_Copies(cur_path));
old_name.Right(old_name_tail, old_name.Length() - last_slash - 1);
rv = current_file->MoveTo(dir, old_name_tail.get());
if (NS_FAILED(rv))
goto Rename_Error;
}
//
// Rename the tmp to current
//
current_name.Right(current_name_tail, current_name.Length() - last_slash - 1);
rv = tmp_file->MoveTo(dir, current_name_tail.get());
if (NS_FAILED(rv))
goto Rename_Error;
//
// remove the previous copy
//
if (exists) {
old_file->Remove(PR_FALSE);
}
return PR_TRUE;
Rename_Error:
mError = PR_TRUE;
NVPDB_PRINTF(("Rename_Error"));
return PR_FALSE;
}