RetroZilla/modules/plugin/tools/tester/common/pplib.cpp
2015-10-20 23:03:22 -04:00

498 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla 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/MPL/
*
* 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):
*
* 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 MPL, 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 MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/****************************************************/
/* */
/* Private profile library */
/* */
/* Attempt to write a cross-platform library for */
/* dealing with Windows style .INI profiles. */
/* */
/* For API see pplib.h */
/* */
/* 11.26.97 - av started */
/* */
/* Current limitations: */
/* - profile must NOT contain space chars */
/* - colon indicating comments must be in the */
/* first position */
/* */
/****************************************************/
#include "xp.h"
static BOOL isCurrentLineCommentedOut(char * pBuf, char * pPosition)
{
for(;;)
{
if((*pPosition == ';') && ((pPosition - 1 < pBuf) || (*(pPosition - 1) == '\n') || (*(pPosition - 1) == '\r')))
return TRUE;
pPosition--;
if(pPosition < pBuf)
return FALSE;
if((*pPosition == '\n') || (*pPosition == '\r'))
return FALSE;
}
}
/*******************************************************************/
/* */
/* Note: For a section header to be found, the [ must be the first */
/* character on the line. This prevents the [Options] string in */
/* the comments of the Sample.pts script from being found as the */
/* top of the Options section. -pollmann */
/* */
/*******************************************************************/
static char * goToSectionBody(char * pBuf, char * szSection)
{
if((pBuf == NULL) || (szSection == NULL))
return NULL;
char szSectionString[256];
strcpy(szSectionString, "\n"); /* Line feed before [ */
strcat(szSectionString, "[");
strcat(szSectionString, szSection);
strcat(szSectionString, "]");
char * p = strstr(pBuf, szSectionString);
if(p == NULL) {
szSectionString[0] = '\r'; /* Carriage return before [ */
char * p = strstr(pBuf, szSectionString);
if(p == NULL)
return NULL;
}
p += strlen(szSectionString) + 1; // 1 is for new line character
return p;
}
static int getSectionLength(char * pBuf, char * szSection)
{
int iRet = 0;
char * pSectionStart = goToSectionBody(pBuf, szSection);
if(pSectionStart == NULL)
return 0;
char * pNextSection = strstr(pSectionStart, "[");
if(pNextSection != NULL)
iRet = (int)(pNextSection - pSectionStart);
else
iRet = (int)(pBuf + strlen(pBuf) - pSectionStart);
return iRet;
}
static char * goToKeyBody(char * pSectionStart, int iSectionLength, char * szKey)
{
if((pSectionStart == NULL) || (szKey == NULL))
return NULL;
if((int)strlen(szKey) >= iSectionLength)
return NULL;
char szKeyString[256];
strcpy(szKeyString, szKey);
strcat(szKeyString, "=");
char chBackup = pSectionStart[iSectionLength];
pSectionStart[iSectionLength] = '\0';
char * p = strstr(pSectionStart, szKeyString);
if(p == NULL)
{
pSectionStart[iSectionLength] = chBackup;
return NULL;
}
p = strstr(p, "=");
if(p == NULL)
{
pSectionStart[iSectionLength] = chBackup;
return NULL;
}
p++;
pSectionStart[iSectionLength] = chBackup;
if(isCurrentLineCommentedOut(pSectionStart, p))
return NULL;
else
return p;
}
static int getKeyLength(char * pSectionStart, int iSectionLength, char * szKey)
{
int iRet = 0;
char * pKeyStart = goToKeyBody(pSectionStart, iSectionLength, szKey);
if(pKeyStart == NULL)
return 0;
char * pFirstCarriageReturn = strchr(pKeyStart, '\r');
char * pFirstNewLine = strchr(pKeyStart, '\n');
if((pFirstCarriageReturn == NULL) && (pFirstNewLine == NULL))
return iSectionLength;
char * p = NULL;
if((pFirstCarriageReturn != NULL) && (pFirstNewLine != NULL))
p = (pFirstCarriageReturn < pFirstNewLine) ? pFirstCarriageReturn : pFirstNewLine;
else
p = (pFirstCarriageReturn != NULL) ? pFirstCarriageReturn : pFirstNewLine;
p--;
// cut off ending spaces and tabs
while((*p == ' ') || (*p == '\t'))
p--;
p++;
iRet = (int)(p - pKeyStart);
return iRet;
}
static char * readFileToNewAllocatedZeroTerminatedBuffer(XP_HFILE hFile)
{
if(hFile == NULL)
return NULL;
int iSize;
#ifdef XP_MAC
iSize = 32000; /* HACK for the MAC */
#else
#if defined(XP_UNIX) || defined(XP_OS2)
struct stat buf;
fstat(fileno(hFile), &buf);
iSize = buf.st_size;
#else
iSize = (int)_filelength(/*_fileno*/(hFile));
#endif
#endif
if(iSize <= 0)
return NULL;
char * pBuf = new char[iSize + 1];
if(pBuf == NULL)
return NULL;
fseek((FILE *)hFile, 0L, SEEK_SET);
fread((void *)pBuf, iSize, 1, (FILE *)hFile);
// cut off strange stuff at the end and reallocate
char * p = pBuf + iSize - 1;
for(;;)
{
BOOL bNormalChar = ((int)*p > 0) && (isprint(*p) != 0);
if(bNormalChar || (*p == '\n') || (*p == '\r') || (p < pBuf))
break;
p--;
}
p++;
*p = '\0';
iSize = strlen(pBuf);
char * pBufFinal = new char[iSize + 1];
memcpy((void *)pBufFinal, (void *)pBuf, iSize);
pBufFinal[iSize] = '\0';
delete [] pBuf;
return pBufFinal;
}
DWORD PP_GetString(char * szSection, char * szKey, char * szDefault, char * szString, DWORD dwSize, XP_HFILE hFile)
{
char * pBuf = NULL;
char * pSectionStart = NULL;
int iSectionLength = 0;
int iSize = 0;
pBuf = readFileToNewAllocatedZeroTerminatedBuffer(hFile);
if(pBuf == NULL)
goto ReturnDefault;
iSize = strlen(pBuf);
//
// first consider two special cases: szSection = NULL and szKey = NULL
//
if(szSection == NULL) // find all sections and return
{
char * pNextSection = NULL;
char * pSource = pBuf;
char * pDest = szString;
int iBytes = 0;
for(;;)
{
pSource = strstr(pSource, "[");
if(pSource == NULL)
break;
pNextSection = pSource + 1;
char * pEnd = strstr(pSource, "]");
int iLength = pEnd - pNextSection;
if(!isCurrentLineCommentedOut(pBuf, pSource))
{
if(iBytes + iLength + 2 < (int)dwSize)
memcpy((void *)pDest, (void *)pNextSection, iLength);
else
break;
pDest += iLength;
*pDest = '\0';
pDest++;
iBytes += iLength + 1; // for '\0'
if(iBytes >= iSize)
break;
}
pSource += iLength + 2; // for "[" and "]"
}
*pDest = '\0';
iBytes++; // for this '\0'
delete [] pBuf;
return (DWORD)iBytes;
}
pSectionStart = goToSectionBody(pBuf, szSection);
if(pSectionStart == NULL)
goto ReturnDefault;
iSectionLength = getSectionLength(pBuf, szSection);
if(iSectionLength == 0)
goto ReturnDefault;
if(szKey == NULL) // find all keys and return
{
int iBytes = 0;
char * pSource = pSectionStart - 1; // point to previous new line char
char * pDest = szString;
for(;;)
{
char * pEqualSign = strstr(pSource, "=");
if(pEqualSign > pSectionStart + iSectionLength)
break;
*pEqualSign = '\0';
char * pLastCarriageReturn = strrchr(pSource, '\r');
char * pLastNewLine = strrchr(pSource, '\n');
if((pLastCarriageReturn == NULL) && (pLastNewLine == NULL))
{
pSource = pEqualSign + 1;
continue;
}
char * pKey = (pLastCarriageReturn > pLastNewLine) ? pLastCarriageReturn : pLastNewLine;
pKey++;
int iLength = strlen(pKey);
if(!isCurrentLineCommentedOut(pBuf, pKey))
{
if(iBytes + iLength + 2 < (int)dwSize)
memcpy((void *)pDest, (void *)pKey, iLength);
else
break;
pDest += iLength;
*pDest = '\0';
pDest++;
iBytes += iLength + 1; // for '\0'
if(iBytes >= iSize)
break;
}
pSource = pEqualSign + 1;
}
*pDest = '\0';
iBytes++; // for this '\0'
delete [] pBuf;
return (DWORD)iBytes;
}
//
// Now the real thing
//
{
char * pKeyStart = goToKeyBody(pSectionStart, iSectionLength, szKey);
if(pKeyStart == NULL)
goto ReturnDefault;
int iKeyLength = getKeyLength(pSectionStart, iSectionLength, szKey);
int iLength = (iKeyLength < (int)dwSize - 1) ? iKeyLength : (int)dwSize - 1;
memcpy((void *)szString, (void *)pKeyStart, iLength);
szString[iLength] = '\0';
delete [] pBuf;
return (DWORD)iLength;
}
ReturnDefault:
if(pBuf != NULL)
delete [] pBuf;
if((szDefault != NULL) && (szString != NULL))
strcpy(szString, szDefault);
return (DWORD)strlen(szString);
}
static BOOL replaceBytesInReallocatedBufferAfter(
char ** ppBuf, // address of buffer pointer
char * szString, // string to make a replacement with
int iPosition, // byte after which to insert the string
int iBytesToReplace) // number of bytes to replace
{
if(ppBuf == NULL)
return FALSE;
char * pBuf = *ppBuf;
if(pBuf == NULL)
return FALSE;
int iNewLength = strlen(pBuf) - iBytesToReplace + strlen(szString);
char * pBufNew = new char[iNewLength + 1]; // 1 - for zero termination
if(pBufNew == NULL)
return FALSE;
if(iPosition > 0)
memcpy((void *)pBufNew, (void *)pBuf, iPosition);
char * p = pBufNew + iPosition;
memcpy((void *)p, (void *)szString, strlen(szString));
p += strlen(szString);
memcpy((void *)p, (void *)(pBuf + iPosition + iBytesToReplace), strlen(pBuf) - iPosition - iBytesToReplace);
p += strlen(pBuf) - iPosition - iBytesToReplace;
*p = '\0';
delete [] pBuf;
*ppBuf = pBufNew;
return TRUE;
}
BOOL PP_WriteString(char * szSection, char * szKey, char * szString, XP_HFILE hFile)
{
if((szSection == NULL) || (szKey == NULL) || (szString == NULL) || (hFile == NULL))
return FALSE;
char * pBuf = readFileToNewAllocatedZeroTerminatedBuffer(hFile);
if(pBuf == NULL)
return FALSE;
#if !(defined XP_MAC || defined XP_UNIX || defined XP_OS2)
long lOldSize = (long)strlen(pBuf);
#endif
char * pSectionStart = goToSectionBody(pBuf, szSection);
// add section if not present
if(pSectionStart == NULL)
{
char szNewSection[256];
strcpy(szNewSection, "[");
strcat(szNewSection, szSection);
strcat(szNewSection, "]");
strcat(szNewSection, "\n");
strcat(szNewSection, "\n");
if(!replaceBytesInReallocatedBufferAfter(&pBuf, szNewSection, 0, 0))
{
if(pBuf != NULL)
delete [] pBuf;
return FALSE;
}
pSectionStart = goToSectionBody(pBuf, szSection);
}
if(pSectionStart == NULL)
return FALSE;
int iSectionLength = getSectionLength(pBuf, szSection);
char * pKeyStart = goToKeyBody(pSectionStart, iSectionLength, szKey);
// add key if not present
if(pKeyStart == NULL)
{
char szNewKey[256];
strcpy(szNewKey, szKey);
strcat(szNewKey, "=");
strcat(szNewKey, "\n");
int iPos = pSectionStart - pBuf;
if(!replaceBytesInReallocatedBufferAfter(&pBuf, szNewKey, iPos, 0))
{
if(pBuf != NULL)
delete [] pBuf;
return FALSE;
}
pSectionStart = goToSectionBody(pBuf, szSection);
iSectionLength = getSectionLength(pBuf, szSection);
pKeyStart = goToKeyBody(pSectionStart, iSectionLength, szKey);
}
if(pKeyStart == NULL)
return FALSE;
int iKeyLength = getKeyLength(pSectionStart, iSectionLength, szKey);
int iPos = pKeyStart - pBuf;
if(!replaceBytesInReallocatedBufferAfter(&pBuf, szString, iPos, iKeyLength))
{
if(pBuf != NULL)
delete [] pBuf;
return FALSE;
}
#if (defined XP_MAC || defined XP_UNIX || defined XP_OS2)
rewind(hFile);
#else
// change file size
long lNewSize = (long)strlen(pBuf);
long lSizeChange = lNewSize - lOldSize;
if(lSizeChange != 0L)
{
long lOldFileSize = (long)_filelength(/*_fileno*/(hFile));
long lNewFileSize = lOldFileSize + lSizeChange;
_chsize(/*_fileno*/(hFile), lNewFileSize);
}
fseek((FILE *)hFile, 0L, SEEK_SET);
#endif
fwrite(pBuf, strlen(pBuf), 1, (FILE *)hFile);
delete [] pBuf;
return TRUE;
}