2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "sfzparser.h"
26 struct sfz_parser_state
28 struct sfz_parser_client
*client
;
29 gboolean (*handler
)(struct sfz_parser_state
*state
, int ch
);
34 int key_start
, key_end
;
35 int value_start
, value_end
;
39 static gboolean
handle_char(struct sfz_parser_state
*state
, int ch
);
41 static void unexpected_char(struct sfz_parser_state
*state
, int ch
)
43 g_set_error(state
->error
, CBOX_SFZPARSER_ERROR
, CBOX_SFZ_PARSER_ERROR_INVALID_CHAR
, "Unexpected character '%c' (%d)", ch
, ch
);
46 static gboolean
handle_header(struct sfz_parser_state
*state
, int ch
)
48 if (ch
>= 'a' && ch
<= 'z')
52 char *token
= g_strndup(state
->buf
+ state
->token_start
, state
->pos
- 1 - state
->token_start
);
53 gboolean result
= state
->client
->token(state
->client
, token
, state
->error
);
55 state
->handler
= handle_char
;
58 unexpected_char(state
, ch
);
62 static void scan_for_value(struct sfz_parser_state
*state
)
64 state
->value_start
= state
->pos
;
65 while(state
->pos
< state
->len
)
67 if (state
->pos
< state
->len
+ 2 && state
->buf
[state
->pos
] == '/' && state
->buf
[state
->pos
+ 1] == '/')
69 state
->value_end
= state
->pos
;
70 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
73 while (state
->pos
< state
->len
&& state
->buf
[state
->pos
] != '\r' && state
->buf
[state
->pos
] != '\n')
77 int ch
= state
->buf
[state
->pos
];
78 if (ch
== 0 || ch
== '\r' || ch
== '\n' || ch
== '<')
80 state
->value_end
= state
->pos
;
81 // remove spaces before next key
82 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
88 state
->value_end
= state
->pos
;
90 while(state
->value_end
> state
->value_start
&& !isspace(state
->buf
[state
->value_end
- 1]))
92 // remove spaces before next key
93 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
95 state
->pos
= state
->value_end
;
100 state
->value_end
= state
->pos
;
101 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
105 static gboolean
handle_key(struct sfz_parser_state
*state
, int ch
)
107 if (isalpha(ch
) || isdigit(ch
) || ch
== '_')
111 state
->key_end
= state
->pos
- 1;
112 scan_for_value(state
);
114 gchar
*key
= g_strndup(state
->buf
+ state
->key_start
, state
->key_end
- state
->key_start
);
115 gchar
*value
= g_strndup(state
->buf
+ state
->value_start
, state
->value_end
- state
->value_start
);
116 gboolean result
= state
->client
->key_value(state
->client
, key
, value
);
119 state
->handler
= handle_char
;
122 unexpected_char(state
, ch
);
126 static gboolean
handle_char(struct sfz_parser_state
*state
, int ch
)
128 if (isalpha(ch
) || isdigit(ch
))
130 state
->key_start
= state
->pos
- 1;
131 state
->handler
= handle_key
;
146 state
->token_start
= state
->pos
;
147 state
->handler
= handle_header
;
150 unexpected_char(state
, ch
);
155 gboolean
load_sfz(const char *name
, struct sfz_parser_client
*c
, GError
**error
)
157 g_clear_error(error
);
158 FILE *f
= fopen(name
, "rb");
161 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (errno
), "Cannot open '%s'", name
);
169 unsigned char *buf
= malloc(len
+ 1);
171 if (fread(buf
, 1, len
, f
) != len
)
173 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (errno
), "Cannot read '%s'", name
);
178 gboolean result
= load_sfz_from_string((char *)buf
, len
, c
, error
);
183 gboolean
load_sfz_from_string(const char *buf
, int len
, struct sfz_parser_client
*c
, GError
**error
)
185 struct sfz_parser_state s
;
186 s
.filename
= "<inline>";
188 s
.handler
= handle_char
;
194 if (len
>= 3 && buf
[0] == 0xEF && buf
[1] == 0xBB && buf
[2] == 0xBF)
199 while(s
.pos
< len
&& s
.handler
!= NULL
)
201 if (s
.pos
< len
+ 2 && buf
[s
.pos
] == '/' && buf
[s
.pos
+ 1] == '/')
204 while (s
.pos
< len
&& buf
[s
.pos
] != '\r' && buf
[s
.pos
] != '\n')
208 if (!(*s
.handler
)(&s
, buf
[s
.pos
++]))
213 if (!(*s
.handler
)(&s
, -1))
220 GQuark
cbox_sfz_parser_error_quark(void)
222 return g_quark_from_string("cbox-sfz-parser-error-quark");