struct cue_file *mp_parse_cue(struct bstr data) { struct cue_file *f = talloc_zero(NULL, struct cue_file); f->tags = talloc_zero(f, struct mp_tags); data = skip_utf8_bom(data); char *filename = NULL; // Global metadata, and copied into new tracks. struct cue_track proto_track = {0}; struct cue_track *cur_track = NULL; while (data.len) { struct bstr param; int cmd = read_cmd(&data, ¶m); switch (cmd) { case CUE_ERROR: talloc_free(f); return NULL; case CUE_TRACK: { MP_TARRAY_GROW(f, f->tracks, f->num_tracks); f->num_tracks += 1; cur_track = &f->tracks[f->num_tracks - 1]; *cur_track = proto_track; cur_track->tags = talloc_zero(f, struct mp_tags); break; } case CUE_TITLE: case CUE_PERFORMER: { static const char *metanames[] = { [CUE_TITLE] = "title", [CUE_PERFORMER] = "performer", }; struct mp_tags *tags = cur_track ? cur_track->tags : f->tags; mp_tags_set_bstr(tags, bstr0(metanames[cmd]), param); break; } case CUE_INDEX: { int type = read_int_2(¶m); double time = read_time(¶m); if (cur_track) { if (type == 1) { cur_track->start = time; cur_track->filename = filename; } else if (type == 0) { cur_track->pregap_start = time; } } break; } case CUE_FILE: // NOTE: FILE comes before TRACK, so don't use cur_track->filename filename = read_quoted(f, ¶m); break; } } return f; }
pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) { trace::verbose(_X("--- Resolving CLI version from global json [%s]"), global_json.c_str()); pal::string_t retval; if (!pal::file_exists(global_json)) { trace::verbose(_X("[%s] does not exist"), global_json.c_str()); return retval; } pal::ifstream_t file(global_json); if (!file.good()) { trace::verbose(_X("[%s] could not be opened"), global_json.c_str()); return retval; } if (skip_utf8_bom(&file)) { trace::verbose(_X("UTF-8 BOM skipped while reading [%s]"), global_json.c_str()); } try { const auto root = json_value::parse(file); const auto& json = root.as_object(); const auto sdk_iter = json.find(_X("sdk")); if (sdk_iter == json.end() || sdk_iter->second.is_null()) { trace::verbose(_X("CLI '/sdk/version' field not present/null in [%s]"), global_json.c_str()); return retval; } const auto& sdk_obj = sdk_iter->second.as_object(); const auto ver_iter = sdk_obj.find(_X("version")); if (ver_iter == sdk_obj.end() || ver_iter->second.is_null()) { trace::verbose(_X("CLI 'sdk/version' field not present/null in [%s]"), global_json.c_str()); return retval; } retval = ver_iter->second.as_string(); } catch (const std::exception& je) { pal::string_t jes; (void) pal::utf8_palstring(je.what(), &jes); trace::error(_X("A JSON parsing exception occurred in [%s]: %s"), global_json.c_str(), jes.c_str()); } trace::verbose(_X("CLI version is [%s] in global json file [%s]"), retval.c_str(), global_json.c_str()); return retval; }
/** * Resolve the hostpolicy version from deps. * - Scan the deps file's libraries section and find the hostpolicy version in the file. */ pal::string_t resolve_hostpolicy_version_from_deps(const pal::string_t& deps_json) { trace::verbose(_X("--- Resolving %s version from deps json [%s]"), LIBHOSTPOLICY_NAME, deps_json.c_str()); pal::string_t retval; if (!pal::file_exists(deps_json)) { trace::verbose(_X("Dependency manifest [%s] does not exist"), deps_json.c_str()); return retval; } pal::ifstream_t file(deps_json); if (!file.good()) { trace::verbose(_X("Dependency manifest [%s] could not be opened"), deps_json.c_str()); return retval; } if (skip_utf8_bom(&file)) { trace::verbose(_X("UTF-8 BOM skipped while reading [%s]"), deps_json.c_str()); } try { const auto root = json_value::parse(file); const auto& json = root.as_object(); const auto& libraries = json.at(_X("libraries")).as_object(); // Look up the root package instead of the "runtime" package because we can't do a full rid resolution. // i.e., look for "Microsoft.NETCore.DotNetHostPolicy/" followed by version. pal::string_t prefix = _X("Microsoft.NETCore.DotNetHostPolicy/"); for (const auto& library : libraries) { if (starts_with(library.first, prefix, false)) { // Extract the version information that occurs after '/' retval = library.first.substr(prefix.size()); break; } } } catch (const std::exception& je) { pal::string_t jes; (void)pal::utf8_palstring(je.what(), &jes); trace::error(_X("A JSON parsing exception occurred in [%s]: %s"), deps_json.c_str(), jes.c_str()); } trace::verbose(_X("Resolved version %s from dependency manifest file [%s]"), retval.c_str(), deps_json.c_str()); return retval; }
// 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; }
// ----------------------------------------------------------------------------- // Load the deps file and parse its "entry" lines which contain the "fields" of // the entry. Populate an array of these entries. // bool deps_json_t::load(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& rid_fallback_graph) { m_file_exists = pal::file_exists(deps_path); // If file doesn't exist, then assume parsed. if (!m_file_exists) { trace::verbose(_X("Could not locate the dependencies manifest file [%s]. Some libraries may fail to resolve."), deps_path.c_str()); return true; } // Somehow the file stream could not be opened. This is an error. pal::ifstream_t file(deps_path); if (!file.good()) { trace::error(_X("Could not open dependencies manifest file [%s]"), deps_path.c_str()); return false; } if (skip_utf8_bom(&file)) { trace::verbose(_X("UTF-8 BOM skipped while reading [%s]"), deps_path.c_str()); } try { const auto json = json_value::parse(file); const auto& runtime_target = json.at(_X("runtimeTarget")); const pal::string_t& name = runtime_target.is_string()? runtime_target.as_string(): runtime_target.at(_X("name")).as_string(); trace::verbose(_X("Loading deps file... %s as portable=[%d]"), deps_path.c_str(), portable); return (portable) ? load_portable(json, name, rid_fallback_graph) : load_standalone(json, name); } catch (const std::exception& je) { pal::string_t jes; (void) pal::utf8_palstring(je.what(), &jes); trace::error(_X("A JSON parsing exception occurred in [%s]: %s"), deps_path.c_str(), jes.c_str()); return false; } }
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok) { FILE *fp = fopen_or_warn(path, "r"); struct attr_stack *res; char buf[2048]; int lineno = 0; if (!fp) return NULL; res = xcalloc(1, sizeof(*res)); while (fgets(buf, sizeof(buf), fp)) { char *bufp = buf; if (!lineno) skip_utf8_bom(&bufp, strlen(bufp)); handle_attr_line(res, bufp, path, ++lineno, macro_ok); } fclose(fp); return res; }
int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, struct exclude_list *el, int check_index) { struct stat st; int fd, i, lineno = 1; size_t size = 0; char *buf, *entry; fd = open(fname, O_RDONLY); if (fd < 0 || fstat(fd, &st) < 0) { if (errno != ENOENT) warn_on_inaccessible(fname); if (0 <= fd) close(fd); if (!check_index || (buf = read_skip_worktree_file_from_index(fname, &size)) == NULL) return -1; if (size == 0) { free(buf); return 0; } if (buf[size-1] != '\n') { buf = xrealloc(buf, size+1); buf[size++] = '\n'; } } else { size = xsize_t(st.st_size); if (size == 0) { close(fd); return 0; } buf = xmalloc(size+1); if (read_in_full(fd, buf, size) != size) { free(buf); close(fd); return -1; } buf[size++] = '\n'; close(fd); } el->filebuf = buf; if (skip_utf8_bom(&buf, size)) size -= buf - el->filebuf; entry = buf; for (i = 0; i < size; i++) { if (buf[i] == '\n') { if (entry != buf + i && entry[0] != '#') { buf[i - (i && buf[i-1] == '\r')] = 0; trim_trailing_spaces(entry); add_exclude(entry, base, baselen, el, lineno); } lineno++; entry = buf + i + 1; } } return 0; }
Dict* dict_text_new(const char* filename) { TextDict* text_dictionary; text_dictionary = (TextDict*)malloc(sizeof(TextDict)); text_dictionary->entry_count = INITIAL_DICTIONARY_SIZE; text_dictionary->max_length = 0; text_dictionary->lexicon = (TextEntry*)malloc( sizeof(TextEntry) * text_dictionary->entry_count); text_dictionary->word_buff = NULL; static char buff[ENTRY_BUFF_SIZE]; FILE* fp = fopen(filename, "r"); if (fp == NULL) { dict_text_delete((Dict*)text_dictionary); return (Dict*)-1; } skip_utf8_bom(fp); size_t i = 0; while (fgets(buff, ENTRY_BUFF_SIZE, fp)) { if (i >= text_dictionary->entry_count) { text_dictionary->entry_count += text_dictionary->entry_count; text_dictionary->lexicon = (TextEntry*)realloc( text_dictionary->lexicon, sizeof(TextEntry) * text_dictionary->entry_count ); } if (parse_entry(buff, text_dictionary->lexicon + i) == -1) { text_dictionary->entry_count = i; dict_text_delete((Dict*)text_dictionary); return (Dict*)-1; } size_t length = ucs4len(text_dictionary->lexicon[i].key); if (length > text_dictionary->max_length) { text_dictionary->max_length = length; } i++; } fclose(fp); text_dictionary->entry_count = i; text_dictionary->lexicon = (TextEntry*)realloc( text_dictionary->lexicon, sizeof(TextEntry) * text_dictionary->entry_count ); text_dictionary->word_buff = (ucs4_t*) malloc(sizeof(ucs4_t) * (text_dictionary->max_length + 1)); qsort(text_dictionary->lexicon, text_dictionary->entry_count, sizeof(text_dictionary->lexicon[0]), qsort_entry_cmp ); return (Dict*)text_dictionary; }
void build_cue_timeline(struct MPContext *mpctx) { void *ctx = talloc_new(NULL); struct bstr data = mpctx->demuxer->file_contents; data = skip_utf8_bom(data); struct cue_track *tracks = NULL; size_t track_count = 0; struct bstr filename = {0}; // Global metadata, and copied into new tracks. struct cue_track proto_track = {0}; struct cue_track *cur_track = &proto_track; while (data.len) { struct bstr param; switch (read_cmd(&data, ¶m)) { case CUE_ERROR: mp_msg(MSGT_CPLAYER, MSGL_ERR, "CUE: error parsing input file!\n"); goto out; case CUE_TRACK: { track_count++; tracks = talloc_realloc(ctx, tracks, struct cue_track, track_count); cur_track = &tracks[track_count - 1]; *cur_track = proto_track; break; } case CUE_TITLE: cur_track->title = read_quoted(¶m); break; case CUE_INDEX: { int type = read_int_2(¶m); double time = read_time(¶m); if (type == 1) { cur_track->start = time; cur_track->filename = filename; } else if (type == 0) { cur_track->pregap_start = time; } break; } case CUE_FILE: // NOTE: FILE comes before TRACK, so don't use cur_track->filename filename = read_quoted(¶m); break; } } if (track_count == 0) { mp_msg(MSGT_CPLAYER, MSGL_ERR, "CUE: no tracks found!\n"); goto out; } // Remove duplicate file entries. This might be too sophisticated, since // CUE files usually use either separate files for every single track, or // only one file for all tracks. struct bstr *files = 0; size_t file_count = 0; for (size_t n = 0; n < track_count; n++) { struct cue_track *track = &tracks[n]; track->source = -1; for (size_t file = 0; file < file_count; file++) { if (bstrcmp(files[file], track->filename) == 0) { track->source = file; break; } } if (track->source == -1) { file_count++; files = talloc_realloc(ctx, files, struct bstr, file_count); files[file_count - 1] = track->filename; track->source = file_count - 1; } }
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; }