Back to index

lightning-sunbird  0.9+nobinonly
nsINIParser.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Samir Gehani <sgehani@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 
00041 #include "nsINIParser.h"
00042 
00043 #ifdef __cplusplus
00044 extern "C" {
00045 #endif
00046 unsigned long GetPrivateProfileString(const char* szAppName,
00047                                       const char* szKeyName,
00048                                       const char* szDefault,
00049                                       char* szReturnedString,
00050                                       int nSize,
00051                                       const char* szFileName)
00052 {
00053    nsINIParser parser((char*)szFileName);
00054    if (parser.GetString((char*)szAppName, (char*)szKeyName, szReturnedString, &nSize) != nsINIParser::OK) {
00055       if (szDefault) {
00056          strcpy(szReturnedString, szDefault);
00057       }
00058    }
00059    return strlen(szReturnedString);
00060 }
00061 
00062 unsigned long WritePrivateProfileString(const char* szAppName,
00063                                         const char* szKeyName,
00064                                         const char* szValue,
00065                                         const char* szFileName)
00066 {
00067    nsINIParser parser((char*)szFileName);
00068    if (parser.WriteString((char*)szAppName, (char*)szKeyName, (char*)szValue) != nsINIParser::OK) {
00069       return 0;
00070    }
00071    return 1;
00072 }
00073 #ifdef __cplusplus
00074 }
00075 #endif
00076 
00077 nsINIParser::nsINIParser(char *aFilename)
00078 {
00079     FILE    *fd = NULL;
00080     long    eofpos = 0;
00081     int     rd = 0;
00082 
00083     mfWrite = 0;
00084     mFileBuf = NULL;
00085     mFilename = (char*)malloc(strlen(aFilename)+1);
00086     strcpy(mFilename, aFilename);
00087     mFileBufSize = 0;
00088     mError = OK;
00089 
00090     /* param check */
00091     if (!aFilename)
00092     {
00093         mError = E_PARAM;
00094         return;
00095     }
00096 
00097     /* open the file */
00098     fd = fopen(aFilename, "r");
00099     if (!fd)
00100         goto bail;
00101     
00102     /* get file size */
00103     if (fseek(fd, 0, SEEK_END) != 0)
00104         goto bail;
00105     eofpos = ftell(fd);
00106     if (eofpos == 0)
00107         goto bail;
00108 
00109     /* malloc an internal buf the size of the file */
00110     mFileBuf = (char *) calloc(1, eofpos * sizeof(char));
00111     if (!mFileBuf)
00112     {
00113         mError = E_MEM;
00114         return;
00115     }
00116     mFileBufSize = eofpos;
00117 
00118     /* read the file in one swoop */
00119     if (fseek(fd, 0, SEEK_SET) != 0)
00120         goto bail;
00121     rd = fread((void *)mFileBuf, 1, eofpos, fd);
00122     if (!rd)
00123         goto bail;
00124 
00125     /* actual number of bytes read is less than the size of the file */
00126     /* due to /r/n -> /n conversion */
00127     if (rd < eofpos) {
00128       mFileBufSize = rd;
00129     } else {
00130       mFileBufSize = eofpos;
00131     }
00132 
00133     /* close file */
00134     fclose(fd);
00135 
00136     return;
00137 
00138 bail:
00139     mError = E_READ;
00140     return;
00141 }
00142 
00143 nsINIParser::~nsINIParser()
00144 {
00145     if (mfWrite) {
00146       FILE* hFile = fopen(mFilename, "w+");
00147       fwrite(mFileBuf, mFileBufSize, 1, (FILE *)hFile);
00148       fclose(hFile);
00149     }
00150     free(mFileBuf);
00151     free(mFilename);
00152 }
00153 
00154 int
00155 nsINIParser::GetString( char *aSection, char *aKey, 
00156                         char *aValBuf, int *aIOValBufSize )
00157 {
00158     char *secPtr = NULL;
00159     mError = OK;
00160     DUMP("GetString");
00161 
00162     /* param check */
00163     if ( !aSection || !aKey || !aValBuf || 
00164          !aIOValBufSize || (*aIOValBufSize <= 0) )
00165         return E_PARAM;
00166 
00167     /* find the section if it exists */
00168     mError = FindSection(aSection, &secPtr);
00169     if (mError != OK)
00170         return mError;
00171 
00172     /* find the key if it exists in the valid section we found */
00173     mError = GetValue(secPtr, aKey, aValBuf, aIOValBufSize);
00174 
00175     return mError;
00176 }
00177 
00178 int
00179 nsINIParser::GetStringAlloc( char *aSection, char *aKey,
00180                              char **aOutBuf, int *aOutBufSize )
00181 {
00182     char buf[MAX_VAL_SIZE];
00183     int bufsize = MAX_VAL_SIZE;
00184     mError = OK;
00185     DUMP("GetStringAlloc");
00186 
00187     mError = GetString(aSection, aKey, buf, &bufsize);
00188     if (mError != OK)
00189         return mError;
00190 
00191     *aOutBuf = (char *) malloc(bufsize + 1);
00192     strncpy(*aOutBuf, buf, bufsize);
00193     *(*aOutBuf + bufsize) = 0;
00194     *aOutBufSize = bufsize + 1;
00195 
00196     return mError;
00197 }
00198 
00199 int
00200 nsINIParser::GetError()
00201 {
00202     DUMP("GetError");
00203     return mError;
00204 }
00205 
00206 char *
00207 nsINIParser::ResolveName(char *aINIRoot)
00208 {
00209     char *resolved = NULL;
00210     char *locale = NULL;
00211     struct stat st_exists;
00212 
00213     /* param check */
00214     if (!aINIRoot)
00215         return NULL;
00216 
00217     locale = setlocale(LC_CTYPE, NULL);
00218     if (!locale) 
00219         return NULL;
00220 
00221     /* resolved string: "<root>.ini.<locale>\0" */
00222     resolved = (char *) malloc(strlen(aINIRoot) + 5 + strlen(locale) + 1);
00223     if (!resolved)
00224         return NULL;
00225 
00226     /* locale specific ini file name */
00227     sprintf(resolved, "%s.ini.%s", aINIRoot, locale);
00228     if (0 == stat(resolved, &st_exists))
00229         return resolved;
00230 
00231     /* fallback to general ini file name */
00232     sprintf(resolved, "%s.ini", aINIRoot);
00233     if (0 == stat(resolved, &st_exists))
00234         return resolved;
00235     
00236     /* neither existed so error returned */
00237     return NULL;
00238 }
00239 
00240 int
00241 nsINIParser::WriteString(char *aSection, char *aKey, char *aValBuf)
00242 {
00243     mfWrite = 1;
00244     char *secPtr = NULL;
00245     char *keyPtr = NULL;
00246     mError = OK;
00247     DUMP("GetString");
00248 
00249     /* param check */
00250     if ( !aSection || !aKey || !aValBuf )
00251         return E_PARAM;
00252 
00253     /* find the section if it exists */
00254     mError = FindSection(aSection, &secPtr);
00255     if (mError != OK) {
00256       /* if the seciont doesn't exist, add it to the END of the buffer */
00257       char szNewSection[MAX_VAL_SIZE];
00258       strcpy(szNewSection, "[");
00259       strcat(szNewSection, aSection);
00260       strcat(szNewSection, "]");
00261       strcat(szNewSection, NLSTRING);
00262       mFileBuf = (char*)realloc(mFileBuf, mFileBufSize+strlen(szNewSection));
00263       memcpy(&mFileBuf[mFileBufSize], szNewSection, strlen(szNewSection));
00264       secPtr = &mFileBuf[mFileBufSize];
00265       mFileBufSize+= strlen(szNewSection);
00266       mError = OK;
00267     }
00268 
00269     /* find the key if it exists in the valid section we found */
00270     mError = FindKey(secPtr, aKey, &keyPtr);
00271     if (mError != OK) {
00272       char szNewKeyValue[MAX_VAL_SIZE];
00273       strcpy(szNewKeyValue, aKey);
00274       strcat(szNewKeyValue, "=");
00275       strcat(szNewKeyValue, aValBuf);
00276       strcat(szNewKeyValue, NLSTRING);
00277       char *mNewFileBuf = (char*)calloc(1, mFileBufSize+strlen(szNewKeyValue));
00278       memcpy(mNewFileBuf, mFileBuf, mFileBufSize);
00279       /* Set the section pointer to the location of the rest of the buffer */
00280       while (*secPtr != NL) {
00281          secPtr++;
00282       }
00283       secPtr++;
00284       /* Use sectionptr to compte where in the new buf we are going to insert */
00285       memcpy(mNewFileBuf+(secPtr-mFileBuf), szNewKeyValue, strlen(szNewKeyValue));
00286       memcpy(mNewFileBuf+(secPtr-mFileBuf)+strlen(szNewKeyValue), secPtr, mFileBufSize-(secPtr-mFileBuf));
00287       mFileBufSize += strlen(szNewKeyValue);
00288       free(mFileBuf);
00289       mFileBuf = mNewFileBuf;
00290       mError = OK;
00291     } else {
00292       while (*keyPtr != '=') {
00293          keyPtr++;
00294       }
00295       keyPtr++;
00296       int length = 0;
00297       char* lenPtr = keyPtr;
00298       while (*lenPtr != NL) {
00299          lenPtr++;
00300          length++;
00301       }
00302       int difference;
00303       difference = strlen(aValBuf)- length;
00304       char *mNewFileBuf = (char*)calloc(1, mFileBufSize+difference);
00305       memcpy(mNewFileBuf, mFileBuf, mFileBufSize);
00306       /* Use keyptr to compte where in the new buf we are going to insert */
00307       memcpy(mNewFileBuf+(keyPtr-mFileBuf), aValBuf, strlen(aValBuf));
00308 
00309 
00310       memcpy(mNewFileBuf+(keyPtr-mFileBuf)+strlen(aValBuf), lenPtr, mFileBufSize-(lenPtr-mFileBuf));
00311       mFileBufSize += difference;
00312       free(mFileBuf);
00313       mFileBuf = mNewFileBuf;
00314       mError = OK;
00315 
00316 
00317     }
00318 
00319     return mError;
00320 }
00321 
00322 int
00323 nsINIParser::FindSection(char *aSection, char **aOutSecPtr)
00324 {
00325     char *currChar = mFileBuf;
00326     char *nextSec = NULL;
00327     char *secClose = NULL;
00328     char *nextNL = NULL;
00329     mError = E_NO_SEC;
00330     DUMP("FindSection");
00331 
00332     // param check
00333     if (!aSection || !aOutSecPtr)
00334     {
00335         mError = E_PARAM;
00336         return mError;
00337     }
00338 
00339     while (currChar < (mFileBuf + mFileBufSize))
00340     {
00341         // look for first '['
00342         nextSec = NULL;
00343         nextSec = strchr(currChar, '[');
00344         if (!nextSec)
00345             break;
00346             
00347         currChar = nextSec + 1;
00348 
00349         // extract section name till first ']'
00350         secClose = NULL; nextNL = NULL;
00351         secClose = strchr(currChar, ']');
00352         nextNL = strchr(currChar, NL);
00353         if ((!nextNL) || (nextNL < secClose))
00354         {
00355             currChar = nextNL;
00356             continue;
00357         }
00358 
00359         // if section name matches we succeeded
00360         if (strnicmp(aSection, currChar, strlen(aSection)) == 0)
00361         {
00362             *aOutSecPtr = secClose + 1;
00363             mError = OK;
00364             break;
00365         }
00366     }
00367 
00368     return mError;
00369 }
00370 
00371 int
00372 nsINIParser::GetValue(char *aSecPtr, char *aKey, char *aVal, int *aIOValSize)
00373 {
00374     char *nextNL = NULL;
00375     char *secEnd = NULL;
00376     char *currLine = aSecPtr;
00377     char *nextEq = NULL;
00378     mError = E_NO_KEY;
00379     DUMP("FindKey");
00380 
00381     // param check
00382     if (!aSecPtr || !aKey || !aVal || !aIOValSize || (*aIOValSize <= 0))
00383     {
00384         mError = E_PARAM;
00385         return mError;
00386     }
00387 
00388     // determine the section end
00389     secEnd = aSecPtr;
00390 find_end:
00391     if (secEnd)
00392         secEnd = strchr(secEnd, '['); // search for next sec start
00393     if (!secEnd)
00394     {
00395         secEnd = strchr(aSecPtr, '\0'); // else search for file end
00396         if (!secEnd)
00397         {
00398             mError = E_SEC_CORRUPT; // else this data is corrupt
00399             return mError;
00400         }
00401     }
00402 
00403     // handle start section token ('[') in values for i18n
00404     if (*secEnd == '[' && !(secEnd == aSecPtr || *(secEnd-1) == NL))
00405     {
00406         secEnd++;
00407         goto find_end;
00408     }
00409 
00410     while (currLine < secEnd)
00411     {
00412         nextNL = NULL;
00413         nextNL = strchr(currLine, NL);
00414         if (!nextNL)
00415             nextNL = mFileBuf + mFileBufSize;
00416 
00417         // ignore commented lines (starting with ;)
00418         if (currLine == strchr(currLine, ';'))
00419         {
00420             currLine = nextNL + 1;
00421             continue;
00422         }
00423 
00424         // extract key before '='
00425         nextEq = NULL;
00426         nextEq = strchr(currLine, '=');
00427         if (!nextEq || nextEq > nextNL) 
00428         {
00429             currLine = nextNL + 1;
00430             continue;
00431         }
00432 
00433         // if key matches we succeeded
00434         if (strnicmp(currLine, aKey, strlen(aKey)) == 0)
00435         {
00436             // extract the value and return
00437             if (*aIOValSize < nextNL - nextEq)
00438             {
00439                 mError = E_SMALL_BUF;
00440                 *aVal = '\0';
00441                 *aIOValSize = 0;
00442                 return mError;
00443             }
00444                 
00445             *aIOValSize = nextNL - (nextEq + 1); 
00446             strncpy(aVal, (nextEq + 1), *aIOValSize);
00447             *(aVal + *aIOValSize) = 0; // null terminate
00448             mError = OK;
00449             return mError;
00450         }
00451         else
00452         {
00453             currLine = nextNL + 1;
00454         }
00455     }
00456 
00457     return mError;
00458 }
00459 
00460 int
00461 nsINIParser::FindKey(char *aSecPtr, char *aKey, char **aOutKeyPtr)
00462 {
00463     char *nextNL = NULL;
00464     char *secEnd = NULL;
00465     char *currLine = aSecPtr;
00466     char *nextEq = NULL;
00467     mError = E_NO_KEY;
00468     DUMP("FindKey");
00469 
00470     // param check
00471     if (!aSecPtr || !aKey || !aOutKeyPtr)
00472     {
00473         mError = E_PARAM;
00474         return mError;
00475     }
00476 
00477     // determine the section end
00478     secEnd = aSecPtr;
00479 find_end:
00480     if (secEnd)
00481         secEnd = strchr(secEnd, '['); // search for next sec start
00482     if (!secEnd)
00483     {
00484         secEnd = strchr(aSecPtr, '\0'); // else search for file end
00485         if (!secEnd)
00486         {
00487             mError = E_SEC_CORRUPT; // else this data is corrupt
00488             return mError;
00489         }
00490     }
00491 
00492     // handle start section token ('[') in values for i18n
00493     if (*secEnd == '[' && !(secEnd == aSecPtr || *(secEnd-1) == NL))
00494     {
00495         secEnd++;
00496         goto find_end;
00497     }
00498 
00499     while (currLine < secEnd)
00500     {
00501         nextNL = NULL;
00502         nextNL = strchr(currLine, NL);
00503         if (!nextNL)
00504             nextNL = mFileBuf + mFileBufSize;
00505 
00506         // ignore commented lines (starting with ;)
00507         if (currLine == strchr(currLine, ';'))
00508         {
00509             currLine = nextNL + 1;
00510             continue;
00511         }
00512 
00513         // extract key before '='
00514         nextEq = NULL;
00515         nextEq = strchr(currLine, '=');
00516         if (!nextEq || nextEq > nextNL) 
00517         {
00518             currLine = nextNL + 1;
00519             continue;
00520         }
00521 
00522         // if key matches we succeeded
00523         if (strnicmp(currLine, aKey, strlen(aKey)) == 0)
00524         {
00525             *aOutKeyPtr = currLine;
00526             mError = OK;
00527             return mError;
00528         }
00529         else
00530         {
00531             currLine = nextNL + 1;
00532         }
00533     }
00534 
00535     return mError;
00536 }