Spellforce-Spell-framework
Toggle main menu visibility
Loading...
Searching...
No Matches
sf_screens_loader.c
Go to the documentation of this file.
1
5
6
#include <ctype.h>
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <string.h>
10
11
#include "
sf_screens_loader.h
"
12
#include "
sf_building_loader.h
"
/* readfile() */
13
#include "
sf_wrappers.h
"
14
15
#define JSMN_STATIC
16
#define JSMN_PARENT_LINKS
17
#include "
jsmn.h
"
18
19
static
void
str_to_lower(
char
*str)
20
{
21
for
(
int
i = 0; str[i] !=
'\0'
; i++)
22
{
23
str[i] = (char)tolower((
unsigned
char
)str[i]);
24
}
25
}
26
28
static
int
skip_token_tree(
const
jsmntok_t
*tokens,
int
token_count,
int
index)
29
{
30
if
(index >= token_count)
31
{
32
return
index;
33
}
34
35
if
(tokens[index].type ==
JSMN_OBJECT
|| tokens[index].type ==
JSMN_ARRAY
)
36
{
37
int
children_count = tokens[index].
size
;
38
int
next_index = index + 1;
39
for
(
int
i = 0; i < children_count; i++)
40
{
41
if
(next_index >= token_count)
42
{
43
return
token_count;
44
}
45
if
(tokens[index].type ==
JSMN_OBJECT
)
46
{
47
next_index = skip_token_tree(tokens, token_count, next_index);
// key
48
next_index = skip_token_tree(tokens, token_count, next_index);
// value
49
}
50
else
51
{
52
next_index = skip_token_tree(tokens, token_count, next_index);
53
}
54
}
55
return
next_index;
56
}
57
58
return
index + 1;
59
}
60
61
// Copies a JSON string token's contents into a bounded buffer.
62
static
void
json_str(
const
char
*json,
const
jsmntok_t
*token,
char
*out,
size_t
out_size)
63
{
64
int
len = token->
end
- token->
start
;
65
if
(len >= (
int
)out_size)
66
{
67
len = (int)out_size - 1;
68
}
69
strncpy(out, json + token->
start
, len);
70
out[len] =
'\0'
;
71
}
72
73
bool
parse_screens_json_file
(
const
char
*path,
ScreenEntry
*out_entries,
74
int
max_entries,
int
*out_count)
75
{
76
*out_count = 0;
77
78
char
*json_string =
readfile
(path);
79
if
(json_string == NULL)
80
{
81
// readfile has already logged the reason.
82
return
false
;
83
}
84
85
jsmn_parser
parser;
86
jsmn_init
(&parser);
87
88
size_t
json_length = strlen(json_string);
89
int
token_count =
jsmn_parse
(&parser, json_string, json_length, NULL, 0);
90
if
(token_count < 1)
91
{
92
log_error
(
"screens.json is not valid JSON: %s"
, path);
93
log_debug
(
DEBUG_HIGH
, json_string);
94
free(json_string);
95
return
false
;
96
}
97
98
jsmntok_t
*tokens = (
jsmntok_t
*)calloc(token_count,
sizeof
(
jsmntok_t
));
99
if
(tokens == NULL)
100
{
101
log_error
(
"Unable to allocate %d JSON tokens for: %s"
, token_count, path);
102
free(json_string);
103
return
false
;
104
}
105
106
jsmn_init
(&parser);
107
token_count =
jsmn_parse
(&parser, json_string, json_length, tokens, token_count);
108
109
bool
success =
false
;
110
if
(token_count < 1)
111
{
112
log_error
(
"screens.json failed to tokenize: %s"
, path);
113
log_debug
(
DEBUG_HIGH
, json_string);
114
}
115
else
if
(tokens[0].type !=
JSMN_OBJECT
)
116
{
117
log_error
(
"screens.json must be a single JSON object of map_name : msb_file pairs"
);
118
}
119
else
120
{
121
int
pairs_to_process = tokens[0].
size
;
122
int
current_token_index = 1;
123
124
for
(
int
i = 0; i < pairs_to_process; i++)
125
{
126
if
(current_token_index + 1 >= token_count)
127
{
128
break
;
129
}
130
131
if
(*out_count >= max_entries)
132
{
133
log_error
(
"screens.json has more than %d entries, ignoring the rest"
, max_entries);
134
break
;
135
}
136
137
const
jsmntok_t
*key_token = &tokens[current_token_index];
138
const
jsmntok_t
*value_token = &tokens[current_token_index + 1];
139
140
if
(key_token->
type
!=
JSMN_STRING
|| value_token->
type
!=
JSMN_STRING
)
141
{
142
log_error
(
"screens.json entry %d is not a string:string pair, skipping"
, i);
143
}
144
else
145
{
146
ScreenEntry
*entry = &out_entries[*out_count];
147
json_str(json_string, key_token, entry->
map_name
,
sizeof
(entry->
map_name
));
148
json_str(json_string, value_token, entry->
msb_file
,
sizeof
(entry->
msb_file
));
149
str_to_lower(entry->
map_name
);
150
(*out_count)++;
151
}
152
153
/* Using skip_token_tree for safer json parsing. */
154
current_token_index = skip_token_tree(tokens, token_count, current_token_index);
// key
155
current_token_index = skip_token_tree(tokens, token_count, current_token_index);
// value
156
}
157
158
success =
true
;
159
}
160
161
free(tokens);
162
free(json_string);
163
return
success;
164
}
165
parse_screens_json_file
bool parse_screens_json_file(const char *path, ScreenEntry *out_entries, int max_entries, int *out_count)
Reads a screens.json: a single object of map_name : msb_file pairs.
Definition
sf_screens_loader.c:73
log_error
void log_error(const char *format,...)
Definition
sf_wrappers.c:153
log_debug
void log_debug(DebugLevel level, const char *format,...)
Definition
sf_wrappers.c:182
jsmn.h
JSMN_OBJECT
@ JSMN_OBJECT
Definition
jsmn.h:48
JSMN_ARRAY
@ JSMN_ARRAY
Definition
jsmn.h:49
JSMN_STRING
@ JSMN_STRING
Definition
jsmn.h:50
jsmn_init
void jsmn_init(jsmn_parser *parser)
Definition
jsmn.h:456
jsmn_parse
int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const unsigned int num_tokens)
Definition
jsmn.h:265
readfile
char * readfile(const char *path)
Definition
sf_building_loader.c:496
sf_building_loader.h
DEBUG_HIGH
@ DEBUG_HIGH
Definition
sf_general_structures.h:40
sf_screens_loader.h
sf_wrappers.h
ScreenEntry
One "map name -> loading screen mesh" pair.
Definition
sf_screens_loader.h:24
ScreenEntry::msb_file
char msb_file[128]
Definition
sf_screens_loader.h:26
ScreenEntry::map_name
char map_name[128]
Definition
sf_screens_loader.h:25
jsmn_parser
Definition
jsmn.h:83
jsmntok_t
Definition
jsmn.h:69
jsmntok_t::start
int start
Definition
jsmn.h:71
jsmntok_t::size
int size
Definition
jsmn.h:73
jsmntok_t::end
int end
Definition
jsmn.h:72
jsmntok_t::type
jsmntype_t type
Definition
jsmn.h:70
src
internal
core
sf_screens_loader.c
Generated by
1.17.0