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 || !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     if (aKey) {
00173         /* find the key if it exists in the valid section we found */
00174         mError = GetValue(secPtr, aKey, aValBuf, aIOValBufSize);
00175     } else {
00176         mError = GetAllKeys(secPtr, aValBuf, aIOValBufSize);
00177     }
00178 
00179 
00180     return mError;
00181 }
00182 
00183 int
00184 nsINIParser::GetStringAlloc( char *aSection, char *aKey,
00185                              char **aOutBuf, int *aOutBufSize )
00186 {
00187     char buf[MAX_VAL_SIZE];
00188     int bufsize = MAX_VAL_SIZE;
00189     mError = OK;
00190     DUMP("GetStringAlloc");
00191 
00192     mError = GetString(aSection, aKey, buf, &bufsize);
00193     if (mError != OK)
00194         return mError;
00195 
00196     *aOutBuf = (char *) malloc(bufsize + 1);
00197     strncpy(*aOutBuf, buf, bufsize);
00198     *(*aOutBuf + bufsize) = 0;
00199     *aOutBufSize = bufsize + 1;
00200 
00201     return mError;
00202 }
00203 
00204 int
00205 nsINIParser::GetError()
00206 {
00207     DUMP("GetError");
00208     return mError;
00209 }
00210 
00211 char *
00212 nsINIParser::ResolveName(char *aINIRoot)
00213 {
00214     char *resolved = NULL;
00215     char *locale = NULL;
00216     struct stat st_exists;
00217 
00218     /* param check */
00219     if (!aINIRoot)
00220         return NULL;
00221 
00222     locale = setlocale(LC_CTYPE, NULL);
00223     if (!locale) 
00224         return NULL;
00225 
00226     /* resolved string: "<root>.ini.<locale>\0" */
00227     resolved = (char *) malloc(strlen(aINIRoot) + 5 + strlen(locale) + 1);
00228     if (!resolved)
00229         return NULL;
00230 
00231     /* locale specific ini file name */
00232     sprintf(resolved, "%s.ini.%s", aINIRoot, locale);
00233     if (0 == stat(resolved, &st_exists))
00234         return resolved;
00235 
00236     /* fallback to general ini file name */
00237     sprintf(resolved, "%s.ini", aINIRoot);
00238     if (0 == stat(resolved, &st_exists))
00239         return resolved;
00240     
00241     /* neither existed so error returned */
00242     return NULL;
00243 }
00244 
00245 int
00246 nsINIParser::WriteString(char *aSection, char *aKey, char *aValBuf)
00247 {
00248     mfWrite = 1;
00249     char *secPtr = NULL;
00250     char *keyPtr = NULL;
00251     mError = OK;
00252     DUMP("GetString");
00253 
00254     /* param check */
00255     if ( !aSection || !aKey || !aValBuf )
00256         return E_PARAM;
00257 
00258     /* find the section if it exists */
00259     mError = FindSection(aSection, &secPtr);
00260     if (mError != OK) {
00261       /* if the seciont doesn't exist, add it to the END of the buffer */
00262       char szNewSection[MAX_VAL_SIZE];
00263       strcpy(szNewSection, "[");
00264       strcat(szNewSection, aSection);
00265       strcat(szNewSection, "]");
00266       strcat(szNewSection, NLSTRING);
00267       mFileBuf = (char*)realloc(mFileBuf, mFileBufSize+strlen(szNewSection));
00268       memcpy(&mFileBuf[mFileBufSize], szNewSection, strlen(szNewSection));
00269       secPtr = &mFileBuf[mFileBufSize];
00270       mFileBufSize+= strlen(szNewSection);
00271       mError = OK;
00272     }
00273 
00274     /* find the key if it exists in the valid section we found */
00275     mError = FindKey(secPtr, aKey, &keyPtr);
00276     if (mError != OK) {
00277       char szNewKeyValue[MAX_VAL_SIZE];
00278       strcpy(szNewKeyValue, aKey);
00279       strcat(szNewKeyValue, "=");
00280       strcat(szNewKeyValue, aValBuf);
00281       strcat(szNewKeyValue, NLSTRING);
00282       char *mNewFileBuf = (char*)calloc(1, mFileBufSize+strlen(szNewKeyValue));
00283       memcpy(mNewFileBuf, mFileBuf, mFileBufSize);
00284       /* Set the section pointer to the location of the rest of the buffer */
00285       while (*secPtr != NL) {
00286          secPtr++;
00287       }
00288       secPtr++;
00289       /* Use sectionptr to compte where in the new buf we are going to insert */
00290       memcpy(mNewFileBuf+(secPtr-mFileBuf), szNewKeyValue, strlen(szNewKeyValue));
00291       memcpy(mNewFileBuf+(secPtr-mFileBuf)+strlen(szNewKeyValue), secPtr, mFileBufSize-(secPtr-mFileBuf));
00292       mFileBufSize += strlen(szNewKeyValue);
00293       free(mFileBuf);
00294       mFileBuf = mNewFileBuf;
00295       mError = OK;
00296     } else {
00297       while (*keyPtr != '=') {
00298          keyPtr++;
00299       }
00300       keyPtr++;
00301       int length = 0;
00302       char* lenPtr = keyPtr;
00303       while (*lenPtr != NL) {
00304          lenPtr++;
00305          length++;
00306       }
00307       int difference;
00308       difference = strlen(aValBuf)- length;
00309       char *mNewFileBuf = (char*)calloc(1, mFileBufSize+difference);
00310       memcpy(mNewFileBuf, mFileBuf, mFileBufSize);
00311       /* Use keyptr to compte where in the new buf we are going to insert */
00312       memcpy(mNewFileBuf+(keyPtr-mFileBuf), aValBuf, strlen(aValBuf));
00313 
00314 
00315       memcpy(mNewFileBuf+(keyPtr-mFileBuf)+strlen(aValBuf), lenPtr, mFileBufSize-(lenPtr-mFileBuf));
00316       mFileBufSize += difference;
00317       free(mFileBuf);
00318       mFileBuf = mNewFileBuf;
00319       mError = OK;
00320 
00321 
00322     }
00323 
00324     return mError;
00325 }
00326 
00327 int
00328 nsINIParser::FindSection(char *aSection, char **aOutSecPtr)
00329 {
00330     char *currChar = mFileBuf;
00331     char *nextSec = NULL;
00332     char *secClose = NULL;
00333     char *nextNL = NULL;
00334     mError = E_NO_SEC;
00335     DUMP("FindSection");
00336 
00337     // param check
00338     if (!aSection || !aOutSecPtr)
00339     {
00340         mError = E_PARAM;
00341         return mError;
00342     }
00343 
00344     while (currChar < (mFileBuf + mFileBufSize))
00345     {
00346         // look for first '['
00347         nextSec = NULL;
00348         nextSec = strchr(currChar, '[');
00349         if (!nextSec)
00350             break;
00351             
00352         currChar = nextSec + 1;
00353 
00354         // extract section name till first ']'
00355         secClose = NULL; nextNL = NULL;
00356         secClose = strchr(currChar, ']');
00357         nextNL = strchr(currChar, NL);
00358         if ((!nextNL) || (nextNL < secClose))
00359         {
00360             currChar = nextNL;
00361             continue;
00362         }
00363 
00364         // if section name matches we succeeded
00365         if (strnicmp(aSection, currChar, strlen(aSection)) == 0)
00366         {
00367             *aOutSecPtr = secClose + 1;
00368             mError = OK;
00369             break;
00370         }
00371     }
00372 
00373     return mError;
00374 }
00375 
00376 int
00377 nsINIParser::GetValue(char *aSecPtr, char *aKey, char *aVal, int *aIOValSize)
00378 {
00379     char *nextNL = NULL;
00380     char *secEnd = NULL;
00381     char *currLine = aSecPtr;
00382     char *nextEq = NULL;
00383     mError = E_NO_KEY;
00384     DUMP("FindKey");
00385 
00386     // param check
00387     if (!aSecPtr || !aKey || !aVal || !aIOValSize || (*aIOValSize <= 0))
00388     {
00389         mError = E_PARAM;
00390         return mError;
00391     }
00392 
00393     // determine the section end
00394     secEnd = aSecPtr;
00395 find_end:
00396     if (secEnd)
00397         secEnd = strchr(secEnd, '['); // search for next sec start
00398     if (!secEnd)
00399     {
00400         secEnd = strchr(aSecPtr, '\0'); // else search for file end
00401         if (!secEnd)
00402         {
00403             mError = E_SEC_CORRUPT; // else this data is corrupt
00404             return mError;
00405         }
00406     }
00407 
00408     // handle start section token ('[') in values for i18n
00409     if (*secEnd == '[' && !(secEnd == aSecPtr || *(secEnd-1) == NL))
00410     {
00411         secEnd++;
00412         goto find_end;
00413     }
00414 
00415     while (currLine < secEnd)
00416     {
00417         nextNL = NULL;
00418         nextNL = strchr(currLine, NL);
00419         if (!nextNL)
00420             nextNL = mFileBuf + mFileBufSize;
00421 
00422         // ignore commented lines (starting with ;)
00423         if (currLine == strchr(currLine, ';'))
00424         {
00425             currLine = nextNL + 1;
00426             continue;
00427         }
00428 
00429         // extract key before '='
00430         nextEq = NULL;
00431         nextEq = strchr(currLine, '=');
00432         if (!nextEq || nextEq > nextNL) 
00433         {
00434             currLine = nextNL + 1;
00435             continue;
00436         }
00437 
00438         // if key matches we succeeded
00439         if (strnicmp(currLine, aKey, strlen(aKey)) == 0)
00440         {
00441             // extract the value and return
00442             if (*aIOValSize < nextNL - nextEq)
00443             {
00444                 mError = E_SMALL_BUF;
00445                 *aVal = '\0';
00446                 *aIOValSize = 0;
00447                 return mError;
00448             }
00449                 
00450             *aIOValSize = nextNL - (nextEq + 1); 
00451             strncpy(aVal, (nextEq + 1), *aIOValSize);
00452             *(aVal + *aIOValSize) = 0; // null terminate
00453             mError = OK;
00454             return mError;
00455         }
00456         else
00457         {
00458             currLine = nextNL + 1;
00459         }
00460     }
00461 
00462     return mError;
00463 }
00464 
00465 int
00466 nsINIParser::GetAllKeys(char *aSecPtr, char *aVal, int *aIOValSize)
00467 {
00468     char *nextNL = NULL;
00469     char *secEnd = NULL;
00470     char *currLine = aSecPtr;
00471     char *nextEq = NULL;
00472     char *outPtr = NULL;
00473     mError = E_NO_KEY;
00474     DUMP("FindKey");
00475 
00476     // param check
00477     if (!aSecPtr || !aVal || !aIOValSize || (*aIOValSize <= 0))
00478     {
00479         mError = E_PARAM;
00480         return mError;
00481     }
00482 
00483     // determine the section end
00484     secEnd = aSecPtr;
00485 find_end:
00486     if (secEnd)
00487         secEnd = strchr(secEnd, '['); // search for next sec start
00488     if (!secEnd)
00489     {
00490         secEnd = strchr(aSecPtr, '\0'); // else search for file end
00491         if (!secEnd)
00492         {
00493             mError = E_SEC_CORRUPT; // else this data is corrupt
00494             return mError;
00495         }
00496     }
00497 
00498     // handle start section token ('[') in values for i18n
00499     if (*secEnd == '[' && !(secEnd == aSecPtr || *(secEnd-1) == NL))
00500     {
00501         secEnd++;
00502         goto find_end;
00503     }
00504 
00505     outPtr = aVal;
00506 
00507     while (currLine < secEnd)
00508     {
00509         nextNL = NULL;
00510         nextNL = strchr(currLine, NL);
00511         if (!nextNL)
00512             nextNL = mFileBuf + mFileBufSize;
00513 
00514         // ignore commented lines (starting with ;)
00515         if (currLine == strchr(currLine, ';'))
00516         {
00517             currLine = nextNL + 1;
00518             continue;
00519         }
00520 
00521         // extract key before '='
00522         nextEq = NULL;
00523         nextEq = strchr(currLine, '=');
00524         if (!nextEq || nextEq > nextNL) 
00525         {
00526             currLine = nextNL + 1;
00527             continue;
00528         }
00529 
00530         strncpy(aVal, currLine, nextEq-currLine);
00531         aVal+= nextEq-currLine;
00532         *aVal = '\0';
00533         aVal++;
00534 
00535         currLine = nextNL + 1;
00536     }
00537 
00538     return OK;
00539 }
00540 
00541 int
00542 nsINIParser::FindKey(char *aSecPtr, char *aKey, char **aOutKeyPtr)
00543 {
00544     char *nextNL = NULL;
00545     char *secEnd = NULL;
00546     char *currLine = aSecPtr;
00547     char *nextEq = NULL;
00548     mError = E_NO_KEY;
00549     DUMP("FindKey");
00550 
00551     // param check
00552     if (!aSecPtr || !aKey || !aOutKeyPtr)
00553     {
00554         mError = E_PARAM;
00555         return mError;
00556     }
00557 
00558     // determine the section end
00559     secEnd = aSecPtr;
00560 find_end:
00561     if (secEnd)
00562         secEnd = strchr(secEnd, '['); // search for next sec start
00563     if (!secEnd)
00564     {
00565         secEnd = strchr(aSecPtr, '\0'); // else search for file end
00566         if (!secEnd)
00567         {
00568             mError = E_SEC_CORRUPT; // else this data is corrupt
00569             return mError;
00570         }
00571     }
00572 
00573     // handle start section token ('[') in values for i18n
00574     if (*secEnd == '[' && !(secEnd == aSecPtr || *(secEnd-1) == NL))
00575     {
00576         secEnd++;
00577         goto find_end;
00578     }
00579 
00580     while (currLine < secEnd)
00581     {
00582         nextNL = NULL;
00583         nextNL = strchr(currLine, NL);
00584         if (!nextNL)
00585             nextNL = mFileBuf + mFileBufSize;
00586 
00587         // ignore commented lines (starting with ;)
00588         if (currLine == strchr(currLine, ';'))
00589         {
00590             currLine = nextNL + 1;
00591             continue;
00592         }
00593 
00594         // extract key before '='
00595         nextEq = NULL;
00596         nextEq = strchr(currLine, '=');
00597         if (!nextEq || nextEq > nextNL) 
00598         {
00599             currLine = nextNL + 1;
00600             continue;
00601         }
00602 
00603         // if key matches we succeeded
00604         if (strnicmp(currLine, aKey, strlen(aKey)) == 0)
00605         {
00606             *aOutKeyPtr = currLine;
00607             mError = OK;
00608             return mError;
00609         }
00610         else
00611         {
00612             currLine = nextNL + 1;
00613         }
00614     }
00615 
00616     return mError;
00617 }