summaryrefslogtreecommitdiff
path: root/Source/Core/Common/Src/SysConf.cpp
blob: dbac407dc79db29b9c1c464b49915e9b07c5dff0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright (C) 2003 Dolphin Project.

// 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, version 2.0.

// 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 2.0 for more details.

// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/

// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/

#include "FileUtil.h"
#include "SysConf.h"

SysConf::SysConf()
: m_IsValid(false)
{
	if (LoadFromFile(File::GetUserPath(F_WIISYSCONF_IDX)))
		m_IsValid = true;
}

SysConf::~SysConf()
{
	if (!m_IsValid)
		return;

	Save();

	for (size_t i = 0; i < m_Entries.size() - 1; i++)
	{
		delete [] m_Entries.at(i).data;
		m_Entries.at(i).data = NULL;
	}
}

bool SysConf::LoadFromFile(const char *filename)
{
	// Basic check
	u64 size = File::GetSize(filename);
	if (size == 0)
		return false; //most likely: file does not exist
	if (size != SYSCONF_SIZE)
	{
		PanicAlert("Your SYSCONF file is the wrong size - should be 0x%04x (but is 0x%04x)", 
			SYSCONF_SIZE, size);
		return false;
	}
	FILE* f = fopen(filename, "rb");

	if (f == NULL)
		return false;
	bool result = LoadFromFileInternal(f);
	if (result)
	{
		// OK, done!
		m_Filename = filename;
	}
	fclose(f);
	return result;
}

bool SysConf::LoadFromFileInternal(FILE *f)
{
	// Fill in infos
	if (fread(&m_Header.version, sizeof(m_Header.version), 1, f) != 1) return false;
	if (fread(&m_Header.numEntries, sizeof(m_Header.numEntries), 1, f) != 1) return false;
	m_Header.numEntries = Common::swap16(m_Header.numEntries) + 1;

	for (u16 index = 0; index < m_Header.numEntries; index++)
	{
		SSysConfEntry tmpEntry;
		if (fread(&tmpEntry.offset, sizeof(tmpEntry.offset), 1, f) != 1) return false;
		tmpEntry.offset = Common::swap16(tmpEntry.offset);
		m_Entries.push_back(tmpEntry);
	}

	// Last offset is an invalid entry. We ignore it throughout this class
	for (size_t i = 0; i < m_Entries.size() - 1; i++)
	{
		SSysConfEntry& curEntry = m_Entries.at(i);
		if (fseek(f, curEntry.offset, SEEK_SET) != 0) return false;

		u8 description = 0;
		if (fread(&description, sizeof(description), 1, f) != 1) return false;
		// Data type
		curEntry.type = (SysconfType)((description & 0xe0) >> 5);
		// Length of name in bytes - 1
		curEntry.nameLength = (description & 0x1f) + 1;
		// Name
		if (fread(&curEntry.name, curEntry.nameLength, 1, f) != 1) return false;
		curEntry.name[curEntry.nameLength] = '\0';
		// Get length of data
		curEntry.dataLength = 0;
		switch (curEntry.type)
		{
		case Type_BigArray:
			if (fread(&curEntry.dataLength, 2, 1, f) != 1) return false;
			curEntry.dataLength = Common::swap16(curEntry.dataLength);
			break;
		case Type_SmallArray:
			if (fread(&curEntry.dataLength, 1, 1, f) != 1) return false;
			break;
		case Type_Byte:
		case Type_Bool:
			curEntry.dataLength = 1;
			break;
		case Type_Short:
			curEntry.dataLength = 2;
			break;
		case Type_Long:
			curEntry.dataLength = 4;
			break;
		default:
			PanicAlert("Unknown entry type %i in SYSCONF (%s@%x)!",
				curEntry.type, curEntry.name, curEntry.offset);
			return false;
		}
		// Fill in the actual data
		if (curEntry.dataLength)
		{
			curEntry.data = new u8[curEntry.dataLength];
			if (fread(curEntry.data, curEntry.dataLength, 1, f) != 1) return false;
		}
	}

	return true;
}

bool SysConf::SaveToFile(const char *filename)
{
	FILE *f = fopen(filename, "r+b");

	if (f == NULL)
		return false;

	for (size_t i = 0; i < m_Entries.size() - 1; i++)
	{
		// Seek to after the name of this entry
		if (fseek(f, m_Entries.at(i).offset + m_Entries.at(i).nameLength + 1, SEEK_SET) != 0) return false;
		// We may have to write array length value...
		if (m_Entries.at(i).type == Type_BigArray)
		{
			u16 tmpDataLength = Common::swap16(m_Entries.at(i).dataLength);
			if (fwrite(&tmpDataLength, 2, 1, f) != 1) return false;
		}
		else if (m_Entries.at(i).type == Type_SmallArray)
		{
			if (fwrite(&m_Entries.at(i).dataLength, 1, 1, f) != 1) return false;
		}
		// Now write the actual data
		if (fwrite(m_Entries.at(i).data, m_Entries.at(i).dataLength, 1, f) != 1) return false;
	}

	fclose(f);
	return true;
}

bool SysConf::Save()
{
	if (!m_IsValid)
		return false;
	return SaveToFile(m_Filename.c_str());
}