Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/emulator/xnes/snes9x/conffile.cpp
28515 views
1
/***********************************************************************************
2
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4
(c) Copyright 1996 - 2002 Gary Henderson ([email protected]),
5
Jerremy Koot ([email protected])
6
7
(c) Copyright 2002 - 2004 Matthew Kendora
8
9
(c) Copyright 2002 - 2005 Peter Bortas ([email protected])
10
11
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13
(c) Copyright 2001 - 2006 John Weidman ([email protected])
14
15
(c) Copyright 2002 - 2006 funkyass ([email protected]),
16
Kris Bleakley ([email protected])
17
18
(c) Copyright 2002 - 2010 Brad Jorsch ([email protected]),
19
Nach ([email protected]),
20
21
(c) Copyright 2002 - 2011 zones ([email protected])
22
23
(c) Copyright 2006 - 2007 nitsuja
24
25
(c) Copyright 2009 - 2011 BearOso,
26
OV2
27
28
29
BS-X C emulator code
30
(c) Copyright 2005 - 2006 Dreamer Nom,
31
zones
32
33
C4 x86 assembler and some C emulation code
34
(c) Copyright 2000 - 2003 _Demo_ ([email protected]),
35
Nach,
36
zsKnight ([email protected])
37
38
C4 C++ code
39
(c) Copyright 2003 - 2006 Brad Jorsch,
40
Nach
41
42
DSP-1 emulator code
43
(c) Copyright 1998 - 2006 _Demo_,
44
Andreas Naive ([email protected]),
45
Gary Henderson,
46
Ivar ([email protected]),
47
John Weidman,
48
Kris Bleakley,
49
Matthew Kendora,
50
Nach,
51
neviksti ([email protected])
52
53
DSP-2 emulator code
54
(c) Copyright 2003 John Weidman,
55
Kris Bleakley,
56
Lord Nightmare ([email protected]),
57
Matthew Kendora,
58
neviksti
59
60
DSP-3 emulator code
61
(c) Copyright 2003 - 2006 John Weidman,
62
Kris Bleakley,
63
Lancer,
64
z80 gaiden
65
66
DSP-4 emulator code
67
(c) Copyright 2004 - 2006 Dreamer Nom,
68
John Weidman,
69
Kris Bleakley,
70
Nach,
71
z80 gaiden
72
73
OBC1 emulator code
74
(c) Copyright 2001 - 2004 zsKnight,
75
pagefault ([email protected]),
76
Kris Bleakley
77
Ported from x86 assembler to C by sanmaiwashi
78
79
SPC7110 and RTC C++ emulator code used in 1.39-1.51
80
(c) Copyright 2002 Matthew Kendora with research by
81
zsKnight,
82
John Weidman,
83
Dark Force
84
85
SPC7110 and RTC C++ emulator code used in 1.52+
86
(c) Copyright 2009 byuu,
87
neviksti
88
89
S-DD1 C emulator code
90
(c) Copyright 2003 Brad Jorsch with research by
91
Andreas Naive,
92
John Weidman
93
94
S-RTC C emulator code
95
(c) Copyright 2001 - 2006 byuu,
96
John Weidman
97
98
ST010 C++ emulator code
99
(c) Copyright 2003 Feather,
100
John Weidman,
101
Kris Bleakley,
102
Matthew Kendora
103
104
Super FX x86 assembler emulator code
105
(c) Copyright 1998 - 2003 _Demo_,
106
pagefault,
107
zsKnight
108
109
Super FX C emulator code
110
(c) Copyright 1997 - 1999 Ivar,
111
Gary Henderson,
112
John Weidman
113
114
Sound emulator code used in 1.5-1.51
115
(c) Copyright 1998 - 2003 Brad Martin
116
(c) Copyright 1998 - 2006 Charles Bilyue'
117
118
Sound emulator code used in 1.52+
119
(c) Copyright 2004 - 2007 Shay Green ([email protected])
120
121
SH assembler code partly based on x86 assembler code
122
(c) Copyright 2002 - 2004 Marcus Comstedt ([email protected])
123
124
2xSaI filter
125
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
126
127
HQ2x, HQ3x, HQ4x filters
128
(c) Copyright 2003 Maxim Stepin ([email protected])
129
130
NTSC filter
131
(c) Copyright 2006 - 2007 Shay Green
132
133
GTK+ GUI code
134
(c) Copyright 2004 - 2011 BearOso
135
136
Win32 GUI code
137
(c) Copyright 2003 - 2006 blip,
138
funkyass,
139
Matthew Kendora,
140
Nach,
141
nitsuja
142
(c) Copyright 2009 - 2011 OV2
143
144
Mac OS GUI code
145
(c) Copyright 1998 - 2001 John Stiles
146
(c) Copyright 2001 - 2011 zones
147
148
149
Specific ports contains the works of other authors. See headers in
150
individual files.
151
152
153
Snes9x homepage: http://www.snes9x.com/
154
155
Permission to use, copy, modify and/or distribute Snes9x in both binary
156
and source form, for non-commercial purposes, is hereby granted without
157
fee, providing that this license information and copyright notice appear
158
with all copies and any derived work.
159
160
This software is provided 'as-is', without any express or implied
161
warranty. In no event shall the authors be held liable for any damages
162
arising from the use of this software or it's derivatives.
163
164
Snes9x is freeware for PERSONAL USE only. Commercial users should
165
seek permission of the copyright holders first. Commercial use includes,
166
but is not limited to, charging money for Snes9x or software derived from
167
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
168
using Snes9x as a promotion for your commercial product.
169
170
The copyright holders request that bug fixes and improvements to the code
171
should be forwarded to them so everyone can benefit from the modifications
172
in future versions.
173
174
Super NES and Super Nintendo Entertainment System are trademarks of
175
Nintendo Co., Limited and its subsidiary companies.
176
***********************************************************************************/
177
178
179
#include <stdio.h>
180
#include <time.h>
181
#include <string.h>
182
#include <string>
183
184
#include "conffile.h"
185
186
#ifdef __WIN32__
187
#define snprintf _snprintf // needs ANSI compliant name
188
#endif
189
190
#define SORT_SECTIONS_BY_SIZE // output
191
192
using namespace std;
193
194
bool ConfigFile::defaultAutoAdd = false;
195
bool ConfigFile::niceAlignment = false;
196
bool ConfigFile::showComments = true;
197
bool ConfigFile::alphaSort = true;
198
bool ConfigFile::timeSort = false;
199
static ConfigFile* curConfigFile = NULL; // for section_then_key_less
200
201
ConfigFile::ConfigFile(void) {
202
Clear();
203
}
204
205
void ConfigFile::Clear(void){
206
data.clear();
207
sectionSizes.ClearSections();
208
linectr = 0;
209
}
210
211
bool ConfigFile::LoadFile(const char *filename){
212
STREAM s;
213
bool ret=false;
214
const char *n, *n2;
215
216
if((s=OPEN_STREAM(filename, "r"))){
217
n=filename;
218
n2=strrchr(n, '/'); if(n2!=NULL) n=n2+1;
219
n2=strrchr(n, '\\'); if(n2!=NULL) n=n2+1;
220
LoadFile(new fReader(s), n);
221
CLOSE_STREAM(s);
222
ret = true;
223
} else {
224
fprintf(stderr, "Couldn't open conffile ");
225
perror(filename);
226
}
227
return ret;
228
}
229
230
231
void ConfigFile::LoadFile(Reader *r, const char *name){
232
curConfigFile = this;
233
string l, key, val;
234
string section;
235
string comment;
236
int i, line, line2;
237
bool eof;
238
239
line=line2=0;
240
section.clear();
241
do {
242
line=line2++;
243
l=r->getline(eof);
244
ConfigEntry::trim(l);
245
if(l.size()==0) continue;
246
247
if(l[0]=='#' || l[0]==';'){
248
// comment
249
continue;
250
}
251
252
if(l[0]=='['){
253
if(*l.rbegin()!=']'){
254
if(name) fprintf(stderr, "%s:", name);
255
fprintf(stderr, "[%d]: Ignoring invalid section header\n", line);
256
continue;
257
}
258
section.assign(l, 1, l.size()-2);
259
continue;
260
}
261
262
while(*l.rbegin()=='\\'){
263
l.erase(l.size()-1);
264
line2++;
265
val=r->getline(eof);
266
if(eof){
267
fprintf(stderr, "Unexpected EOF reading config file");
268
if(name) fprintf(stderr, " '%s'", name);
269
fprintf(stderr, "\n");
270
return;
271
}
272
ConfigEntry::trim(val);
273
l+=val;
274
}
275
i=l.find('=');
276
if(i<0){
277
if(name) fprintf(stderr, "%s:", name);
278
fprintf(stderr, "[%d]: Ignoring invalid entry\n", line);
279
continue;
280
}
281
key=l.substr(0,i); ConfigEntry::trim(key);
282
val=l.substr(i+1); comment = ConfigEntry::trimCommented(val);
283
if(val.size() > 0 && val[0]=='"' && *val.rbegin()=='"') val=val.substr(1, val.size()-2);
284
285
ConfigEntry e(line, section, key, val);
286
e.comment = comment;
287
if(data.erase(e))
288
sectionSizes.DecreaseSectionSize(e.section);
289
data.insert(e);
290
sectionSizes.IncreaseSectionSize(e.section);
291
} while(!eof);
292
curConfigFile = NULL;
293
}
294
295
bool ConfigFile::SaveTo(const char *filename){
296
string section;
297
FILE *fp;
298
299
if((fp=fopen(filename, "w"))==NULL){
300
fprintf(stderr, "Couldn't write conffile ");
301
perror(filename);
302
return false;
303
}
304
305
curConfigFile = this;
306
section.clear();
307
set<ConfigEntry, ConfigEntry::line_less> tmp;
308
fprintf(fp, "# Config file output by snes9x\n");
309
time_t t=time(NULL);
310
fprintf(fp, "# %s", ctime(&t));
311
312
#ifdef SORT_SECTIONS_BY_SIZE
313
std::set<ConfigEntry, ConfigEntry::section_then_key_less> data2;
314
for(set<ConfigEntry, ConfigEntry::key_less>::iterator k=data.begin(); k!=data.end(); k++){
315
ConfigEntry e (k->line, k->section, k->key, k->val); e.comment = k->comment;
316
data2.insert(e);
317
}
318
#else
319
#define data2 data
320
#define section_then_key_less key_less
321
#endif
322
323
for(set<ConfigEntry, ConfigEntry::section_then_key_less>::iterator j=data2.begin(); ; j++){
324
if(j==data2.end() || j->section!=section){
325
if(!tmp.empty()){
326
fprintf(fp, "\n[%s]\n", section.c_str());
327
unsigned int maxKeyLen=0, maxValLen=0; int maxLeftDiv=0; int maxRightDiv=-1;
328
if(niceAlignment){
329
for(set<ConfigEntry, ConfigEntry::line_less>::iterator i=tmp.begin(); i!=tmp.end(); i++){
330
int len3 = i->key.find_last_of(':');
331
maxRightDiv = MAX(maxRightDiv, len3);
332
len3 = i->key.length() - len3;
333
maxLeftDiv = MAX(maxLeftDiv, len3);
334
maxKeyLen = MAX(maxKeyLen, i->key.length()+3);
335
if(showComments){
336
string o=i->val; ConfigEntry::trim(o);
337
unsigned int len = o.length();
338
for(signed int j=len-1;j>=0;j--) if(o.at(j)=='#') len++;
339
if(o!=i->val) len+=2;
340
maxValLen = MAX(maxValLen, len);
341
}
342
}
343
if(maxValLen>48) maxValLen=48; // limit spacing
344
}
345
346
for(set<ConfigEntry, ConfigEntry::line_less>::iterator i=tmp.begin(); i!=tmp.end(); i++){
347
string o=i->val; ConfigEntry::trim(o);
348
if(o!=i->val) o="\""+i->val+"\"";
349
int off=0, len3=0;
350
for(;;){
351
int k=o.find('#',off);
352
if(k>=0){
353
o.insert(k,1,'#'); // re-double any comment characters
354
off=k+2;
355
if(off<(int)o.length()) continue;
356
}
357
break;
358
}
359
if(niceAlignment){
360
len3=i->key.find_last_of(':');
361
int len3sub=0;
362
if(len3 < maxRightDiv){
363
for(int j=len3;j<maxRightDiv;j++) fputc(' ',fp);
364
len3sub=maxRightDiv-len3;
365
len3 = maxRightDiv;
366
}
367
len3+=maxLeftDiv-i->key.length();
368
for(unsigned int j=i->key.length()+len3+3;j<maxKeyLen;j++) fputc(' ',fp);
369
fprintf(fp, "%s", i->key.c_str());
370
for(int j=0;j<len3-len3sub;j++) fputc(' ',fp);
371
fprintf(fp, " = %s", o.c_str());
372
} else
373
fprintf(fp, "%s = %s", i->key.c_str(), o.c_str());
374
375
if(showComments && !i->comment.empty()){
376
if(niceAlignment) for(unsigned int j=o.length();j<maxValLen;j++) fputc(' ',fp);
377
fprintf(fp, " # %s", i->comment.c_str());
378
}
379
fprintf(fp, "\n");
380
}
381
}
382
if(j==data2.end()) break;
383
section=j->section;
384
tmp.clear();
385
}
386
tmp.insert(*j);
387
}
388
curConfigFile = NULL;
389
390
#undef data2
391
#undef section_then_key_less
392
393
if(ferror(fp))
394
{
395
fp = fp;
396
}
397
398
fclose(fp);
399
return true;
400
}
401
402
403
/***********************************************/
404
405
string ConfigFile::Get(const char *key){
406
set<ConfigEntry, ConfigEntry::key_less>::iterator i;
407
i=data.find(ConfigEntry(key));
408
i->used=true;
409
return i->val;
410
}
411
bool ConfigFile::Has(const char *key){
412
return data.find(ConfigEntry(key))!=data.end();
413
}
414
415
// exists and isn't completely empty (any side-effects are intentional)
416
bool ConfigFile::Exists(const char *key){
417
const char* val = GetString(key, NULL);
418
return val && *val;
419
}
420
421
422
string ConfigFile::GetString(const char *key, string def){
423
if(!Exists(key))
424
return def;
425
return Get(key);
426
}
427
428
char *ConfigFile::GetString(const char *key, char *out, uint32 outlen){
429
if(!Exists(key)) return NULL;
430
ZeroMemory(out, outlen);
431
string o=Get(key);
432
if(outlen>0){
433
outlen--;
434
if(o.size()<outlen) outlen=o.size();
435
memcpy(out, o.data(), outlen);
436
}
437
return out;
438
}
439
440
const char *ConfigFile::GetString(const char *key, const char *def){
441
set<ConfigEntry, ConfigEntry::key_less>::iterator i;
442
i=data.find(ConfigEntry(key));
443
if(i==data.end())
444
{
445
if(defaultAutoAdd) SetString(key,""); //SetString(key, def?def:"");
446
return def;
447
}
448
i->used=true;
449
// This should be OK, until this key gets removed
450
const std::string &iVal = i->val;
451
return iVal.c_str();
452
}
453
454
char *ConfigFile::GetStringDup(const char *key, const char *def){
455
const char *c=GetString(key, def);
456
if(c==NULL) return NULL;
457
return strdup(c);
458
}
459
460
bool ConfigFile::SetString(const char *key, string val, const char *comment){
461
set<ConfigEntry, ConfigEntry::key_less>::iterator i;
462
bool ret=false;
463
bool found;
464
465
ConfigEntry e(key, val);
466
if(comment && *comment) e.comment = comment;
467
e.used=true;
468
469
i=data.find(e);
470
found=(i==data.end());
471
if(!found){
472
e.line=i->line;
473
data.erase(e);
474
sectionSizes.DecreaseSectionSize(e.section);
475
ret=true;
476
}
477
if((found && (!alphaSort || timeSort)) || (!alphaSort && timeSort))
478
e.line = linectr++;
479
480
data.insert(e);
481
sectionSizes.IncreaseSectionSize(e.section);
482
return ret;
483
}
484
485
int32 ConfigFile::GetInt(const char *key, int32 def, bool *bad){
486
if(bad) *bad=false;
487
if(!Exists(key))
488
return def;
489
char *c;
490
int32 i;
491
string o=Get(key);
492
i=strtol(o.c_str(), &c, 10);
493
if(c!=NULL && *c!='\0'){
494
i=def;
495
if(bad) *bad=true;
496
}
497
return i;
498
}
499
500
bool ConfigFile::SetInt(const char *key, int32 val, const char *comment){
501
char buf[20];
502
snprintf(buf, sizeof(buf), "%d", (int)val);
503
return SetString(key, buf, comment);
504
}
505
506
uint32 ConfigFile::GetUInt(const char *key, uint32 def, int base, bool *bad){
507
if(bad) *bad=false;
508
if(!Exists(key))
509
return def;
510
if(base!=8 && base!=10 && base!=16) base=0;
511
char *c;
512
uint32 i;
513
string o=Get(key);
514
i=strtol(o.c_str(), &c, base);
515
if(c!=NULL && *c!='\0'){
516
i=def;
517
if(bad) *bad=true;
518
}
519
return i;
520
}
521
522
bool ConfigFile::SetUInt(const char *key, uint32 val, int base, const char *comment){
523
char buf[20];
524
switch(base){
525
case 10:
526
default:
527
snprintf(buf, sizeof(buf), "%u", (unsigned int)val);
528
break;
529
case 8:
530
snprintf(buf, sizeof(buf), "%#o", (unsigned int)val);
531
break;
532
case 16:
533
snprintf(buf, sizeof(buf), "%#x", (unsigned int)val);
534
break;
535
}
536
return SetString(key, buf, comment);
537
}
538
539
bool ConfigFile::GetBool(const char *key, bool def, bool *bad){
540
if(bad) *bad=false;
541
if(!Exists(key))
542
return def;
543
string o=Get(key);
544
const char *c=o.c_str();
545
if(!strcasecmp(c, "true") || !strcasecmp(c, "1") || !strcasecmp(c, "yes") || !strcasecmp(c, "on")) return true;
546
if(!strcasecmp(c, "false") || !strcasecmp(c, "0") || !strcasecmp(c, "no") || !strcasecmp(c, "off")) return false;
547
if(bad) *bad=true;
548
return def;
549
}
550
551
bool ConfigFile::SetBool(const char *key, bool val, const char *true_val, const char *false_val, const char *comment){
552
return SetString(key, val?true_val:false_val, comment);
553
}
554
555
const char* ConfigFile::GetComment(const char *key)
556
{
557
set<ConfigEntry, ConfigEntry::key_less>::iterator i;
558
i=data.find(ConfigEntry(key));
559
if(i==data.end())
560
return NULL;
561
562
// This should be OK, until this key gets removed
563
const std::string &iCom = i->comment;
564
return iCom.c_str();
565
}
566
567
bool ConfigFile::DeleteKey(const char *key){
568
ConfigEntry e = ConfigEntry(key);
569
if(data.erase(e)) {
570
sectionSizes.DecreaseSectionSize(e.section);
571
return true;
572
}
573
return false;
574
}
575
576
/***********************************************/
577
578
bool ConfigFile::DeleteSection(const char *section){
579
set<ConfigEntry, ConfigEntry::key_less>::iterator s, e;
580
581
for(s=data.begin(); s!=data.end() && s->section!=section; s++) ;
582
if(s==data.end()) return false;
583
for(e=s; e!=data.end() && e->section==section; e++) ;
584
data.erase(s, e);
585
sectionSizes.DeleteSection(section);
586
return true;
587
}
588
589
ConfigFile::secvec_t ConfigFile::GetSection(const char *section){
590
secvec_t v;
591
set<ConfigEntry, ConfigEntry::key_less>::iterator i;
592
593
v.clear();
594
for(i=data.begin(); i!=data.end(); i++){
595
if(i->section!=section) continue;
596
v.push_back(std::pair<string,string>(i->key, i->val));
597
}
598
return v;
599
}
600
601
int ConfigFile::GetSectionSize(const std::string section){
602
return sectionSizes.GetSectionSize(section);
603
}
604
605
// Clears all key-value pairs that didn't receive a "Get" or "Exists" command
606
void ConfigFile::ClearUnused()
607
{
608
set<ConfigEntry, ConfigEntry::key_less>::iterator i;
609
again:
610
for(i=data.begin(); i!=data.end(); i++){
611
if(!i->used){
612
data.erase(i);
613
goto again;
614
}
615
}
616
}
617
618
void ConfigFile::ClearLines()
619
{
620
set<ConfigEntry, ConfigEntry::key_less>::iterator i;
621
for(i=data.begin(); i!=data.end(); i++){
622
*(const_cast<int*>(&i->line)) = -1;
623
}
624
}
625
626
bool ConfigFile::ConfigEntry::section_then_key_less::operator()(const ConfigEntry &a, const ConfigEntry &b) {
627
if(curConfigFile && a.section!=b.section){
628
const int sva = curConfigFile->GetSectionSize(a.section);
629
const int svb = curConfigFile->GetSectionSize(b.section);
630
if(sva<svb) return true;
631
if(sva>svb) return false;
632
return a.section<b.section;
633
}
634
return a.key<b.key;
635
}
636
637
638
void ConfigFile::SetDefaultAutoAdd(bool autoAdd)
639
{
640
defaultAutoAdd = autoAdd;
641
}
642
void ConfigFile::SetNiceAlignment(bool align)
643
{
644
niceAlignment = align;
645
}
646
void ConfigFile::SetShowComments(bool show)
647
{
648
showComments = show;
649
}
650
void ConfigFile::SetAlphaSort(bool sort)
651
{
652
alphaSort = sort;
653
}
654
void ConfigFile::SetTimeSort(bool sort)
655
{
656
timeSort = sort;
657
}
658
659