struct bstr bstr_strip(struct bstr str) { str = bstr_lstrip(str); while (str.len && mp_isspace(str.start[str.len - 1])) str.len--; return str; }
// Skip whitespace and comments (assuming there are no line breaks) static bool skip_ws(bstr *s) { *s = bstr_lstrip(*s); if (bstr_startswith0(*s, "#")) s->len = 0; return s->len; }
static char *read_quoted(void *talloc_ctx, struct bstr *data) { *data = bstr_lstrip(*data); if (!eat_char(data, '"')) return NULL; int end = bstrchr(*data, '"'); if (end < 0) return NULL; struct bstr res = bstr_splice(*data, 0, end); *data = bstr_cut(*data, end + 1); return bstrto0(talloc_ctx, res); }
// Read a 2 digit unsigned decimal integer. // Return -1 on failure. static int read_int_2(struct bstr *data) { *data = bstr_lstrip(*data); if (data->len && data->start[0] == '-') return -1; struct bstr s = *data; int res = (int)bstrtoll(s, &s, 10); if (data->len == s.len || data->len - s.len > 2) return -1; *data = s; return res; }
double bstrtod(struct bstr str, struct bstr *rest) { str = bstr_lstrip(str); char buf[101]; int len = FFMIN(str.len, 100); memcpy(buf, str.start, len); buf[len] = 0; char *endptr; double r = strtod(buf, &endptr); if (rest) *rest = bstr_cut(str, endptr - buf); return r; }
long long bstrtoll(struct bstr str, struct bstr *rest, int base) { str = bstr_lstrip(str); char buf[51]; int len = FFMIN(str.len, 50); memcpy(buf, str.start, len); buf[len] = 0; char *endptr; long long r = strtoll(buf, &endptr, base); if (rest) *rest = bstr_cut(str, endptr - buf); return r; }
static enum cue_command read_cmd(struct bstr *data, struct bstr *out_params) { struct bstr line = bstr_strip_linebreaks(bstr_getline(*data, data)); line = bstr_lstrip(line); if (line.len == 0) return CUE_EMPTY; for (int n = 0; cue_command_strings[n].command != -1; n++) { struct bstr name = bstr0(cue_command_strings[n].text); if (bstr_startswith(line, name)) { struct bstr rest = bstr_cut(line, name.len); if (rest.len && !strchr(WHITESPACE, rest.start[0])) continue; if (out_params) *out_params = rest; return cue_command_strings[n].command; } } return CUE_ERROR; }
static struct bstr read_quoted(struct bstr *data) { *data = bstr_lstrip(*data); if (!eat_char(data, '"')) return (struct bstr) {0}; int end = bstrchr(*data, '"'); if (end < 0) return (struct bstr) {0}; struct bstr res = bstr_splice(*data, 0, end); *data = bstr_cut(*data, end + 1); return res; } // Read a 2 digit unsigned decimal integer. // Return -1 on failure. static int read_int_2(struct bstr *data) { *data = bstr_lstrip(*data); if (data->len && data->start[0] == '-') return -1; struct bstr s = *data; int res = (int)bstrtoll(s, &s, 10); if (data->len == s.len || data->len - s.len > 2) return -1; *data = s; return res; } static double read_time(struct bstr *data) { struct bstr s = *data; bool ok = true; double t1 = read_int_2(&s); ok = eat_char(&s, ':') && ok; double t2 = read_int_2(&s); ok = eat_char(&s, ':') && ok; double t3 = read_int_2(&s); ok = ok && t1 >= 0 && t2 >= 0 && t3 >= 0; return ok ? t1 * 60.0 + t2 + t3 * SECS_PER_CUE_FRAME : 0; } static struct bstr skip_utf8_bom(struct bstr data) { return bstr_startswith0(data, "\xEF\xBB\xBF") ? bstr_cut(data, 3) : data; } // Check if the text in data is most likely CUE data. This is used by the // demuxer code to check the file type. // data is the start of the probed file, possibly cut off at a random point. bool mp_probe_cue(struct bstr data) { bool valid = false; data = skip_utf8_bom(data); for (;;) { enum cue_command cmd = read_cmd(&data, NULL); // End reached. Since the line was most likely cut off, don't use the // result of the last parsing call. if (data.len == 0) break; if (cmd == CUE_ERROR) return false; if (cmd != CUE_EMPTY) valid = true; } return valid; }