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 gboolean
handle_2ndslash(struct sfz_parser_state
*state
, int ch
)
43 if (ch
== '\r' || ch
== '\n')
45 state
->handler
= handle_char
;
46 state
->token_start
= state
->pos
;
52 static void unexpected_char(struct sfz_parser_state
*state
, int ch
)
54 g_set_error(state
->error
, CBOX_SFZPARSER_ERROR
, CBOX_SFZ_PARSER_ERROR_INVALID_CHAR
, "Unexpected character '%c' (%d)", ch
, ch
);
57 static gboolean
handle_postslash(struct sfz_parser_state
*state
, int ch
)
61 state
->handler
= handle_2ndslash
;
64 unexpected_char(state
, ch
);
68 static gboolean
handle_header(struct sfz_parser_state
*state
, int ch
)
70 if (ch
>= 'a' && ch
<= 'z')
74 if (!strncmp(state
->buf
+ state
->token_start
, "region", state
->pos
- 1 - state
->token_start
))
76 state
->client
->region(state
->client
);
79 if (!strncmp(state
->buf
+ state
->token_start
, "group", state
->pos
- 1 - state
->token_start
))
81 state
->client
->group(state
->client
);
85 gchar
*tmp
= g_strndup(state
->buf
+ state
->token_start
, state
->pos
- 1 - state
->token_start
);
86 g_set_error(state
->error
, CBOX_SFZPARSER_ERROR
, CBOX_SFZ_PARSER_ERROR_INVALID_HEADER
, "Unexpected header <%s>", tmp
);
90 state
->handler
= handle_char
;
93 unexpected_char(state
, ch
);
97 static void scan_for_value(struct sfz_parser_state
*state
)
99 state
->value_start
= state
->pos
;
102 int ch
= state
->buf
[state
->pos
];
103 if (ch
== 0 || ch
== '\r' || ch
== '\n' || ch
== '<')
105 state
->value_end
= state
->pos
;
106 // remove spaces before next key
107 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
113 state
->value_end
= state
->pos
;
115 while(state
->value_end
> state
->value_start
&& !isspace(state
->buf
[state
->value_end
- 1]))
117 // remove spaces before next key
118 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
120 state
->pos
= state
->value_end
;
127 static gboolean
handle_key(struct sfz_parser_state
*state
, int ch
)
129 if (isalpha(ch
) || isdigit(ch
) || ch
== '_')
133 state
->key_end
= state
->pos
- 1;
134 scan_for_value(state
);
136 gchar
*key
= g_strndup(state
->buf
+ state
->key_start
, state
->key_end
- state
->key_start
);
137 gchar
*value
= g_strndup(state
->buf
+ state
->value_start
, state
->value_end
- state
->value_start
);
138 gboolean result
= state
->client
->key_value(state
->client
, key
, value
);
141 state
->handler
= handle_char
;
144 unexpected_char(state
, ch
);
148 static gboolean
handle_char(struct sfz_parser_state
*state
, int ch
)
150 if (isalpha(ch
) || isdigit(ch
))
152 state
->key_start
= state
->pos
- 1;
153 state
->handler
= handle_key
;
168 state
->handler
= handle_postslash
;
171 state
->token_start
= state
->pos
;
172 state
->handler
= handle_header
;
175 unexpected_char(state
, ch
);
180 gboolean
load_sfz(const char *name
, struct sfz_parser_client
*c
, GError
**error
)
182 g_clear_error(error
);
183 FILE *f
= fopen(name
, "rb");
186 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (errno
), "Cannot open '%s'", name
);
194 unsigned char *buf
= malloc(len
+ 1);
196 if (fread(buf
, 1, len
, f
) != len
)
198 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (errno
), "Cannot read '%s'", name
);
203 gboolean result
= load_sfz_from_string((char *)buf
, len
, c
, error
);
208 gboolean
load_sfz_from_string(const char *buf
, int len
, struct sfz_parser_client
*c
, GError
**error
)
210 struct sfz_parser_state s
;
211 s
.filename
= "<inline>";
213 s
.handler
= handle_char
;
218 if (len
>= 3 && buf
[0] == 0xEF && buf
[1] == 0xBB && buf
[2] == 0xBF)
223 while(s
.pos
< len
&& s
.handler
!= NULL
)
225 if (!(*s
.handler
)(&s
, buf
[s
.pos
++]))
230 if (!(*s
.handler
)(&s
, -1))
237 GQuark
cbox_sfz_parser_error_quark(void)
239 return g_quark_from_string("cbox-sfz-parser-error-quark");