2010-04-24 21:37:39 +00:00
|
|
|
/* ini.c
|
|
|
|
|
|
|
|
* Copyright (C) 2002-2005 PCSX2 Team
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* PCSX2 members can be contacted through their website at www.pcsx2.net.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stddef.h> // NULL
|
|
|
|
|
|
|
|
#include <stdio.h> // sprintf()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "logfile.h"
|
|
|
|
|
|
|
|
#include "actualfile.h"
|
|
|
|
|
|
|
|
#include "ini.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char INIext[] = ".ini";
|
|
|
|
|
|
|
|
const char INInewext[] = ".new";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Returns: position where new extensions should be added.
|
|
|
|
|
|
|
|
int INIRemoveExt(char *argname, char *tempname) {
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
int k;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: RemoveExt(%s)", argname);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i <= INIMAXLEN) && (*(argname + i) != 0)) {
|
|
|
|
|
|
|
|
*(tempname + i) = *(argname + i);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
} // ENDWHILE- Copying the argument name into a temporary area;
|
|
|
|
|
|
|
|
*(tempname + i) = 0; // And 0-terminate
|
|
|
|
|
|
|
|
k = i;
|
|
|
|
|
|
|
|
k--;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
while((j <= INIMAXLEN) && (INIext[j] != 0)) j++;
|
|
|
|
|
|
|
|
j--;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while((j >= 0) && (*(tempname + k) == INIext[j])) {
|
|
|
|
|
|
|
|
k--;
|
|
|
|
|
|
|
|
j--;
|
|
|
|
|
|
|
|
} // ENDWHILE- Comparing the ending characters to the INI ext.
|
|
|
|
|
|
|
|
if(j < 0) {
|
|
|
|
|
|
|
|
k++;
|
|
|
|
|
|
|
|
i = k;
|
|
|
|
|
|
|
|
*(tempname + i) = 0; // 0-terminate, cutting off ".ini"
|
|
|
|
|
|
|
|
} // ENDIF- Do we have a match? Then remove the end chars.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(i);
|
|
|
|
|
|
|
|
} // END INIRemoveExt()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void INIAddInExt(char *tempname, int temppos) {
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: AddInExt(%s, %i)", tempname, temppos);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i + temppos < INIMAXLEN) && (INIext[i] != 0)) {
|
|
|
|
|
|
|
|
*(tempname + temppos + i) = INIext[i];
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
} // ENDWHILE- Attaching extenstion to filename
|
|
|
|
|
|
|
|
*(tempname + temppos + i) = 0; // And 0-terminate
|
|
|
|
|
|
|
|
} // END INIAddInExt()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void INIAddOutExt(char *tempname, int temppos) {
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: AddOutExt(%s, %i)", tempname, temppos);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i + temppos < INIMAXLEN) && (INInewext[i] != 0)) {
|
|
|
|
|
|
|
|
*(tempname + temppos + i) = INInewext[i];
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
} // ENDWHILE- Attaching extenstion to filename
|
|
|
|
|
|
|
|
*(tempname + temppos + i) = 0; // And 0-terminate
|
|
|
|
|
|
|
|
} // END INIAddInExt()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Returns number of bytes read to get line (0 means end-of-file)
|
|
|
|
|
|
|
|
int INIReadLine(ACTUALHANDLE infile, char *buffer) {
|
|
|
|
|
|
|
|
int charcount;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
char tempin[2];
|
|
|
|
|
|
|
|
int retflag;
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: ReadLine()");
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
charcount = 0;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
tempin[1] = 0;
|
|
|
|
|
|
|
|
retflag = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (retflag < 2)) {
|
|
|
|
|
|
|
|
retval = ActualFileRead(infile, 1, tempin);
|
|
|
|
|
|
|
|
charcount++;
|
|
|
|
|
|
|
|
if(retval != 1) {
|
|
|
|
|
|
|
|
retflag = 2;
|
|
|
|
|
|
|
|
charcount--;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if(tempin[0] == '\n') {
|
|
|
|
|
|
|
|
retflag = 2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if(tempin[0] >= ' ') {
|
|
|
|
|
|
|
|
*(buffer + i) = tempin[0];
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
} // ENDLONGIF- How do we react to the next character?
|
|
|
|
|
|
|
|
} // ENDWHILE- Loading up on characters until an End-of-Line appears
|
|
|
|
|
|
|
|
*(buffer + i) = 0; // And 0-terminate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: Line: %s", buffer);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(charcount);
|
|
|
|
|
|
|
|
} // END INIReadLine()
|
|
|
|
|
|
|
|
// Note: Do we need to back-skip a char if something other \n follows \r?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Returns: number of bytes to get to start of section (or -1)
|
|
|
|
|
|
|
|
int INIFindSection(ACTUALHANDLE infile, char *section) {
|
|
|
|
|
|
|
|
int charcount;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
int retflag;
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
char scanbuffer[INIMAXLEN+1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: FindSection(%s)", section);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
charcount = 0;
|
|
|
|
|
|
|
|
retflag = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while(retflag == 0) {
|
|
|
|
|
|
|
|
retval = INIReadLine(infile, scanbuffer);
|
|
|
|
|
|
|
|
if(retval == 0) return(-1); // EOF? Stop here.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(scanbuffer[0] == '[') {
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
2010-04-25 00:31:27 +00:00
|
|
|
while((i < INIMAXLEN) &&
|
2010-04-24 21:37:39 +00:00
|
|
|
|
|
|
|
(*(section + i) != 0) &&
|
|
|
|
|
|
|
|
(*(section + i) == scanbuffer[i + 1])) i++;
|
|
|
|
|
|
|
|
if((i < INIMAXLEN - 2) && (*(section + i) == 0)) {
|
|
|
|
|
|
|
|
if((scanbuffer[i + 1] == ']') && (scanbuffer[i + 2] == 0)) {
|
|
|
|
|
|
|
|
retflag = 1;
|
|
|
|
|
|
|
|
} // ENDIF- End marks look good? Return successful.
|
|
|
|
|
|
|
|
} // ENDIF- Do we have a section match?
|
|
|
|
|
|
|
|
} // ENDIF- Does this look like a section header?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(retflag == 0) charcount += retval;
|
|
|
|
|
|
|
|
} // ENDWHILE- Scanning lines for the correct [Section] header.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(charcount);
|
|
|
|
|
|
|
|
} // END INIFindSection()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Returns: number of bytes to get to start of keyword (or -1)
|
|
|
|
|
|
|
|
int INIFindKeyword(ACTUALHANDLE infile, char *keyword, char *buffer) {
|
|
|
|
|
|
|
|
int charcount;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
int retflag;
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
char scanbuffer[INIMAXLEN+1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: FindKeyword(%s)", keyword);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
charcount = 0;
|
|
|
|
|
|
|
|
retflag = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while(retflag == 0) {
|
|
|
|
|
|
|
|
retval = INIReadLine(infile, scanbuffer);
|
|
|
|
|
|
|
|
if(retval == 0) return(-1); // EOF? Stop here.
|
|
|
|
|
|
|
|
if(scanbuffer[0] == '[') return(-1); // New section? Stop here.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
2010-04-25 00:31:27 +00:00
|
|
|
while((i < INIMAXLEN) &&
|
2010-04-24 21:37:39 +00:00
|
|
|
|
|
|
|
(*(keyword + i) != 0) &&
|
|
|
|
|
|
|
|
(*(keyword + i) == scanbuffer[i])) i++;
|
|
|
|
|
|
|
|
if((i < INIMAXLEN - 2) && (*(keyword + i) == 0)) {
|
|
|
|
|
|
|
|
if(scanbuffer[i] == '=') {
|
|
|
|
|
|
|
|
retflag = 1;
|
|
|
|
|
|
|
|
if(buffer != NULL) {
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (scanbuffer[i] != 0)) {
|
|
|
|
|
|
|
|
*(buffer + j) = scanbuffer[i];
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
j++;
|
|
|
|
|
|
|
|
} // ENDWHILE- Copying the value out to the outbound buffer.
|
|
|
|
|
|
|
|
*(buffer + j) = 0; // And 0-terminate.
|
|
|
|
|
|
|
|
} // ENDIF- Return the value as well?
|
|
|
|
|
|
|
|
} // ENDIF- End marks look good? Return successful.
|
|
|
|
|
|
|
|
} // ENDIF- Do we have a section match?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(retflag == 0) charcount += retval;
|
|
|
|
|
|
|
|
} // ENDWHILE- Scanning lines for the correct [Section] header.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: Value: %s", buffer);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(charcount);
|
|
|
|
|
|
|
|
} // END INIFindKeyWord()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Returns: number of bytes left to write... (from charcount back)
|
|
|
|
|
|
|
|
int INICopy(ACTUALHANDLE infile, ACTUALHANDLE outfile, int charcount) {
|
|
|
|
|
|
|
|
char buffer[4096];
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
int chunk;
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: Copy(%i)", charcount);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = charcount;
|
|
|
|
|
|
|
|
chunk = 4096;
|
|
|
|
|
|
|
|
if(i < chunk) chunk = i;
|
|
|
|
|
|
|
|
while(chunk > 0) {
|
|
|
|
|
|
|
|
retval = ActualFileRead(infile, chunk, buffer);
|
|
|
|
|
|
|
|
if(retval <= 0) return(i); // Trouble? Stop here.
|
|
|
|
|
|
|
|
if(retval < chunk) chunk = retval; // Short block? Note it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = ActualFileWrite(outfile, chunk, buffer);
|
|
|
|
|
|
|
|
if(retval <= 0) return(i); // Trouble? Stop here.
|
|
|
|
|
|
|
|
i -= retval;
|
|
|
|
|
|
|
|
if(retval < chunk) return(i); // Short block written? Stop here.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chunk = 4096;
|
|
|
|
|
|
|
|
if(i < chunk) chunk = i;
|
|
|
|
|
|
|
|
} // ENDWHILE- Copying a section of file across, one chunk at a time.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
} // END INICopyToPos()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int INISaveString(char *file, char *section, char *keyword, char *value) {
|
|
|
|
|
|
|
|
char inname[INIMAXLEN+1];
|
|
|
|
|
|
|
|
char outname[INIMAXLEN+1];
|
|
|
|
|
|
|
|
int filepos;
|
|
|
|
|
|
|
|
ACTUALHANDLE infile;
|
|
|
|
|
|
|
|
ACTUALHANDLE outfile;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
char templine[INIMAXLEN+1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(file == NULL) return(-1);
|
|
|
|
|
|
|
|
if(section == NULL) return(-1);
|
|
|
|
|
|
|
|
if(keyword == NULL) return(-1);
|
|
|
|
|
|
|
|
if(value == NULL) return(-1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: SaveString(%s, %s, %s, %s)",
|
|
|
|
|
|
|
|
file, section, keyword, value);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filepos = INIRemoveExt(file, inname);
|
|
|
|
|
|
|
|
for(i = 0; i <= filepos; i++) outname[i] = inname[i];
|
|
|
|
|
|
|
|
INIAddInExt(inname, filepos);
|
|
|
|
|
|
|
|
INIAddOutExt(outname, filepos);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filepos = 0;
|
|
|
|
|
|
|
|
infile = ActualFileOpenForRead(inname);
|
|
|
|
|
|
|
|
if(infile == ACTUALHANDLENULL) {
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: creating new file");
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
outfile = ActualFileOpenForWrite(inname);
|
|
|
|
|
|
|
|
if(outfile == ACTUALHANDLENULL) return(-1); // Just a bad name? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(templine, "[%s]\r\n", section);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0)) i++;
|
|
|
|
|
|
|
|
retval = ActualFileWrite(outfile, i, templine);
|
|
|
|
|
|
|
|
if(retval < i) {
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(inname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing it out? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(templine, "%s=%s\r\n", keyword, value);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0)) i++;
|
|
|
|
|
|
|
|
retval = ActualFileWrite(outfile, i, templine);
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
if(retval < i) {
|
|
|
|
|
|
|
|
ActualFileDelete(inname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing it out? Abort.
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
} // ENDIF- No input file? Create a brand new .ini file then.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = INIFindSection(infile, section);
|
|
|
|
|
|
|
|
if(retval < 0) {
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: creating new section");
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
outfile = ActualFileOpenForWrite(outname);
|
|
|
|
|
|
|
|
if(outfile == ACTUALHANDLENULL) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Couldn't open a temp file? Abort
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ActualFileSeek(infile, 0); // Move ini to beginning of file...
|
|
|
|
|
|
|
|
INICopy(infile, outfile, 0x0FFFFFFF); // Copy the whole file out...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(templine, "\r\n[%s]\r\n", section);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0)) i++;
|
|
|
|
|
|
|
|
retval = ActualFileWrite(outfile, i, templine);
|
|
|
|
|
|
|
|
if(retval < i) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing it out? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(templine, "%s=%s\r\n", keyword, value);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0)) i++;
|
|
|
|
|
|
|
|
retval = ActualFileWrite(outfile, i, templine);
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
if(retval < i) {
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing it out? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ActualFileDelete(inname);
|
|
|
|
|
|
|
|
ActualFileRename(outname, inname);
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
} // ENDIF- Couldn't find the section? Make a new one!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filepos = retval;
|
|
|
|
|
|
|
|
ActualFileSeek(infile, filepos);
|
|
|
|
|
|
|
|
filepos += INIReadLine(infile, templine); // Get section line's byte count
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = INIFindKeyword(infile, keyword, NULL);
|
|
|
|
|
|
|
|
if(retval < 0) {
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: creating new keyword");
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
ActualFileSeek(infile, filepos);
|
|
|
|
|
|
|
|
retval = INIReadLine(infile, templine);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++;
|
|
|
|
|
|
|
|
while((retval > 0) && (templine[i] == '=')) {
|
|
|
|
|
|
|
|
filepos += retval;
|
|
|
|
|
|
|
|
retval = INIReadLine(infile, templine);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++;
|
|
|
|
|
|
|
|
} // ENDWHILE- skimming to the bottom of the section
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
outfile = ActualFileOpenForWrite(outname);
|
|
|
|
|
|
|
|
if(outfile == ACTUALHANDLENULL) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Couldn't open a temp file? Abort
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ActualFileSeek(infile, 0);
|
|
|
|
|
|
|
|
retval = INICopy(infile, outfile, filepos);
|
|
|
|
|
|
|
|
if(retval > 0) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing everything up to keyword? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(templine, "%s=%s\r\n", keyword, value);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0)) i++;
|
|
|
|
|
|
|
|
retval = ActualFileWrite(outfile, i, templine);
|
|
|
|
|
|
|
|
if(retval < i) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing it out? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: replacing keyword");
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
filepos += retval; // Position just before old version of keyword
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
outfile = ActualFileOpenForWrite(outname);
|
|
|
|
|
|
|
|
if(outfile == ACTUALHANDLENULL) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Couldn't open a temp file? Abort
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ActualFileSeek(infile, 0);
|
|
|
|
|
|
|
|
retval = INICopy(infile, outfile, filepos);
|
|
|
|
|
|
|
|
if(retval > 0) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing everything up to keyword? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INIReadLine(infile, templine); // Read past old keyword/value...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Replace with new value
|
|
|
|
|
|
|
|
sprintf(templine, "%s=%s\r\n", keyword, value);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0)) i++;
|
|
|
|
|
|
|
|
retval = ActualFileWrite(outfile, i, templine);
|
|
|
|
|
|
|
|
if(retval < i) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing it out? Abort.
|
|
|
|
|
|
|
|
} // ENDIF- Need to add a new keyword?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(inname);
|
|
|
|
|
|
|
|
ActualFileRename(outname, inname);
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
} // END INISaveString()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int INILoadString(char *file, char *section, char *keyword, char *buffer) {
|
|
|
|
|
|
|
|
char inname[INIMAXLEN+1];
|
|
|
|
|
|
|
|
int filepos;
|
|
|
|
|
|
|
|
ACTUALHANDLE infile;
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(file == NULL) return(-1);
|
|
|
|
|
|
|
|
if(section == NULL) return(-1);
|
|
|
|
|
|
|
|
if(keyword == NULL) return(-1);
|
|
|
|
|
|
|
|
if(buffer == NULL) return(-1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: LoadString(%s, %s, %s)",
|
|
|
|
|
|
|
|
file, section, keyword);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filepos = INIRemoveExt(file, inname);
|
|
|
|
|
|
|
|
INIAddInExt(inname, filepos);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filepos = 0;
|
|
|
|
|
|
|
|
infile = ActualFileOpenForRead(inname);
|
|
|
|
|
|
|
|
if(infile == ACTUALHANDLENULL) return(-1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = INIFindSection(infile, section);
|
|
|
|
|
|
|
|
if(retval < 0) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Didn't find it? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = INIFindKeyword(infile, keyword, buffer);
|
|
|
|
|
|
|
|
if(retval < 0) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Didn't find it? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
} // END INILoadString()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int INIRemove(char *file, char *section, char *keyword) {
|
|
|
|
|
|
|
|
char inname[INIMAXLEN+1];
|
|
|
|
|
|
|
|
char outname[INIMAXLEN+1];
|
|
|
|
|
|
|
|
int filepos;
|
|
|
|
|
|
|
|
ACTUALHANDLE infile;
|
|
|
|
|
|
|
|
ACTUALHANDLE outfile;
|
|
|
|
|
|
|
|
char templine[INIMAXLEN+1];
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(file == NULL) return(-1);
|
|
|
|
|
|
|
|
if(section == NULL) return(-1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: Remove(%s, %s, %s)",
|
|
|
|
|
|
|
|
file, section, keyword);
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filepos = INIRemoveExt(file, inname);
|
|
|
|
|
|
|
|
for(i = 0; i <= filepos; i++) outname[i] = inname[i];
|
|
|
|
|
|
|
|
INIAddInExt(inname, filepos);
|
|
|
|
|
|
|
|
INIAddOutExt(outname, filepos);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
infile = ActualFileOpenForRead(inname);
|
|
|
|
|
|
|
|
if(infile == ACTUALHANDLENULL) return(-1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = INIFindSection(infile, section);
|
|
|
|
|
|
|
|
if(retval == -1) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Couldn't even find the section? Abort
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filepos = retval;
|
|
|
|
|
|
|
|
if(keyword == NULL) {
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: removing section");
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
outfile = ActualFileOpenForWrite(outname);
|
|
|
|
|
|
|
|
if(outfile == ACTUALHANDLENULL) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Couldn't open a temp file? Abort
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ActualFileSeek(infile, 0);
|
|
|
|
|
|
|
|
retval = INICopy(infile, outfile, filepos);
|
|
|
|
|
|
|
|
if(retval > 0) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing everything up to the section? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
templine[0] = 0;
|
|
|
|
|
|
|
|
retval = 1;
|
|
|
|
|
|
|
|
while((retval > 0) && (templine[0] != '[')) {
|
|
|
|
|
|
|
|
retval = INIReadLine(infile, templine);
|
|
|
|
|
|
|
|
} // ENDWHILE- Read to the start of the next section... or EOF.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(templine[0] == '[') {
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while((i < INIMAXLEN) && (templine[i] != 0)) i++;
|
|
|
|
|
|
|
|
retval = ActualFileWrite(outfile, i, templine);
|
|
|
|
|
|
|
|
if(retval < i) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing it out? Abort.
|
|
|
|
|
|
|
|
} // ENDIF- Are there other sections after this one? Save them then.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
filepos = retval;
|
|
|
|
|
|
|
|
ActualFileSeek(infile, filepos);
|
|
|
|
|
|
|
|
filepos += INIReadLine(infile, templine); // Get section line's byte count
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = INIFindKeyword(infile, keyword, NULL);
|
|
|
|
|
|
|
|
if(retval == -1) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Couldn't find the keyword? Abort
|
|
|
|
|
|
|
|
filepos += retval;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VERBOSE_FUNCTION_INI
|
|
|
|
|
|
|
|
PrintLog("CDVDiso ini: removing keyword");
|
|
|
|
|
|
|
|
#endif /* VERBOSE_FUNCTION_INI */
|
|
|
|
|
|
|
|
outfile = ActualFileOpenForWrite(outname);
|
|
|
|
|
|
|
|
if(outfile == ACTUALHANDLENULL) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Couldn't open a temp file? Abort
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ActualFileSeek(infile, 0);
|
|
|
|
|
|
|
|
retval = INICopy(infile, outfile, filepos);
|
|
|
|
|
|
|
|
if(retval > 0) {
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(outname);
|
|
|
|
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
} // ENDIF- Trouble writing everything up to keyword? Abort.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INIReadLine(infile, templine); // Read (and discard) the keyword line
|
|
|
|
|
|
|
|
} // ENDIF- Wipe out the whole section? Or just a keyword?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file
|
|
|
|
|
|
|
|
ActualFileClose(infile);
|
|
|
|
|
|
|
|
infile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileClose(outfile);
|
|
|
|
|
|
|
|
outfile = ACTUALHANDLENULL;
|
|
|
|
|
|
|
|
ActualFileDelete(inname);
|
|
|
|
|
|
|
|
ActualFileRename(outname, inname);
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
} // END INIRemove()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int INISaveUInt(char *file, char *section, char *keyword, unsigned int value) {
|
|
|
|
|
|
|
|
char numvalue[INIMAXLEN+1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(numvalue, "%u", value);
|
|
|
|
|
|
|
|
return(INISaveString(file, section, keyword, numvalue));
|
|
|
|
|
|
|
|
} // END INISaveUInt()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer) {
|
|
|
|
|
|
|
|
char numvalue[INIMAXLEN+1];
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
unsigned int value;
|
|
|
|
|
|
|
|
// unsigned int sign; // Not needed in unsigned numbers
|
|
|
|
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(buffer == NULL) return(-1);
|
|
|
|
|
|
|
|
*(buffer) = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = INILoadString(file, section, keyword, numvalue);
|
|
|
|
|
|
|
|
if(retval < 0) return(retval);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
value = 0;
|
|
|
|
|
|
|
|
// sign = 1; // Start positive
|
|
|
|
|
|
|
|
pos = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Note: skip leading spaces? (Shouldn't have to, I hope)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if(numvalue[pos] == '-') {
|
|
|
|
|
|
|
|
// pos++;
|
|
|
|
|
|
|
|
// sign = -1;
|
|
|
|
|
|
|
|
// } // ENDIF- Negative sign check
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while((pos < INIMAXLEN) && (numvalue[pos] != 0)) {
|
|
|
|
|
|
|
|
if(value > (0xFFFFFFFF / 10)) return(-1); // Overflow?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if((numvalue[pos] >= '0') && (numvalue[pos] <= '9')) {
|
|
|
|
|
|
|
|
value *= 10;
|
|
|
|
|
|
|
|
value += numvalue[pos] - '0';
|
|
|
|
|
|
|
|
pos++;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
numvalue[pos] = 0;
|
|
|
|
|
|
|
|
} // ENDIF- Add a digit in? Or stop searching for digits?
|
|
|
|
|
|
|
|
} // ENDWHILE- Adding digits of info to our ever-increasing value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// value *= sign
|
|
|
|
|
|
|
|
*(buffer) = value;
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
} // END INILoadUInt()
|
|
|
|
|