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"
27 struct sfz_parser_state
29 struct sfz_parser_client
*client
;
30 gboolean (*handler
)(struct sfz_parser_state
*state
, int ch
);
35 int key_start
, key_end
;
36 int value_start
, value_end
;
40 static gboolean
handle_char(struct sfz_parser_state
*state
, int ch
);
42 static void unexpected_char(struct sfz_parser_state
*state
, int ch
)
44 g_set_error(state
->error
, CBOX_SFZPARSER_ERROR
, CBOX_SFZ_PARSER_ERROR_INVALID_CHAR
, "Unexpected character '%c' (%d)", ch
, ch
);
47 static gboolean
handle_header(struct sfz_parser_state
*state
, int ch
)
49 if (ch
>= 'a' && ch
<= 'z')
53 char *token
= g_strndup(state
->buf
+ state
->token_start
, state
->pos
- 1 - state
->token_start
);
54 gboolean result
= state
->client
->token(state
->client
, token
, state
->error
);
56 state
->handler
= handle_char
;
59 unexpected_char(state
, ch
);
63 static void scan_for_value(struct sfz_parser_state
*state
)
65 state
->value_start
= state
->pos
;
66 while(state
->pos
< state
->len
)
68 if (state
->pos
< state
->len
+ 2 && state
->buf
[state
->pos
] == '/' && state
->buf
[state
->pos
+ 1] == '/')
70 state
->value_end
= state
->pos
;
71 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
74 while (state
->pos
< state
->len
&& state
->buf
[state
->pos
] != '\r' && state
->buf
[state
->pos
] != '\n')
78 int ch
= state
->buf
[state
->pos
];
79 if (ch
== 0 || ch
== '\r' || ch
== '\n' || ch
== '<')
81 state
->value_end
= state
->pos
;
82 // remove spaces before next key
83 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
89 state
->value_end
= state
->pos
;
91 while(state
->value_end
> state
->value_start
&& !isspace(state
->buf
[state
->value_end
- 1]))
93 // remove spaces before next key
94 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
96 state
->pos
= state
->value_end
;
101 state
->value_end
= state
->pos
;
102 while(state
->value_end
> state
->value_start
&& isspace(state
->buf
[state
->value_end
- 1]))
106 static gboolean
handle_key(struct sfz_parser_state
*state
, int ch
)
108 if (isalpha(ch
) || isdigit(ch
) || ch
== '_')
112 state
->key_end
= state
->pos
- 1;
113 scan_for_value(state
);
115 gchar
*key
= g_strndup(state
->buf
+ state
->key_start
, state
->key_end
- state
->key_start
);
116 gchar
*value
= g_strndup(state
->buf
+ state
->value_start
, state
->value_end
- state
->value_start
);
117 gboolean result
= state
->client
->key_value(state
->client
, key
, value
);
120 state
->handler
= handle_char
;
123 unexpected_char(state
, ch
);
127 static gboolean
handle_char(struct sfz_parser_state
*state
, int ch
)
129 if (isalpha(ch
) || isdigit(ch
))
131 state
->key_start
= state
->pos
- 1;
132 state
->handler
= handle_key
;
147 state
->token_start
= state
->pos
;
148 state
->handler
= handle_header
;
151 unexpected_char(state
, ch
);
156 gboolean
load_sfz(const char *name
, struct cbox_tarfile
*tarfile
, struct sfz_parser_client
*c
, GError
**error
)
158 g_clear_error(error
);
163 struct cbox_taritem
*item
= cbox_tarfile_get_item_by_name(tarfile
, name
, TRUE
);
166 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (2), "Cannot find '%s' in the tarfile", name
);
169 int fd
= cbox_tarfile_openitem(tarfile
, item
);
172 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (errno
), "Cannot open '%s' in the tarfile", name
);
175 f
= fdopen(fd
, "rb");
179 f
= fopen(name
, "rb");
183 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (errno
), "Cannot open '%s'", name
);
189 fseek(f
, 0, SEEK_END
);
191 fseek(f
, 0, SEEK_SET
);
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
;
219 if (len
>= 3 && buf
[0] == 0xEF && buf
[1] == 0xBB && buf
[2] == 0xBF)
224 while(s
.pos
< len
&& s
.handler
!= NULL
)
226 if (s
.pos
< len
+ 2 && buf
[s
.pos
] == '/' && buf
[s
.pos
+ 1] == '/')
229 while (s
.pos
< len
&& buf
[s
.pos
] != '\r' && buf
[s
.pos
] != '\n')
233 if (!(*s
.handler
)(&s
, buf
[s
.pos
++]))
238 if (!(*s
.handler
)(&s
, -1))
245 GQuark
cbox_sfz_parser_error_quark(void)
247 return g_quark_from_string("cbox-sfz-parser-error-quark");