// search for named .dsc file and load into network param desc memory extern u8 files_load_desc(const char* name) { char path[64] = DSP_PATH; void * fp; int nparams = -1; // word buffer for 4-byte unpickling u8 nbuf[4]; // buffer for binary blob of single descriptor u8 dbuf[PARAM_DESC_PICKLE_BYTES]; // unpacked descriptor ParamDesc desc; int i; u8 ret = 0; app_pause(); strcat(path, name); strip_ext(path); strcat(path, ".dsc"); print_dbg("\r\n opening .dsc file at path: "); print_dbg(path); fp = fl_fopen(path, "r"); if(fp == NULL) { print_dbg("... error opening .dsc file."); print_dbg(path); ret = 1; } else { // get number of parameters fake_fread(nbuf, 4, fp); unpickle_32(nbuf, (u32*)&nparams); /// loop over params if(nparams > 0) { net_clear_params(); // net->numParams = nparams; for(i=0; i<nparams; i++) { // FIXME: a little gross, // to be interleaving network and file manipulation like this... ///.... // read into desc buffer fake_fread(dbuf, PARAM_DESC_PICKLE_BYTES, fp); // unpickle directly into network descriptor memory pdesc_unpickle( &desc, dbuf ); // copy descriptor to network and increment count net_add_param(i, (const ParamDesc*)(&desc)); } } else { print_dbg("\r\n error: crazy parameter count from descriptor file."); ret = 1; } } fl_fclose(fp); app_resume(); return ret; }
int insert_playlist(const char * path, char * name) { struct song_metadata plist; struct stat file; int items = 0, matches, ret; char type[4]; strncpy(type, strrchr(name, '.')+1, 4); if( start_plist(path, NULL, &file, NULL, type) != 0 ) { DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path); return -1; } while( (ret = next_plist_track(&plist, &file, NULL, type)) == 0 ) { items++; freetags(&plist); } if( ret == 2 ) // Bad playlist -- contains binary characters { DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path); return -1; } strip_ext(name); DPRINTF(E_DEBUG, L_SCANNER, "Playlist %s contains %d items\n", name, items); matches = sql_get_int_field(db, "SELECT count(*) from PLAYLISTS where NAME = '%q'", name); if( matches > 0 ) { sql_exec(db, "INSERT into PLAYLISTS" " (NAME, PATH, ITEMS) " "VALUES" " ('%q(%d)', '%q', %d)", name, matches, path, items); } else { sql_exec(db, "INSERT into PLAYLISTS" " (NAME, PATH, ITEMS) " "VALUES" " ('%q', '%q', %d)", name, path, items); } sql_exec(db, "INSERT into DETAILS" " (PATH, TIMESTAMP, MIME) " "VALUES" " ('%q', %ld, 'audio/x-mpegurl')", path, 0); return 0; }
static void load_menu(void) { Tuple *t = dict_read_first(&items_iter); while(t != NULL) { char* id = (char*) t->value->cstring; char* name = split_id_name_pair(id); strip_ext(name); basic_menu_model_add_item(s_model, name, NULL, id); t = dict_read_next(&items_iter); } menu_layer_reload_data(s_menu); layer_set_hidden(s_lyr_loading, true); }
// search for specified dsp file and load it u8 files_load_dsp_name(const char* name) { // don't need .ldr, but we do need .dsc... char descname[128]; u8 nbuf[4]; // buffer for binary blob of single descriptor u8 dbuf[PARAM_DESC_PICKLE_BYTES]; // unpacked descriptor ParamDesc desc; u32 nparams; u8 ret = 0; FILE* fp; int i; strcpy(descname, workingDir); strcat(descname, name); strip_ext(descname); strcat(descname, ".dsc"); fp = fopen(descname, "r"); if(fp == NULL) { printf("\r\n module descriptor not found; path: %s", descname); ret = 1; return ret; } // get count of params fread(nbuf, 1, 4, fp); unpickle_32(nbuf, (u32*)&nparams); /// loop over params if(nparams > 0) { printf("\r\n loading param descriptor; count: %d", nparams); net_clear_params(); for(i=0; i<nparams; i++) { // read into desc buffer fread(dbuf, 1, PARAM_DESC_PICKLE_BYTES, fp); // unpickle directly into network descriptor memory pdesc_unpickle( &desc, dbuf ); // copy descriptor to network and increment count net_add_param(i, (const ParamDesc*)(&desc)); } } else { ret = 1; } fclose(fp); scene_set_module_name(name); return ret; }
void check_for_captions(const char *path, int64_t detailID) { char *file = malloc(MAXPATHLEN); char *id = NULL; sprintf(file, "%s", path); strip_ext(file); /* If we weren't given a detail ID, look for one. */ if( !detailID ) { id = sql_get_text_field(db, "SELECT ID from DETAILS where (PATH > '%q.' and PATH <= '%q.z')" " and MIME glob 'video/*' limit 1", file, file); if( id ) { DPRINTF(E_DEBUG, L_METADATA, "New file %s looks like a caption file.\n", path); detailID = strtoll(id, NULL, 10); } else { DPRINTF(E_DEBUG, L_METADATA, "No file found for caption %s.\n", path); goto no_source_video; } } strcat(file, ".srt"); DPRINTF(E_DEBUG, L_METADATA, "search %s.\n", file); if( access(file, R_OK) == 0 ) { sql_exec(db, "INSERT into CAPTIONS" " (ID, PATH) " "VALUES" " (%lld, %Q)", detailID, file); DPRINTF(E_DEBUG, L_INOTIFY, "INSERT into CAPTIONS (%lld, %s).\n", detailID, file); } no_source_video: if( id ) sqlite3_free(id); free(file); }
void check_for_captions(const char *path, int64_t detailID) { char file[MAXPATHLEN]; char *p; int ret; strncpyt(file, path, sizeof(file)); p = strip_ext(file); if (!p) p = strrchr(file, '\0'); /* If we weren't given a detail ID, look for one. */ if (!detailID) { detailID = sql_get_int64_field(db, "SELECT ID from DETAILS where (PATH > '%q.' and PATH <= '%q.z')" " and MIME glob 'video/*' limit 1", file, file); if (detailID <= 0) { //DPRINTF(E_MAXDEBUG, L_METADATA, "No file found for caption %s.\n", path); return; } } strcpy(p, ".srt"); ret = access(file, R_OK); if (ret != 0) { strcpy(p, ".smi"); ret = access(file, R_OK); } if (ret == 0) { sql_exec(db, "INSERT into CAPTIONS" " (ID, PATH) " "VALUES" " (%lld, %Q)", detailID, file); } }
bool gen_xsds(string &excel, string &xsd_dir) { if(false == fileuitl::exist(excel)) { ECHO_ERR("´íÎó: %s ·¾¶²»´æÔÚ", excel.c_str()); return false; } if(false == fileuitl::exist(xsd_dir)) { ECHO_ERR("´íÎó: %s ·¾¶²»´æÔÚ", xsd_dir.c_str()); return false; } propunit_t unit; errvec_t errvec; bool ok = parseutil::parse_excel(excel, unit, errvec); if (!ok){ ECHO_ERR("´íÎó: %s ½âÎöÎļþʧ°Ü", xsd_dir.c_str()); proputil::echo_errvec(errvec); return false; } // proputil::parse(excel, unit, errvec); for(propdeclvec_t::iterator itr = unit.propdecls.begin(); itr != unit.propdecls.end(); ++itr) { propdecl_t &decl = *itr; string xsd = xsd_dir + "\\" + strip_ext(strip_dir(decl.filename)) + ".xsd"; gen_xsd(decl, xsd); } return true; }
int64_t GetImageMetadata(const char *path, char *name) { ExifData *ed; ExifEntry *e = NULL; ExifLoader *l; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE *infile; int width=0, height=0, thumb=0; char make[32], model[64] = {'\0'}; char b[1024]; struct stat file; int64_t ret; image_s *imsrc; metadata_t m; uint32_t free_flags = 0xFFFFFFFF; memset(&m, '\0', sizeof(metadata_t)); //DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing %s...\n", path); if ( stat(path, &file) != 0 ) return 0; strip_ext(name); //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size); /* MIME hard-coded to JPEG for now, until we add PNG support */ m.mime = strdup("image/jpeg"); l = exif_loader_new(); exif_loader_write_file(l, path); ed = exif_loader_get_data(l); exif_loader_unref(l); if( !ed ) goto no_exifdata; e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL); if( e || (e = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED)) ) { m.date = strdup(exif_entry_get_value(e, b, sizeof(b))); if( strlen(m.date) > 10 ) { m.date[4] = '-'; m.date[7] = '-'; m.date[10] = 'T'; } else { free(m.date); m.date = NULL; } } else { /* One last effort to get the date from XMP */ image_get_jpeg_date_xmp(path, &m.date); } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * date: %s\n", m.date); e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); if( e ) { strncpyt(make, exif_entry_get_value(e, b, sizeof(b)), sizeof(make)); e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MODEL); if( e ) { strncpyt(model, exif_entry_get_value(e, b, sizeof(b)), sizeof(model)); if( !strcasestr(model, make) ) snprintf(model, sizeof(model), "%s %s", make, exif_entry_get_value(e, b, sizeof(b))); m.creator = escape_tag(trim(model), 1); } } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * model: %s\n", model); e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION); if( e ) { int rotate; switch( exif_get_short(e->data, exif_data_get_byte_order(ed)) ) { case 3: rotate = 180; break; case 6: rotate = 90; break; case 8: rotate = 270; break; default: rotate = 0; break; } if( rotate ) xasprintf(&m.rotation, "%d", rotate); } if( ed->size ) { /* We might need to verify that the thumbnail is 160x160 or smaller */ if( ed->size > 12000 ) { imsrc = image_new_from_jpeg(NULL, 0, (char *)ed->data, ed->size, 1, ROTATE_NONE); if( imsrc ) { if( (imsrc->width <= 160) && (imsrc->height <= 160) ) thumb = 1; image_free(imsrc); } } else { thumb = 1; //- 20130708 Sungmin add if(ed->data && ed->size) { char* art_file; if( !thumb_cache_exists(path, &art_file) ) { char cache_dir[MAXPATHLEN]; strncpyt(cache_dir, art_file, sizeof(cache_dir)); make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); FILE *thumb = fopen(art_file, "wb"); //DPRINTF(E_WARN, L_METADATA, " * cache_dir: %s\n", cache_dir); //DPRINTF(E_WARN, L_METADATA, " * thumbnail: %s\n", art_file); if(thumb) { fwrite(ed->data, 1, ed->size, thumb); fclose(thumb); } } free(art_file); } } } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * thumbnail: %d\n", thumb); exif_data_unref(ed); no_exifdata: /* If SOF parsing fails, then fall through to reading the JPEG data with libjpeg to get the resolution */ if( image_get_jpeg_resolution(path, &width, &height) != 0 || !width || !height ) { infile = fopen(path, "r"); if( infile ) { cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = libjpeg_error_handler; jpeg_create_decompress(&cinfo); if( setjmp(setjmp_buffer) ) goto error; jpeg_stdio_src(&cinfo, infile); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); width = cinfo.output_width; height = cinfo.output_height; error: jpeg_destroy_decompress(&cinfo); fclose(infile); } } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * resolution: %dx%d\n", width, height); if( !width || !height ) { free_metadata(&m, free_flags); return 0; } if( width <= 640 && height <= 480 ) m.dlna_pn = strdup("JPEG_SM"); else if( width <= 1024 && height <= 768 ) m.dlna_pn = strdup("JPEG_MED"); else if( (width <= 4096 && height <= 4096) || !GETFLAG(DLNA_STRICT_MASK) ) m.dlna_pn = strdup("JPEG_LRG"); xasprintf(&m.resolution, "%dx%d", width, height); ret = sql_exec(db, "INSERT into DETAILS" " (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION," " ROTATION, THUMBNAIL, CREATOR, DLNA_PN, MIME) " "VALUES" " (%Q, '%q', %lld, %ld, %Q, %Q, %Q, %d, %Q, %Q, %Q);", path, name, (long long)file.st_size, file.st_mtime, m.date, m.resolution, m.rotation, thumb, m.creator, m.dlna_pn, m.mime); if( ret != SQLITE_OK ) { fprintf(stderr, "Error inserting details for '%s'!\n", path); ret = 0; } else { ret = sqlite3_last_insert_rowid(db); } free_metadata(&m, free_flags); return ret; }
int64_t GetAudioMetadata(const char *path, char *name) { char type[4]; static char lang[6] = { '\0' }; struct stat file; int64_t ret; char *esc_tag; int i; int64_t album_art = 0; struct song_metadata song; metadata_t m; uint32_t free_flags = FLAG_MIME|FLAG_DURATION|FLAG_DLNA_PN|FLAG_DATE; memset(&m, '\0', sizeof(metadata_t)); if ( stat(path, &file) != 0 ) return 0; strip_ext(name); if( ends_with(path, ".mp3") ) { strcpy(type, "mp3"); m.mime = strdup("audio/mpeg"); } else if( ends_with(path, ".m4a") || ends_with(path, ".mp4") || ends_with(path, ".aac") || ends_with(path, ".m4p") ) { strcpy(type, "aac"); m.mime = strdup("audio/mp4"); } else if( ends_with(path, ".3gp") ) { strcpy(type, "aac"); m.mime = strdup("audio/3gpp"); } else if( ends_with(path, ".wma") || ends_with(path, ".asf") ) { strcpy(type, "asf"); m.mime = strdup("audio/x-ms-wma"); } else if( ends_with(path, ".flac") || ends_with(path, ".fla") || ends_with(path, ".flc") ) { strcpy(type, "flc"); m.mime = strdup("audio/x-flac"); } else if( ends_with(path, ".wav") ) { strcpy(type, "wav"); m.mime = strdup("audio/x-wav"); } else if( ends_with(path, ".ogg") || ends_with(path, ".oga") ) { strcpy(type, "ogg"); m.mime = strdup("audio/ogg"); } else if( ends_with(path, ".pcm") ) { strcpy(type, "pcm"); m.mime = strdup("audio/L16"); } else { DPRINTF(E_WARN, L_GENERAL, "Unhandled file extension on %s\n", path); return 0; } if( !(*lang) ) { if( !getenv("LANG") ) strcpy(lang, "en_US"); else strncpyt(lang, getenv("LANG"), sizeof(lang)); } if( readtags((char *)path, &song, &file, lang, type) != 0 ) { DPRINTF(E_WARN, L_GENERAL, "Cannot extract tags from %s!\n", path); freetags(&song); free_metadata(&m, free_flags); return 0; } if( song.dlna_pn ) m.dlna_pn = strdup(song.dlna_pn); if( song.year ) xasprintf(&m.date, "%04d-01-01", song.year); xasprintf(&m.duration, "%d:%02d:%02d.%03d", (song.song_length/3600000), (song.song_length/60000%60), (song.song_length/1000%60), (song.song_length%1000)); if( song.title && *song.title ) { m.title = trim(song.title); if( (esc_tag = escape_tag(m.title, 0)) ) { free_flags |= FLAG_TITLE; m.title = esc_tag; } } else { m.title = name; } for( i=ROLE_START; i<N_ROLE; i++ ) { if( song.contributor[i] && *song.contributor[i] ) { m.creator = trim(song.contributor[i]); if( strlen(m.creator) > 48 ) { m.creator = strdup("Various Artists"); free_flags |= FLAG_CREATOR; } else if( (esc_tag = escape_tag(m.creator, 0)) ) { m.creator = esc_tag; free_flags |= FLAG_CREATOR; } m.artist = m.creator; break; } } /* If there is a band associated with the album, use it for virtual containers. */ if( (i != ROLE_BAND) && (i != ROLE_ALBUMARTIST) ) { if( song.contributor[ROLE_BAND] && *song.contributor[ROLE_BAND] ) { i = ROLE_BAND; m.artist = trim(song.contributor[i]); if( strlen(m.artist) > 48 ) { m.artist = strdup("Various Artists"); free_flags |= FLAG_ARTIST; } else if( (esc_tag = escape_tag(m.artist, 0)) ) { m.artist = esc_tag; free_flags |= FLAG_ARTIST; } } } if( song.album && *song.album ) { m.album = trim(song.album); if( (esc_tag = escape_tag(m.album, 0)) ) { free_flags |= FLAG_ALBUM; m.album = esc_tag; } } if( song.genre && *song.genre ) { m.genre = trim(song.genre); if( (esc_tag = escape_tag(m.genre, 0)) ) { free_flags |= FLAG_GENRE; m.genre = esc_tag; } } if( song.comment && *song.comment ) { m.comment = trim(song.comment); if( (esc_tag = escape_tag(m.comment, 0)) ) { free_flags |= FLAG_COMMENT; m.comment = esc_tag; } } album_art = find_album_art(path, song.image, song.image_size); ret = sql_exec(db, "INSERT into DETAILS" " (PATH, SIZE, TIMESTAMP, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE," " TITLE, CREATOR, ARTIST, ALBUM, GENRE, COMMENT, DISC, TRACK, DLNA_PN, MIME, ALBUM_ART) " "VALUES" " (%Q, %lld, %ld, '%s', %d, %d, %d, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %d, %d, %Q, '%s', %lld);", path, (long long)file.st_size, file.st_mtime, m.duration, song.channels, song.bitrate, song.samplerate, m.date, m.title, m.creator, m.artist, m.album, m.genre, m.comment, song.disc, song.track, m.dlna_pn, song.mime?song.mime:m.mime, album_art); if( ret != SQLITE_OK ) { fprintf(stderr, "Error inserting details for '%s'!\n", path); ret = 0; } else { ret = sqlite3_last_insert_rowid(db); } freetags(&song); free_metadata(&m, free_flags); return ret; }
char * expand_format (struct WEdit *edit_widget, char c, int quote) { WPanel *panel = NULL; char *(*quote_func) (const char *, int); char *fname; char *result; char c_lc; if (c == '%') return g_strdup ("%"); if (edit_one_file != NULL) fname = edit_widget->filename; else { if (islower ((unsigned char) c)) panel = current_panel; else { if (get_other_type () != view_listing) return g_strdup (""); panel = other_panel; } fname = panel->dir.list[panel->selected].fname; } if (quote) quote_func = name_quote; else quote_func = fake_name_quote; c_lc = tolower ((unsigned char) c); switch (c_lc) { case 'f': case 'p': return (*quote_func) (fname, 0); case 'x': return (*quote_func) (extension (fname), 0); case 'd': { char *cwd; char *qstr; cwd = g_malloc(MC_MAXPATHLEN + 1); if (panel) g_strlcpy(cwd, panel->cwd, MC_MAXPATHLEN + 1); else mc_get_current_wd(cwd, MC_MAXPATHLEN + 1); qstr = (*quote_func) (cwd, 0); g_free (cwd); return qstr; } case 'i': /* indent equal number cursor position in line */ if (edit_widget) return g_strnfill (edit_widget->curs_col, ' '); break; case 'y': /* syntax type */ if (edit_widget && edit_widget->syntax_type) return g_strdup (edit_widget->syntax_type); break; case 'k': /* block file name */ case 'b': /* block file name / strip extension */ { if (edit_widget) { char *file = g_strconcat (home_dir, PATH_SEP_STR BLOCK_FILE, (char *) NULL); fname = (*quote_func) (file, 0); g_free (file); return fname; } else if (c_lc == 'b') { return strip_ext ((*quote_func) (fname, 0)); } break; } case 'e': /* was "cooledit.error" */ return g_strdup("/dev/null"); case 'n': /* strip extension in editor */ if (edit_widget) return strip_ext ((*quote_func) (fname, 0)); break; case 'm': /* menu file name */ if (menu) return (*quote_func) (menu, 0); break; case 's': if (!panel || !panel->marked) return (*quote_func) (fname, 0); /* Fall through */ case 't': case 'u': { int length = 2, i; char *block, *tmp; if (!panel) return g_strdup (""); for (i = 0; i < panel->count; i++) if (panel->dir.list[i].f.marked) length += strlen (panel->dir.list[i].fname) + 1; /* for space */ block = g_malloc (length * 2 + 1); *block = 0; for (i = 0; i < panel->count; i++) if (panel->dir.list[i].f.marked) { strcat (block, tmp = (*quote_func) (panel->dir.list[i].fname, 0)); g_free (tmp); strcat (block, " "); if (c_lc == 'u') do_file_mark (panel, i, 0); } return block; } /* sub case block */ } /* switch */ result = g_strdup ("% "); result[1] = c; return result; }
static struct bstr strip_ext(struct bstr str) { int dotpos = bstrrchr(str, '.'); if (dotpos < 0) return str; return (struct bstr){str.start, dotpos}; } static struct bstr get_ext(struct bstr s) { int dotpos = bstrrchr(s, '.'); if (dotpos < 0) return (struct bstr){NULL, 0}; return bstr_splice(s, dotpos + 1, s.len); } struct subfn { int priority; char *fname; }; static int compare_sub_priority(const void *a, const void *b) { const struct subfn *s1 = a; const struct subfn *s2 = b; if (s1->priority > s2->priority) return -1; if (s1->priority < s2->priority) return 1; return strcoll(s1->fname, s2->fname); } static struct bstr guess_lang_from_filename(struct bstr name) { if (name.len < 2) return (struct bstr){NULL, 0}; int n = 0; int i = name.len - 1; if (name.start[i] == ')' || name.start[i] == ']') i--; while (i >= 0 && isalpha(name.start[i])) { n++; if (n > 3) return (struct bstr){NULL, 0}; i--; } if (n < 2) return (struct bstr){NULL, 0}; return (struct bstr){name.start + i + 1, n}; } struct sub_list { struct subfn subs[MAX_SUBTITLE_FILES]; int sid; void *ctx; }; /** * @brief Append all the subtitles in the given path matching fname * @param opts MPlayer options * @param slist pointer to the subtitles list tallocated * @param nsub pointer to the number of subtitles * @param path Look for subtitles in this directory * @param fname Subtitle filename (pattern) * @param limit_fuzziness Ignore flag when sub_fuziness == 2 */ static void append_dir_subtitles(struct MPOpts *opts, struct subfn **slist, int *nsub, struct bstr path, const char *fname, int limit_fuzziness) { char *sub_exts[] = {"utf", "utf8", "utf-8", "sub", "srt", "smi", "rt", "txt", "ssa", "aqt", "jss", "js", "ass", NULL}; void *tmpmem = talloc_new(NULL); FILE *f; assert(strlen(fname) < 1e6); struct bstr f_fname = bstr0(mp_basename(fname)); struct bstr f_fname_noext = bstrdup(tmpmem, strip_ext(f_fname)); bstr_lower(f_fname_noext); struct bstr f_fname_trim = bstr_strip(f_fname_noext); // 0 = nothing // 1 = any subtitle file // 2 = any sub file containing movie name // 3 = sub file containing movie name and the lang extension char *path0 = bstrdup0(tmpmem, path); DIR *d = opendir(path0); if (!d) goto out; mp_msg(MSGT_SUBREADER, MSGL_V, "Load subtitles in %.*s\n", BSTR_P(path)); struct dirent *de; while ((de = readdir(d))) { struct bstr dename = bstr0(de->d_name); void *tmpmem2 = talloc_new(tmpmem); // retrieve various parts of the filename struct bstr tmp_fname_noext = bstrdup(tmpmem2, strip_ext(dename)); bstr_lower(tmp_fname_noext); struct bstr tmp_fname_ext = get_ext(dename); struct bstr tmp_fname_trim = bstr_strip(tmp_fname_noext); // If it's a .sub, check if there is a .idx with the same name. If // there is one, it's certainly a vobsub so we skip it. if (bstrcasecmp(tmp_fname_ext, bstr0("sub")) == 0) { char *idxname = talloc_asprintf(tmpmem2, "%.*s.idx", (int)tmp_fname_noext.len, de->d_name); char *idx = mp_path_join(tmpmem2, path, bstr0(idxname)); f = fopen(idx, "rt"); if (f) { fclose(f); goto next_sub; } } // does it end with a subtitle extension? #ifdef CONFIG_ICONV #ifdef CONFIG_ENCA int i = (sub_cp && strncasecmp(sub_cp, "enca", 4) != 0) ? 3 : 0; #else int i = sub_cp ? 3 : 0; #endif #else int i = 0; #endif while (1) { if (!sub_exts[i]) goto next_sub; if (bstrcasecmp(bstr0(sub_exts[i]), tmp_fname_ext) == 0) break; i++; } // we have a (likely) subtitle file int prio = 0; if (opts->sub_lang) { if (bstr_startswith(tmp_fname_trim, f_fname_trim)) { struct bstr lang = guess_lang_from_filename(tmp_fname_trim); if (lang.len) { for (int n = 0; opts->sub_lang[n]; n++) { if (bstr_startswith(lang, bstr0(opts->sub_lang[n]))) { prio = 4; // matches the movie name + lang extension break; } } } } } if (!prio && bstrcmp(tmp_fname_trim, f_fname_trim) == 0) prio = 3; // matches the movie name if (!prio && bstr_find(tmp_fname_trim, f_fname_trim) >= 0 && sub_match_fuzziness >= 1) prio = 2; // contains the movie name if (!prio) { // doesn't contain the movie name // don't try in the mplayer subtitle directory if (!limit_fuzziness && sub_match_fuzziness >= 2) { prio = 1; } } mp_msg(MSGT_SUBREADER, MSGL_DBG2, "Potential sub file: " "\"%s\" Priority: %d\n", de->d_name, prio); if (prio) { prio += prio; #ifdef CONFIG_ICONV if (i < 3) // prefer UTF-8 coded prio++; #endif char *subpath = mp_path_join(*slist, path, dename); if ((f = fopen(subpath, "rt"))) { MP_GROW_ARRAY(*slist, *nsub); struct subfn *sub = *slist + (*nsub)++; fclose(f); sub->priority = prio; sub->fname = subpath; } else talloc_free(subpath); } next_sub: talloc_free(tmpmem2); } closedir(d); out: talloc_free(tmpmem); } char **find_text_subtitles(struct MPOpts *opts, const char *fname) { char **subnames = NULL; struct subfn *slist = talloc_array_ptrtype(NULL, slist, 1); int n = 0; // Load subtitles from current media directory append_dir_subtitles(opts, &slist, &n, mp_dirname(fname), fname, 0); // Load subtitles in dirs specified by sub-paths option if (opts->sub_paths) { for (int i = 0; opts->sub_paths[i]; i++) { char *path = mp_path_join(slist, mp_dirname(fname), bstr0(opts->sub_paths[i])); append_dir_subtitles(opts, &slist, &n, bstr0(path), fname, 0); } } // Load subtitles in ~/.mplayer/sub limiting sub fuzziness char *mp_subdir = get_path("sub/"); if (mp_subdir) append_dir_subtitles(opts, &slist, &n, bstr0(mp_subdir), fname, 1); free(mp_subdir); // Sort subs by priority and append them qsort(slist, n, sizeof(*slist), compare_sub_priority); subnames = talloc_array_ptrtype(NULL, subnames, n); for (int i = 0; i < n; i++) subnames[i] = talloc_strdup(subnames, slist[i].fname); talloc_free(slist); return subnames; } char **find_vob_subtitles(struct MPOpts *opts, const char *fname) { char **vobs = talloc_array_ptrtype(NULL, vobs, 1); int n = 0; // Potential vobsub in the media directory struct bstr bname = bstr0(mp_basename(fname)); int pdot = bstrrchr(bname, '.'); if (pdot >= 0) bname.len = pdot; vobs[n++] = mp_path_join(vobs, mp_dirname(fname), bname); // Potential vobsubs in directories specified by sub-paths option if (opts->sub_paths) { for (int i = 0; opts->sub_paths[i]; i++) { char *path = mp_path_join(NULL, mp_dirname(fname), bstr0(opts->sub_paths[i])); MP_GROW_ARRAY(vobs, n); vobs[n++] = mp_path_join(vobs, bstr0(path), bname); talloc_free(path); } } // Potential vobsub in ~/.mplayer/sub char *mp_subdir = get_path("sub/"); if (mp_subdir) { MP_GROW_ARRAY(vobs, n); vobs[n++] = mp_path_join(vobs, bstr0(mp_subdir), bname); } free(mp_subdir); MP_RESIZE_ARRAY(NULL, vobs, n); return vobs; }
static void do_name (const char *arg) { globals.dll_name = strip_ext (arg); }
char * expand_format (struct WEdit *edit_widget, char c, gboolean do_quote) { WPanel *panel = NULL; char *(*quote_func) (const char *, int); char *fname = NULL; char *result; char c_lc; #ifndef USE_INTERNAL_EDIT (void) edit_widget; #endif if (c == '%') return g_strdup ("%"); if (mc_run_mode == MC_RUN_FULL) { if (g_ascii_islower ((gchar) c)) panel = current_panel; else { if (get_other_type () != view_listing) return g_strdup (""); panel = other_panel; } fname = panel->dir.list[panel->selected].fname; } #ifdef USE_INTERNAL_EDIT else if (mc_run_mode == MC_RUN_EDITOR) fname = (char *) edit_get_file_name (edit_widget); #endif if (do_quote) quote_func = name_quote; else quote_func = fake_name_quote; c_lc = g_ascii_tolower ((gchar) c); switch (c_lc) { case 'f': case 'p': return (*quote_func) (fname, 0); case 'x': return (*quote_func) (extension (fname), 0); case 'd': { char *cwd; char *qstr; cwd = g_malloc (MC_MAXPATHLEN + 1); if (panel) g_strlcpy (cwd, panel->cwd, MC_MAXPATHLEN + 1); else mc_get_current_wd (cwd, MC_MAXPATHLEN + 1); qstr = (*quote_func) (cwd, 0); g_free (cwd); return qstr; } case 'i': /* indent equal number cursor position in line */ #ifdef USE_INTERNAL_EDIT if (edit_widget) return g_strnfill (edit_get_curs_col (edit_widget), ' '); #endif break; case 'y': /* syntax type */ #ifdef USE_INTERNAL_EDIT if (edit_widget) { const char *syntax_type = edit_get_syntax_type (edit_widget); if (syntax_type != NULL) return g_strdup (syntax_type); } #endif break; case 'k': /* block file name */ case 'b': /* block file name / strip extension */ { #ifdef USE_INTERNAL_EDIT if (edit_widget) { char *file = concat_dir_and_file (mc_config_get_cache_path (), EDIT_BLOCK_FILE); fname = (*quote_func) (file, 0); g_free (file); return fname; } #endif if (c_lc == 'b') return strip_ext ((*quote_func) (fname, 0)); break; } case 'n': /* strip extension in editor */ #ifdef USE_INTERNAL_EDIT if (edit_widget) return strip_ext ((*quote_func) (fname, 0)); #endif break; case 'm': /* menu file name */ if (menu) return (*quote_func) (menu, 0); break; case 's': if (!panel || !panel->marked) return (*quote_func) (fname, 0); /* Fall through */ case 't': case 'u': { int length = 2, i; char *block, *tmp; if (!panel) return g_strdup (""); for (i = 0; i < panel->count; i++) if (panel->dir.list[i].f.marked) length += strlen (panel->dir.list[i].fname) + 1; /* for space */ block = g_malloc (length * 2 + 1); *block = 0; for (i = 0; i < panel->count; i++) if (panel->dir.list[i].f.marked) { tmp = (*quote_func) (panel->dir.list[i].fname, 0); strcat (block, tmp); g_free (tmp); strcat (block, " "); if (c_lc == 'u') do_file_mark (panel, i, 0); } return block; } /* sub case block */ } /* switch */ result = g_strdup ("% "); result[1] = c; return result; }
int FileSelector () { u32 p, wp, ph, wh; signed char a, c; int haverom = 0; int redraw = 1; int selectit = 0; float mag = 0; float mag2 = 0; u16 ang = 0; u16 ang2 = 0; int scroll_delay = 0; bool move_selection = 0; #define SCROLL_INITIAL_DELAY 15 #define SCROLL_LOOP_DELAY 4 while (haverom == 0) { if (redraw) ShowFiles (offset, selection); redraw = 0; VIDEO_WaitVSync(); // slow things down a bit so we don't overread the pads p = PAD_ButtonsDown (0); ph = PAD_ButtonsHeld (0); #ifdef HW_RVL wp = WPAD_ButtonsDown (0); wh = WPAD_ButtonsHeld (0); wpad_get_analogues(0, &mag, &ang, &mag2, &ang2); // get joystick info from wii expansions #else wp = 0; wh = 0; #endif a = PAD_StickY (0); c = PAD_SubStickX (0); /*** Check for exit combo ***/ if ( (c < -70) || (wp & WPAD_BUTTON_HOME) || (wp & WPAD_CLASSIC_BUTTON_HOME) ) return 0; /*** Check buttons, perform actions ***/ if ( (p & PAD_BUTTON_A) || selectit || (wp & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A)) ) { if ( selectit ) selectit = 0; if (filelist[selection].flags) /*** This is directory ***/ { if (loadtype == LOAD_SDC || loadtype == LOAD_USB) { /* memorize last entries list, actual root directory and selection for next access */ if (loadtype == LOAD_SDC) haveSDdir = 1; else haveUSBdir = 1; /* update current directory and set new entry list if directory has changed */ int status = updateFATdirname(); if (status == 1) // ok, open directory { maxfiles = parseFATdirectory(); if (!maxfiles) { WaitPrompt ((char*) "Error reading directory !"); haverom = 1; // quit SD menu if (loadtype == LOAD_SDC) // reset everything at next access haveSDdir = 0; else haveUSBdir = 0; } } else if (status == -1) // directory name too long { haverom = 1; // quit SD menu if (loadtype == LOAD_SDC) // reset everything at next access haveSDdir = 0; else haveUSBdir = 0; } } else { if ( (strcmp (filelist[selection].filename, "..") == 0) && ((unsigned int)rootdir == filelist[selection].offset) ) return 0; else { rootdir = filelist[selection].offset; rootdirlength = filelist[selection].length; offset = selection = 0; maxfiles = parsedirectory (); } } } else // this is a file { rootdir = filelist[selection].offset; rootdirlength = filelist[selection].length; /*** store the filename (used for sram/freeze naming) ***/ strip_ext(filelist[selection].filename, Memory.ROMFilename); // store stripped filename in Memory.ROMFilename switch (loadtype) { case LOAD_DVD: /*** Now load the DVD file to it's offset ***/ ARAM_ROMSIZE = LoadDVDFile (Memory.ROM); break; case LOAD_SMB: /*** Load from SMB ***/ ARAM_ROMSIZE = LoadSMBFile (filelist[selection].filename, filelist[selection].length); break; case LOAD_USB: case LOAD_SDC: /*** Load from SD Card ***/ /* memorize last entries list, actual root directory and selection for next access */ haveSDdir = 1; ARAM_ROMSIZE = LoadSDFile (filelist[selection].filename, filelist[selection].length); break; } if (ARAM_ROMSIZE > 0) { hasloaded = 1; Memory.LoadROM ("BLANK.SMC"); Memory.LoadSRAM ("BLANK"); haverom = 1; return 1; } else { WaitPrompt((char*) "Error loading ROM!"); } } redraw = 1; } // End of A if ( (p & PAD_BUTTON_B) || (wp & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)) ) { while ( (PAD_ButtonsDown(0) & PAD_BUTTON_B) #ifdef HW_RVL || (WPAD_ButtonsDown(0) & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)) #endif ) VIDEO_WaitVSync(); //if ((strcmp(filelist[1].filename,"..") == 0) && (strlen (filelist[0].filename) != 0)) if ( strcmp(filelist[0].filename,"..") == 0 ) { selection = 0; selectit = 1; } else if ( strcmp(filelist[1].filename,"..") == 0 ) { selection = selectit = 1; } else { return 0; } } // End of B if ( ((p | ph) & PAD_BUTTON_DOWN) || ((wp | wh) & (WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN)) || (a < -PADCAL) || (mag>JOY_THRESHOLD && (ang>130 && ang<230)) ) { if ( (p & PAD_BUTTON_DOWN) || (wp & (WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN)) ) { /*** Button just pressed ***/ scroll_delay = SCROLL_INITIAL_DELAY; // reset scroll delay. move_selection = 1; //continue (move selection) } else if (scroll_delay == 0) { /*** Button is held ***/ scroll_delay = SCROLL_LOOP_DELAY; move_selection = 1; //continue (move selection) } else { scroll_delay--; // wait } if (move_selection) { selection++; if (selection == maxfiles) selection = offset = 0; if ((selection - offset) >= PAGESIZE) offset += PAGESIZE; redraw = 1; move_selection = 0; } } // End of down if ( ((p | ph) & PAD_BUTTON_UP) || ((wp | wh) & (WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_UP)) || (a > PADCAL) || (mag>JOY_THRESHOLD && (ang>300 || ang<50)) ) { if ( (p & PAD_BUTTON_UP) || (wp & (WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_UP)) ) { /*** Button just pressed***/ scroll_delay = SCROLL_INITIAL_DELAY; // reset scroll delay. move_selection = 1; //continue (move selection) } else if (scroll_delay == 0) { /*** Button is held ***/ scroll_delay = SCROLL_LOOP_DELAY; move_selection = 1; //continue (move selection) } else { scroll_delay--; // wait } if (move_selection) { selection--; if (selection < 0) { selection = maxfiles - 1; offset = selection - PAGESIZE + 1; } if (selection < offset) offset -= PAGESIZE; if (offset < 0) offset = 0; redraw = 1; move_selection = 0; } } // End of Up if ( (p & PAD_BUTTON_LEFT) || (wp & (WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT)) ) { /*** Go back a page ***/ selection -= PAGESIZE; if (selection < 0) { selection = maxfiles - 1; offset = selection - PAGESIZE + 1; } if (selection < offset) offset -= PAGESIZE; if (offset < 0) offset = 0; redraw = 1; } if ( (p & PAD_BUTTON_RIGHT) || (wp & (WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT)) ) { /*** Go forward a page ***/ selection += PAGESIZE; if (selection > maxfiles - 1) selection = offset = 0; if ((selection - offset) >= PAGESIZE) offset += PAGESIZE; redraw = 1; } } return 0; }
char * expand_format (struct WEdit *edit_widget, char c, gboolean do_quote) { WPanel *panel = NULL; char *(*quote_func) (const char *, int); char *fname = NULL; char *result; char c_lc; #ifndef USE_INTERNAL_EDIT (void) edit_widget; #endif if (c == '%') return g_strdup ("%"); switch (mc_global.mc_run_mode) { case MC_RUN_FULL: if (g_ascii_islower ((gchar) c)) panel = current_panel; else { if (get_other_type () != view_listing) return g_strdup (""); panel = other_panel; } fname = g_strdup (panel->dir.list[panel->selected].fname); break; #ifdef USE_INTERNAL_EDIT case MC_RUN_EDITOR: fname = edit_get_file_name (edit_widget); break; #endif default: /* other modes don't use formats */ return g_strdup (""); } if (do_quote) quote_func = name_quote; else quote_func = fake_name_quote; c_lc = g_ascii_tolower ((gchar) c); switch (c_lc) { case 'f': case 'p': result = (*quote_func) (fname, 0); goto ret; case 'x': result = (*quote_func) (extension (fname), 0); goto ret; case 'd': { char *cwd; char *qstr; if (panel) cwd = g_strdup (vfs_path_as_str (panel->cwd_vpath)); else cwd = vfs_get_current_dir (); qstr = (*quote_func) (cwd, 0); g_free (cwd); result = qstr; goto ret; } case 'i': /* indent equal number cursor position in line */ #ifdef USE_INTERNAL_EDIT if (edit_widget) { result = g_strnfill (edit_get_curs_col (edit_widget), ' '); goto ret; } #endif break; case 'y': /* syntax type */ #ifdef USE_INTERNAL_EDIT if (edit_widget) { const char *syntax_type = edit_get_syntax_type (edit_widget); if (syntax_type != NULL) { result = g_strdup (syntax_type); goto ret; } } #endif break; case 'k': /* block file name */ case 'b': /* block file name / strip extension */ { #ifdef USE_INTERNAL_EDIT if (edit_widget) { char *file; file = mc_config_get_full_path (EDIT_BLOCK_FILE); result = (*quote_func) (file, 0); g_free (file); goto ret; } #endif if (c_lc == 'b') { result = strip_ext ((*quote_func) (fname, 0)); goto ret; } break; } case 'n': /* strip extension in editor */ #ifdef USE_INTERNAL_EDIT if (edit_widget) { result = strip_ext ((*quote_func) (fname, 0)); goto ret; } #endif break; case 'm': /* menu file name */ if (menu) { result = (*quote_func) (menu, 0); goto ret; } break; case 's': if (!panel || !panel->marked) { result = (*quote_func) (fname, 0); goto ret; } /* Fall through */ case 't': case 'u': { GString *block; int i; if (panel == NULL) { result = g_strdup (""); goto ret; } block = g_string_sized_new (16); for (i = 0; i < panel->dir.len; i++) if (panel->dir.list[i].f.marked) { char *tmp; tmp = (*quote_func) (panel->dir.list[i].fname, 0); g_string_append (block, tmp); g_string_append_c (block, ' '); g_free (tmp); if (c_lc == 'u') do_file_mark (panel, i, 0); } result = g_string_free (block, FALSE); goto ret; } /* sub case block */ } /* switch */ result = g_strdup ("% "); result[1] = c; ret: g_free (fname); return result; }
int64_t GetAudioMetadata(const char *path, char *name) { char type[4]; static char lang[6] = { '\0' }; struct stat file; int64_t ret; char *esc_tag; int i; int64_t album_art = 0; struct song_metadata song; metadata_t m; uint32_t free_flags = FLAG_MIME|FLAG_DURATION|FLAG_DLNA_PN|FLAG_DATE; memset(&m, '\0', sizeof(metadata_t)); if ( stat(path, &file) != 0 ) return 0; strip_ext(name); if( ends_with(path, ".mp3") ) { strcpy(type, "mp3"); m.mime = strdup("audio/mpeg"); } else if( ends_with(path, ".m4a") || ends_with(path, ".mp4") || ends_with(path, ".aac") || ends_with(path, ".m4p") ) { strcpy(type, "aac"); m.mime = strdup("audio/mp4"); } else if( ends_with(path, ".3gp") ) { strcpy(type, "aac"); m.mime = strdup("audio/3gpp"); } else if( ends_with(path, ".wma") || ends_with(path, ".asf") ) { strcpy(type, "asf"); m.mime = strdup("audio/x-ms-wma"); } else if( ends_with(path, ".flac") || ends_with(path, ".fla") || ends_with(path, ".flc") ) { strcpy(type, "flc"); m.mime = strdup("audio/x-flac"); } else if( ends_with(path, ".wav") ) { strcpy(type, "wav"); m.mime = strdup("audio/x-wav"); } else if( ends_with(path,".oga") || ends_with(path,".ogg")) { /* The .ogg/.oga file extensions present something of a problem. * ".ogg" has been deprecated in favor of ".oga" for some time, but * many applications still only recognize ".ogg". * * This examines the file and causes .ogg to be presented for any naked * Vorbis file (MIME type audio/ogg; codecs=vorbis) and .oga * (audio/ogg) to be used for everything else. This is in line with * the official ogg naming conventions and, hopefully, makes for a * resonable compromise. */ uint8_t oggtestbuf[35]; FILE *oggfile = fopen (path, "rb"); if (oggfile == (FILE *)NULL) { DPRINTF(E_ERROR, L_METADATA, "Error opening %s\n", path); return 0; } if (fread (oggtestbuf, 1, 35, oggfile) != 35) { DPRINTF(E_WARN, L_METADATA, "Premature EOF on %s\n", path); fclose (oggfile); return 0; } fclose (oggfile); if (memcmp (&oggtestbuf[28], "\x01vorbis", 7)) m.mime = strdup ("audio/ogg"); else m.mime = strdup ("audio/ogg; codecs=vorbis"); strcpy(type, "ogg"); } else if ( ends_with(path, ".opus") ) { strcpy(type,"ops"); m.mime = strdup("audio/ogg; codecs=opus"); } #if 0 /* Not supported yet, and probably won't be. */ else if( ends_with(path, ".ogx") ) { strcpy(type, "ogx"); m.mime = strdup("application/ogg"); } #endif else if( ends_with(path, ".pcm") ) { strcpy(type, "pcm"); m.mime = strdup("audio/L16"); } else { DPRINTF(E_WARN, L_METADATA, "Unhandled file extension on %s\n", path); return 0; } if( !(*lang) ) { if( !getenv("LANG") ) strcpy(lang, "en_US"); else strncpyt(lang, getenv("LANG"), sizeof(lang)); } if( readtags((char *)path, &song, &file, lang, type) != 0 ) { DPRINTF(E_WARN, L_METADATA, "Cannot extract tags from %s!\n", path); freetags(&song); free_metadata(&m, free_flags); return 0; } if( song.dlna_pn ) m.dlna_pn = strdup(song.dlna_pn); if( song.year ) xasprintf(&m.date, "%04d-01-01", song.year); xasprintf(&m.duration, "%d:%02d:%02d.%03d", (song.song_length/3600000), (song.song_length/60000%60), (song.song_length/1000%60), (song.song_length%1000)); if( song.title && *song.title ) { m.title = trim(song.title); if( (esc_tag = escape_tag(m.title, 0)) ) { free_flags |= FLAG_TITLE; m.title = esc_tag; } } else { m.title = name; } for( i = ROLE_START; i < N_ROLE; i++ ) { if( song.contributor[i] && *song.contributor[i] ) { m.creator = trim(song.contributor[i]); if( strlen(m.creator) > 48 ) { m.creator = strdup("Various Artists"); free_flags |= FLAG_CREATOR; } else if( (esc_tag = escape_tag(m.creator, 0)) ) { m.creator = esc_tag; free_flags |= FLAG_CREATOR; } m.artist = m.creator; break; } } /* If there is a album artist or band associated with the album, use it for virtual containers. */ if( i < ROLE_ALBUMARTIST ) { for( i = ROLE_ALBUMARTIST; i <= ROLE_BAND; i++ ) { if( song.contributor[i] && *song.contributor[i] ) break; } if( i <= ROLE_BAND ) { m.artist = trim(song.contributor[i]); if( strlen(m.artist) > 48 ) { m.artist = strdup("Various Artists"); free_flags |= FLAG_ARTIST; } else if( (esc_tag = escape_tag(m.artist, 0)) ) { m.artist = esc_tag; free_flags |= FLAG_ARTIST; } } } if( song.album && *song.album ) { m.album = trim(song.album); if( (esc_tag = escape_tag(m.album, 0)) ) { free_flags |= FLAG_ALBUM; m.album = esc_tag; } } if( song.genre && *song.genre ) { m.genre = trim(song.genre); if( (esc_tag = escape_tag(m.genre, 0)) ) { free_flags |= FLAG_GENRE; m.genre = esc_tag; } } if( song.comment && *song.comment ) { m.comment = trim(song.comment); if( (esc_tag = escape_tag(m.comment, 0)) ) { free_flags |= FLAG_COMMENT; m.comment = esc_tag; } } album_art = find_album_art(path, song.image, song.image_size); ret = sql_exec(db, "INSERT into DETAILS" " (PATH, SIZE, TIMESTAMP, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE," " TITLE, CREATOR, ARTIST, ALBUM, GENRE, COMMENT, DISC, TRACK, DLNA_PN, MIME, ALBUM_ART) " "VALUES" " (%Q, %lld, %lld, '%s', %d, %d, %d, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %d, %d, %Q, '%s', %lld);", path, (long long)file.st_size, (long long)file.st_mtime, m.duration, song.channels, song.bitrate, song.samplerate, m.date, m.title, m.creator, m.artist, m.album, m.genre, m.comment, song.disc, song.track, m.dlna_pn, song.mime?song.mime:m.mime, album_art); if( ret != SQLITE_OK ) { DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path); ret = 0; } else { ret = sqlite3_last_insert_rowid(db); } freetags(&song); free_metadata(&m, free_flags); return ret; }
//------------------------------main------------------------------------------- int main(int argc, char *argv[]) { ArchDesc AD; // Architecture Description object globalAD = &AD; // ResourceMark mark; ADLParser *ADL_Parse; // ADL Parser object to parse AD file // Check for proper arguments if( argc == 1 ) usage(AD); // No arguments? Then print usage // Read command line arguments and file names for( int i = 1; i < argc; i++ ) { // For all arguments register char *s = argv[i]; // Get option/filename if( *s++ == '-' ) { // It's a flag? (not a filename) if( !*s ) { // Stand-alone `-' means stdin //********** INSERT CODE HERE ********** } else while (*s != '\0') { // While have flags on option switch (*s++) { // Handle flag case 'd': // Debug flag AD._dfa_debug += 1; // Set Debug Flag break; case 'g': // Debug ad location flag AD._adlocation_debug += 1; // Set Debug ad location Flag break; case 'o': // No Output Flag AD._no_output ^= 1; // Toggle no_output flag break; case 'q': // Quiet Mode Flag AD._quiet_mode ^= 1; // Toggle quiet_mode flag break; case 'w': // Disable Warnings Flag AD._disable_warnings ^= 1; // Toggle disable_warnings flag break; case 'T': // Option to make DFA as many subroutine calls. AD._dfa_small += 1; // Set Mode Flag break; case 'c': { // Set C++ Output file name AD._CPP_file._name = s; const char *base = strip_ext(strdup(s)); AD._CPP_CLONE_file._name = base_plus_suffix(base,"_clone.cpp"); AD._CPP_EXPAND_file._name = base_plus_suffix(base,"_expand.cpp"); AD._CPP_FORMAT_file._name = base_plus_suffix(base,"_format.cpp"); AD._CPP_GEN_file._name = base_plus_suffix(base,"_gen.cpp"); AD._CPP_MISC_file._name = base_plus_suffix(base,"_misc.cpp"); AD._CPP_PEEPHOLE_file._name = base_plus_suffix(base,"_peephole.cpp"); AD._CPP_PIPELINE_file._name = base_plus_suffix(base,"_pipeline.cpp"); s += strlen(s); break; } case 'h': // Set C++ Output file name AD._HPP_file._name = s; s += strlen(s); break; case 'v': // Set C++ Output file name AD._VM_file._name = s; s += strlen(s); break; case 'a': // Set C++ Output file name AD._DFA_file._name = s; AD._bug_file._name = s; s += strlen(s); break; case '#': // Special internal debug flag AD._adl_debug++; // Increment internal debug level break; case 's': // Output which instructions are cisc-spillable AD._cisc_spill_debug = true; break; case 'D': // Flag Definition { char* flag = s; s += strlen(s); char* def = strchr(flag, '='); if (def == NULL) def = (char*)"1"; else *def++ = '\0'; AD.set_preproc_def(flag, def); } break; case 'U': // Flag Un-Definition { char* flag = s; s += strlen(s); AD.set_preproc_def(flag, NULL); } break; default: // Unknown option usage(AD); // So print usage and exit } // End of switch on options... } // End of while have options... } else { // Not an option; must be a filename AD._ADL_file._name = argv[i]; // Set the input filename // // Files for storage, based on input file name const char *base = strip_ext(strdup(argv[i])); char *temp = base_plus_suffix("dfa_",base); AD._DFA_file._name = base_plus_suffix(temp,".cpp"); delete temp; temp = base_plus_suffix("ad_",base); AD._CPP_file._name = base_plus_suffix(temp,".cpp"); AD._CPP_CLONE_file._name = base_plus_suffix(temp,"_clone.cpp"); AD._CPP_EXPAND_file._name = base_plus_suffix(temp,"_expand.cpp"); AD._CPP_FORMAT_file._name = base_plus_suffix(temp,"_format.cpp"); AD._CPP_GEN_file._name = base_plus_suffix(temp,"_gen.cpp"); AD._CPP_MISC_file._name = base_plus_suffix(temp,"_misc.cpp"); AD._CPP_PEEPHOLE_file._name = base_plus_suffix(temp,"_peephole.cpp"); AD._CPP_PIPELINE_file._name = base_plus_suffix(temp,"_pipeline.cpp"); AD._HPP_file._name = base_plus_suffix(temp,".hpp"); delete temp; temp = base_plus_suffix("adGlobals_",base); AD._VM_file._name = base_plus_suffix(temp,".hpp"); delete temp; temp = base_plus_suffix("bugs_",base); AD._bug_file._name = base_plus_suffix(temp,".out"); delete temp; } // End of files vs options... } // End of while have command line arguments // Open files used to store the matcher and its components if (AD.open_files() == 0) return 1; // Open all input/output files // Build the File Buffer, Parse the input, & Generate Code FileBuff ADL_Buf(&AD._ADL_file, AD); // Create a file buffer for input file // Get pointer to legal text at the beginning of AD file. // It will be used in generated ad files. char* legal_text; int legal_sz = get_legal_text(ADL_Buf, &legal_text); ADL_Parse = new ADLParser(ADL_Buf, AD); // Create a parser to parse the buffer ADL_Parse->parse(); // Parse buffer & build description lists if( AD._dfa_debug >= 1 ) { // For higher debug settings, print dump AD.dump(); } delete ADL_Parse; // Delete parser // Verify that the results of the parse are consistent AD.verify(); // Prepare to generate the result files: AD.generateMatchLists(); AD.identify_unique_operands(); AD.identify_cisc_spill_instructions(); AD.identify_short_branches(); // Make sure every file starts with a copyright: AD.addSunCopyright(legal_text, legal_sz, AD._HPP_file._fp); // .hpp AD.addSunCopyright(legal_text, legal_sz, AD._CPP_file._fp); // .cpp AD.addSunCopyright(legal_text, legal_sz, AD._CPP_CLONE_file._fp); // .cpp AD.addSunCopyright(legal_text, legal_sz, AD._CPP_EXPAND_file._fp); // .cpp AD.addSunCopyright(legal_text, legal_sz, AD._CPP_FORMAT_file._fp); // .cpp AD.addSunCopyright(legal_text, legal_sz, AD._CPP_GEN_file._fp); // .cpp AD.addSunCopyright(legal_text, legal_sz, AD._CPP_MISC_file._fp); // .cpp AD.addSunCopyright(legal_text, legal_sz, AD._CPP_PEEPHOLE_file._fp); // .cpp AD.addSunCopyright(legal_text, legal_sz, AD._CPP_PIPELINE_file._fp); // .cpp AD.addSunCopyright(legal_text, legal_sz, AD._VM_file._fp); // .hpp AD.addSunCopyright(legal_text, legal_sz, AD._DFA_file._fp); // .cpp // Add include guards for all .hpp files AD.addIncludeGuardStart(AD._HPP_file, "GENERATED_ADFILES_AD_HPP"); // .hpp AD.addIncludeGuardStart(AD._VM_file, "GENERATED_ADFILES_ADGLOBALS_HPP"); // .hpp // Add includes AD.addInclude(AD._CPP_file, "precompiled.hpp"); AD.addInclude(AD._CPP_file, "adfiles", get_basename(AD._VM_file._name)); AD.addInclude(AD._CPP_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_file, "memory/allocation.inline.hpp"); AD.addInclude(AD._CPP_file, "asm/macroAssembler.inline.hpp"); AD.addInclude(AD._CPP_file, "code/compiledIC.hpp"); AD.addInclude(AD._CPP_file, "code/nativeInst.hpp"); AD.addInclude(AD._CPP_file, "code/vmreg.inline.hpp"); AD.addInclude(AD._CPP_file, "gc/shared/collectedHeap.inline.hpp"); AD.addInclude(AD._CPP_file, "oops/compiledICHolder.hpp"); AD.addInclude(AD._CPP_file, "oops/markOop.hpp"); AD.addInclude(AD._CPP_file, "oops/method.hpp"); AD.addInclude(AD._CPP_file, "oops/oop.inline.hpp"); AD.addInclude(AD._CPP_file, "opto/cfgnode.hpp"); AD.addInclude(AD._CPP_file, "opto/locknode.hpp"); AD.addInclude(AD._CPP_file, "opto/opcodes.hpp"); AD.addInclude(AD._CPP_file, "opto/regalloc.hpp"); AD.addInclude(AD._CPP_file, "opto/regmask.hpp"); AD.addInclude(AD._CPP_file, "opto/runtime.hpp"); AD.addInclude(AD._CPP_file, "runtime/biasedLocking.hpp"); AD.addInclude(AD._CPP_file, "runtime/sharedRuntime.hpp"); AD.addInclude(AD._CPP_file, "runtime/stubRoutines.hpp"); AD.addInclude(AD._CPP_file, "utilities/growableArray.hpp"); AD.addInclude(AD._HPP_file, "memory/allocation.hpp"); AD.addInclude(AD._HPP_file, "code/nativeInst.hpp"); AD.addInclude(AD._HPP_file, "opto/machnode.hpp"); AD.addInclude(AD._HPP_file, "opto/node.hpp"); AD.addInclude(AD._HPP_file, "opto/regalloc.hpp"); AD.addInclude(AD._HPP_file, "opto/subnode.hpp"); AD.addInclude(AD._HPP_file, "opto/vectornode.hpp"); AD.addInclude(AD._CPP_CLONE_file, "precompiled.hpp"); AD.addInclude(AD._CPP_CLONE_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_EXPAND_file, "precompiled.hpp"); AD.addInclude(AD._CPP_EXPAND_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_FORMAT_file, "precompiled.hpp"); AD.addInclude(AD._CPP_FORMAT_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_GEN_file, "precompiled.hpp"); AD.addInclude(AD._CPP_GEN_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_GEN_file, "opto/cfgnode.hpp"); AD.addInclude(AD._CPP_GEN_file, "opto/locknode.hpp"); AD.addInclude(AD._CPP_MISC_file, "precompiled.hpp"); AD.addInclude(AD._CPP_MISC_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_PEEPHOLE_file, "precompiled.hpp"); AD.addInclude(AD._CPP_PEEPHOLE_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_PIPELINE_file, "precompiled.hpp"); AD.addInclude(AD._CPP_PIPELINE_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._DFA_file, "precompiled.hpp"); AD.addInclude(AD._DFA_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._DFA_file, "opto/cfgnode.hpp"); // Use PROB_MAX in predicate. AD.addInclude(AD._DFA_file, "opto/matcher.hpp"); AD.addInclude(AD._DFA_file, "opto/opcodes.hpp"); AD.addInclude(AD._DFA_file, "opto/convertnode.hpp"); // Make sure each .cpp file starts with include lines: // files declaring and defining generators for Mach* Objects (hpp,cpp) // Generate the result files: // enumerations, class definitions, object generators, and the DFA // file containing enumeration of machine operands & instructions (hpp) AD.addPreHeaderBlocks(AD._HPP_file._fp); // .hpp AD.buildMachOperEnum(AD._HPP_file._fp); // .hpp AD.buildMachOpcodesEnum(AD._HPP_file._fp); // .hpp AD.buildMachRegisterNumbers(AD._VM_file._fp); // VM file AD.buildMachRegisterEncodes(AD._HPP_file._fp); // .hpp file AD.declareRegSizes(AD._HPP_file._fp); // .hpp AD.build_pipeline_enums(AD._HPP_file._fp); // .hpp // output definition of class "State" AD.defineStateClass(AD._HPP_file._fp); // .hpp // file declaring the Mach* classes derived from MachOper and MachNode AD.declareClasses(AD._HPP_file._fp); // declare and define maps: in the .hpp and .cpp files respectively AD.addSourceBlocks(AD._CPP_file._fp); // .cpp AD.addHeaderBlocks(AD._HPP_file._fp); // .hpp AD.buildReduceMaps(AD._HPP_file._fp, AD._CPP_file._fp); AD.buildMustCloneMap(AD._HPP_file._fp, AD._CPP_file._fp); // build CISC_spilling oracle and MachNode::cisc_spill() methods AD.build_cisc_spill_instructions(AD._HPP_file._fp, AD._CPP_file._fp); // define methods for machine dependent State, MachOper, and MachNode classes AD.defineClasses(AD._CPP_file._fp); AD.buildMachOperGenerator(AD._CPP_GEN_file._fp);// .cpp AD.buildMachNodeGenerator(AD._CPP_GEN_file._fp);// .cpp // define methods for machine dependent instruction matching AD.buildInstructMatchCheck(AD._CPP_file._fp); // .cpp // define methods for machine dependent frame management AD.buildFrameMethods(AD._CPP_file._fp); // .cpp AD.generate_needs_clone_jvms(AD._CPP_file._fp); // do this last: AD.addPreprocessorChecks(AD._CPP_file._fp); // .cpp AD.addPreprocessorChecks(AD._CPP_CLONE_file._fp); // .cpp AD.addPreprocessorChecks(AD._CPP_EXPAND_file._fp); // .cpp AD.addPreprocessorChecks(AD._CPP_FORMAT_file._fp); // .cpp AD.addPreprocessorChecks(AD._CPP_GEN_file._fp); // .cpp AD.addPreprocessorChecks(AD._CPP_MISC_file._fp); // .cpp AD.addPreprocessorChecks(AD._CPP_PEEPHOLE_file._fp); // .cpp AD.addPreprocessorChecks(AD._CPP_PIPELINE_file._fp); // .cpp // define the finite automata that selects lowest cost production AD.buildDFA(AD._DFA_file._fp); // Add include guards for all .hpp files AD.addIncludeGuardEnd(AD._HPP_file, "GENERATED_ADFILES_AD_HPP"); // .hpp AD.addIncludeGuardEnd(AD._VM_file, "GENERATED_ADFILES_ADGLOBALS_HPP"); // .hpp AD.close_files(0); // Close all input/output files // Final printout and statistics // cout << program; if( AD._dfa_debug & 2 ) { // For higher debug settings, print timing info // Timer t_stop; // Timer t_total = t_stop - t_start; // Total running time // cerr << "\n---Architecture Description Totals---\n"; // cerr << ", Total lines: " << TotalLines; // float l = TotalLines; // cerr << "\nTotal Compilation Time: " << t_total << "\n"; // float ft = (float)t_total; // if( ft > 0.0 ) fprintf(stderr,"Lines/sec: %#5.2f\n", l/ft); } return (AD._syntax_errs + AD._semantic_errs + AD._internal_errs); // Bye Bye!! }
static struct bstr strip_ext(struct bstr str) { int dotpos = bstrrchr(str, '.'); if (dotpos < 0) return str; return (struct bstr){str.start, dotpos}; } static struct bstr get_ext(struct bstr s) { int dotpos = bstrrchr(s, '.'); if (dotpos < 0) return (struct bstr){NULL, 0}; return bstr_splice(s, dotpos + 1, s.len); } static int compare_sub_filename(const void *a, const void *b) { const struct subfn *s1 = a; const struct subfn *s2 = b; return strcoll(s1->fname, s2->fname); } static int compare_sub_priority(const void *a, const void *b) { const struct subfn *s1 = a; const struct subfn *s2 = b; if (s1->priority > s2->priority) return -1; if (s1->priority < s2->priority) return 1; return strcoll(s1->fname, s2->fname); } static struct bstr guess_lang_from_filename(struct bstr name) { if (name.len < 2) return (struct bstr){NULL, 0}; int n = 0; int i = name.len - 1; if (name.start[i] == ')' || name.start[i] == ']') i--; while (i >= 0 && isalpha(name.start[i])) { n++; if (n > 3) return (struct bstr){NULL, 0}; i--; } if (n < 2) return (struct bstr){NULL, 0}; return (struct bstr){name.start + i + 1, n}; } /** * @brief Append all the subtitles in the given path matching fname * @param opts MPlayer options * @param slist pointer to the subtitles list tallocated * @param nsub pointer to the number of subtitles * @param path Look for subtitles in this directory * @param fname Subtitle filename (pattern) * @param limit_fuzziness Ignore flag when sub_fuziness == 2 */ static void append_dir_subtitles(struct MPOpts *opts, struct subfn **slist, int *nsub, struct bstr path, const char *fname, int limit_fuzziness) { void *tmpmem = talloc_new(NULL); if (mp_is_url(bstr0(fname))) goto out; struct bstr f_fname = bstr0(mp_basename(fname)); struct bstr f_fname_noext = bstrdup(tmpmem, strip_ext(f_fname)); bstr_lower(f_fname_noext); struct bstr f_fname_trim = bstr_strip(f_fname_noext); // 0 = nothing // 1 = any subtitle file // 2 = any sub file containing movie name // 3 = sub file containing movie name and the lang extension char *path0 = bstrdup0(tmpmem, path); DIR *d = opendir(path0); if (!d) goto out; mp_msg(MSGT_SUBREADER, MSGL_V, "Load subtitles in %.*s\n", BSTR_P(path)); struct dirent *de; while ((de = readdir(d))) { struct bstr dename = bstr0(de->d_name); void *tmpmem2 = talloc_new(tmpmem); // retrieve various parts of the filename struct bstr tmp_fname_noext = bstrdup(tmpmem2, strip_ext(dename)); bstr_lower(tmp_fname_noext); struct bstr tmp_fname_ext = get_ext(dename); struct bstr tmp_fname_trim = bstr_strip(tmp_fname_noext); // does it end with a subtitle extension? if (!is_sub_ext(tmp_fname_ext)) goto next_sub; // we have a (likely) subtitle file int prio = 0; char *found_lang = NULL; if (opts->sub_lang) { if (bstr_startswith(tmp_fname_trim, f_fname_trim)) { struct bstr lang = guess_lang_from_filename(tmp_fname_trim); if (lang.len) { for (int n = 0; opts->sub_lang[n]; n++) { if (bstr_startswith0(lang, opts->sub_lang[n])) { prio = 4; // matches the movie name + lang extension found_lang = opts->sub_lang[n]; break; } } } } } if (!prio && bstrcmp(tmp_fname_trim, f_fname_trim) == 0) prio = 3; // matches the movie name if (!prio && bstr_find(tmp_fname_trim, f_fname_trim) >= 0 && opts->sub_match_fuzziness >= 1) prio = 2; // contains the movie name if (!prio) { // doesn't contain the movie name // don't try in the mplayer subtitle directory if (!limit_fuzziness && opts->sub_match_fuzziness >= 2) { prio = 1; } } mp_msg(MSGT_SUBREADER, MSGL_DBG2, "Potential sub file: " "\"%s\" Priority: %d\n", de->d_name, prio); if (prio) { prio += prio; char *subpath = mp_path_join(*slist, path, dename); if (mp_path_exists(subpath)) { MP_GROW_ARRAY(*slist, *nsub); struct subfn *sub = *slist + (*nsub)++; // annoying and redundant if (strncmp(subpath, "./", 2) == 0) subpath += 2; sub->priority = prio; sub->fname = subpath; sub->lang = found_lang; } else talloc_free(subpath); } next_sub: talloc_free(tmpmem2); } closedir(d); out: talloc_free(tmpmem); } static bool case_endswith(const char *s, const char *end) { size_t len = strlen(s); size_t elen = strlen(end); return len >= elen && strcasecmp(s + len - elen, end) == 0; } // Drop .sub file if .idx file exists. // Assumes slist is sorted by compare_sub_filename. static void filter_subidx(struct subfn **slist, int *nsub) { const char *prev = NULL; for (int n = 0; n < *nsub; n++) { const char *fname = (*slist)[n].fname; if (case_endswith(fname, ".idx")) { prev = fname; } else if (case_endswith(fname, ".sub")) { if (prev && strncmp(prev, fname, strlen(fname) - 4) == 0) (*slist)[n].priority = -1; } } for (int n = *nsub - 1; n >= 0; n--) { if ((*slist)[n].priority < 0) MP_TARRAY_REMOVE_AT(*slist, *nsub, n); } } // Return a list of subtitles found, sorted by priority. // Last element is terminated with a fname==NULL entry. struct subfn *find_text_subtitles(struct MPOpts *opts, const char *fname) { struct subfn *slist = talloc_array_ptrtype(NULL, slist, 1); int n = 0; // Load subtitles from current media directory append_dir_subtitles(opts, &slist, &n, mp_dirname(fname), fname, 0); // Load subtitles in dirs specified by sub-paths option if (opts->sub_paths) { for (int i = 0; opts->sub_paths[i]; i++) { char *path = mp_path_join(slist, mp_dirname(fname), bstr0(opts->sub_paths[i])); append_dir_subtitles(opts, &slist, &n, bstr0(path), fname, 0); } } // Load subtitles in ~/.mpv/sub limiting sub fuzziness char *mp_subdir = mp_find_user_config_file("sub/"); if (mp_subdir) append_dir_subtitles(opts, &slist, &n, bstr0(mp_subdir), fname, 1); talloc_free(mp_subdir); // Sort by name for filter_subidx() qsort(slist, n, sizeof(*slist), compare_sub_filename); filter_subidx(&slist, &n); // Sort subs by priority and append them qsort(slist, n, sizeof(*slist), compare_sub_priority); struct subfn z = {0}; MP_TARRAY_APPEND(NULL, slist, n, z); return slist; }
char * check_for_album_file(char * dir, const char * path) { char * file = malloc(PATH_MAX); struct album_art_name_s * album_art_name; image * imsrc = NULL; int width=0, height=0; char * art_file; /* First look for file-specific cover art */ sprintf(file, "%s.cover.jpg", path); if( access(file, R_OK) == 0 ) { if( art_cache_exists(file, &art_file) ) goto existing_file; free(art_file); imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1); if( imsrc ) goto found_file; } sprintf(file, "%s", path); strip_ext(file); strcat(file, ".jpg"); if( access(file, R_OK) == 0 ) { if( art_cache_exists(file, &art_file) ) goto existing_file; free(art_file); imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1); if( imsrc ) goto found_file; } /* Then fall back to possible generic cover art file names */ for( album_art_name = album_art_names; album_art_name; album_art_name = album_art_name->next ) { sprintf(file, "%s/%s", dir, album_art_name->name); if( access(file, R_OK) == 0 ) { if( art_cache_exists(file, &art_file) ) { existing_file: free(file); return art_file; } free(art_file); imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1); if( !imsrc ) continue; found_file: width = imsrc->width; height = imsrc->height; if( width > 160 || height > 160 ) { art_file = file; file = save_resized_album_art(imsrc, art_file); free(art_file); } image_free(imsrc); return(file); } } free(file); return NULL; }
int64_t GetVideoMetadata(const char *path, char *name) { struct stat file; int ret, i; struct tm *modtime; AVFormatContext *ctx = NULL; AVCodecContext *ac = NULL, *vc = NULL; int audio_stream = -1, video_stream = -1; enum audio_profiles audio_profile = PROFILE_AUDIO_UNKNOWN; char fourcc[4]; int64_t album_art = 0; char nfo[MAXPATHLEN], *ext; struct song_metadata video; metadata_t m; uint32_t free_flags = 0xFFFFFFFF; char *path_cpy, *basepath; memset(&m, '\0', sizeof(m)); memset(&video, '\0', sizeof(video)); //DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing video %s...\n", name); if ( stat(path, &file) != 0 ) return 0; strip_ext(name); //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size); ret = lav_open(&ctx, path); if( ret != 0 ) { char err[128]; av_strerror(ret, err, sizeof(err)); DPRINTF(E_WARN, L_METADATA, "Opening %s failed! [%s]\n", path, err); return 0; } //dump_format(ctx, 0, NULL, 0); for( i=0; i<ctx->nb_streams; i++) { if( audio_stream == -1 && ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) { audio_stream = i; ac = ctx->streams[audio_stream]->codec; continue; } else if( video_stream == -1 && ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) { video_stream = i; vc = ctx->streams[video_stream]->codec; continue; } } path_cpy = strdup(path); basepath = basename(path_cpy); if( !vc ) { /* This must not be a video file. */ lav_close(ctx); if( !is_audio(path) ) DPRINTF(E_DEBUG, L_METADATA, "File %s does not contain a video stream.\n", basepath); free(path_cpy); return 0; } if( ac ) { aac_object_type_t aac_type = AAC_INVALID; switch( ac->codec_id ) { case CODEC_ID_MP3: audio_profile = PROFILE_AUDIO_MP3; break; case CODEC_ID_AAC: if( !ac->extradata_size || !ac->extradata ) { DPRINTF(E_DEBUG, L_METADATA, "No AAC type\n"); } else { uint8_t data; memcpy(&data, ac->extradata, 1); aac_type = data >> 3; } switch( aac_type ) { /* AAC Low Complexity variants */ case AAC_LC: case AAC_LC_ER: if( ac->sample_rate < 8000 || ac->sample_rate > 48000 ) { DPRINTF(E_DEBUG, L_METADATA, "Unsupported AAC: sample rate is not 8000 < %d < 48000\n", ac->sample_rate); break; } /* AAC @ Level 1/2 */ if( ac->channels <= 2 && ac->bit_rate <= 576000 ) audio_profile = PROFILE_AUDIO_AAC; else if( ac->channels <= 6 && ac->bit_rate <= 1440000 ) audio_profile = PROFILE_AUDIO_AAC_MULT5; else DPRINTF(E_DEBUG, L_METADATA, "Unhandled AAC: %d channels, %d bitrate\n", ac->channels, ac->bit_rate); break; default: DPRINTF(E_DEBUG, L_METADATA, "Unhandled AAC type [%d]\n", aac_type); break; } break; case CODEC_ID_AC3: case CODEC_ID_DTS: audio_profile = PROFILE_AUDIO_AC3; break; case CODEC_ID_WMAV1: case CODEC_ID_WMAV2: /* WMA Baseline: stereo, up to 48 KHz, up to 192,999 bps */ if ( ac->bit_rate <= 193000 ) audio_profile = PROFILE_AUDIO_WMA_BASE; /* WMA Full: stereo, up to 48 KHz, up to 385 Kbps */ else if ( ac->bit_rate <= 385000 ) audio_profile = PROFILE_AUDIO_WMA_FULL; break; #if LIBAVCODEC_VERSION_INT > ((51<<16)+(50<<8)+1) case CODEC_ID_WMAPRO: audio_profile = PROFILE_AUDIO_WMA_PRO; break; #endif case CODEC_ID_MP2: audio_profile = PROFILE_AUDIO_MP2; break; case CODEC_ID_AMR_NB: audio_profile = PROFILE_AUDIO_AMR; break; default: if( (ac->codec_id >= CODEC_ID_PCM_S16LE) && (ac->codec_id < CODEC_ID_ADPCM_IMA_QT) ) audio_profile = PROFILE_AUDIO_PCM; else DPRINTF(E_DEBUG, L_METADATA, "Unhandled audio codec [0x%X]\n", ac->codec_id); break; } xasprintf(&m.frequency, "%u", ac->sample_rate); #if LIBAVCODEC_VERSION_INT < (52<<16) xasprintf(&m.bps, "%u", ac->bits_per_sample); #else xasprintf(&m.bps, "%u", ac->bits_per_coded_sample); #endif xasprintf(&m.channels, "%u", ac->channels); } if( vc ) { int off; int duration, hours, min, sec, ms; ts_timestamp_t ts_timestamp = NONE; DPRINTF(E_DEBUG, L_METADATA, "Container: '%s' [%s]\n", ctx->iformat->name, basepath); xasprintf(&m.resolution, "%dx%d", vc->width, vc->height); if( ctx->bit_rate > 8 ) xasprintf(&m.bitrate, "%u", ctx->bit_rate / 8); if( ctx->duration > 0 ) { duration = (int)(ctx->duration / AV_TIME_BASE); hours = (int)(duration / 3600); min = (int)(duration / 60 % 60); sec = (int)(duration % 60); ms = (int)(ctx->duration / (AV_TIME_BASE/1000) % 1000); xasprintf(&m.duration, "%d:%02d:%02d.%03d", hours, min, sec, ms); } /* NOTE: The DLNA spec only provides for ASF (WMV), TS, PS, and MP4 containers. * Skip DLNA parsing for everything else. */ if( strcmp(ctx->iformat->name, "avi") == 0 ) { xasprintf(&m.mime, "video/x-msvideo"); if( vc->codec_id == CODEC_ID_MPEG4 ) { fourcc[0] = vc->codec_tag & 0xff; fourcc[1] = vc->codec_tag>>8 & 0xff; fourcc[2] = vc->codec_tag>>16 & 0xff; fourcc[3] = vc->codec_tag>>24 & 0xff; if( memcmp(fourcc, "XVID", 4) == 0 || memcmp(fourcc, "DX50", 4) == 0 || memcmp(fourcc, "DIVX", 4) == 0 ) xasprintf(&m.creator, "DiVX"); } }
static int64_t _get_png_metadata (const char *path, char *name) { FILE *file; uint32_t width=0, height=0; int thumb=0; int got_header = 0; struct stat statbuf; int64_t ret; metadata_t m; uint8_t tagbuf[8]; uint32_t free_flags = 0; memset(&m, '\0', sizeof(metadata_t)); if ( stat(path, &statbuf) != 0 ) return 0; strip_ext(name); if ((file = fopen (path, "rb")) == (FILE *)NULL) { DPRINTF (E_ERROR, L_METADATA, "Error opening \"%s\": %s\n", path, strerror (errno)); return 0; } if (fread (tagbuf, 1, 8, file) != 8) { fclose (file); return 0; } if (memcmp (tagbuf, PNG_ID, PNG_ID_LEN)) { DPRINTF (E_WARN, L_METADATA, "\"%s\" not a PNG file.\n", path); fclose (file); return 0; } /* Go through the chunks */ for (;;) { int32_t chunksize; char *chunkname[5]; uint8_t *buf; if ((fread (tagbuf, 1, 8, file)) != 8) { DPRINTF (E_WARN, L_METADATA, "%s: Premature EOF.\n", path); fclose (file); free_metadata(&m, free_flags); return 0; } chunksize = BE32 (&tagbuf[0]); memcpy (chunkname, &tagbuf[4], 4); chunkname[4] = '\x00'; if (!memcmp (&tagbuf[4], "IEND", 4)) { break; } else if (chunksize <= 0) { if (fseek (file, 4, SEEK_CUR)) { DPRINTF (E_WARN, L_METADATA, "%s: Seek error.\n", path); fclose (file); free_metadata(&m, free_flags); return 0; } continue; } else if (!memcmp (&tagbuf[4], "IHDR", 4)) { if ((buf = _png_readchunk (file, chunksize)) == NULL) { fclose (file); free_metadata(&m, free_flags); return 0; } got_header = 1; /* width and height are 32-bit BE starting at offset 0 */ width = BE32 (&buf[0]); height = BE32 (&buf[4]); free (buf); continue; } else if (!memcmp (&tagbuf[4], "tIME", 4)) { if ((buf = _png_readchunk (file, chunksize)) == NULL) { fclose (file); free_metadata(&m, free_flags); return 0; } if (free_flags & FLAG_DATE) free (m.date); xasprintf (&m.date, "%04d-%02d-%02dT%02d:%02d:%02d", (int)(buf[0]<<8 | buf[1]), (int)buf[2], (int)buf[3], (int)buf[4], (int)buf[5], (int)buf[6]); free_flags |= FLAG_DATE; free (buf); continue; } else if (!memcmp (&tagbuf[4], "tEXt", 4) || !memcmp (&tagbuf[4], "iTXt", 4)) { int international = !memcmp (&tagbuf[4], "iTXt", 4), remaining = chunksize; char *keyword, *value; uint8_t *textp; int l; if ((buf = _png_readchunk (file, chunksize)) == NULL) { fclose (file); free_metadata(&m, free_flags); return 0; } textp = buf; keyword = (char *)buf; l = strlen (keyword) + 1; textp += l; if ((remaining -= l) <= 0) goto textdone; if (international) { char *lang; if (*textp) /* compressed */ goto textdone; textp += 2; if ((remaining -= 2) <= 0) goto textdone; /* language */ lang = (char *)textp; l = strlen (lang) + 1; textp += l; if ((remaining -= l) <= 0) goto textdone; /* translated keyword */ l = strlen ((char *)textp) + 1; textp += l; if ((remaining -= l) <= 0) goto textdone; } /* whatever's left is the value */ if ((value = malloc (remaining + 1)) == (char *)NULL) { DPRINTF (E_ERROR, L_METADATA, "Allocation error.\n"); free (buf); fclose (file); free_metadata(&m, free_flags); return 0; } memcpy (value, textp, remaining); value[remaining] = '\0'; if (!strcmp (keyword, "Title")) { if (free_flags & FLAG_TITLE) free (m.title); m.title = value; free_flags |= FLAG_TITLE; } else if (!strcmp (keyword, "Author")) { if (free_flags & FLAG_CREATOR) free (m.creator); m.creator = value; free_flags |= FLAG_CREATOR; } else { free (value); } textdone: free (buf); } else { /* move on to the next chunk */ if (fseek (file, chunksize+4, SEEK_CUR)) { DPRINTF (E_WARN, L_METADATA, "%s: Seek error.\n", path); fclose (file); free_metadata(&m, free_flags); return 0; } } } fclose (file); if (!got_header) { DPRINTF (E_WARN, L_METADATA, "%s: No PNG header.\n", path); free_metadata (&m, free_flags); return 0; } xasprintf(&m.resolution, "%dx%d", (int)width, (int)height); m.rotation = 0; thumb = 0; m.dlna_pn = NULL; m.mime = strdup("image/png"); free_flags |= (FLAG_MIME | FLAG_RESOLUTION); if (!(free_flags & FLAG_TITLE)) m.title = strdup (name); free_flags |= FLAG_TITLE; DPRINTF (E_MAXDEBUG, L_METADATA, "Processed \"%s\":\n Name: %s\n Resolution: %s\n", path, name, m.resolution); ret = sql_exec(db, "INSERT into DETAILS" " (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION," " ROTATION, THUMBNAIL, CREATOR, DLNA_PN, MIME) " "VALUES" " (%Q, '%q', %lld, %lld, %Q, %Q, %u, %d, %Q, %Q, %Q);", path, m.title, (long long)statbuf.st_size, (long long)statbuf.st_mtime, m.date, m.resolution, m.rotation, thumb, m.creator, m.dlna_pn, m.mime); if( ret != SQLITE_OK ) { DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path); ret = 0; } else { ret = sqlite3_last_insert_rowid(db); } free_metadata(&m, free_flags); return ret; }
static struct bstr strip_ext(struct bstr str) { int dotpos = bstrrchr(str, '.'); if (dotpos < 0) return str; return (struct bstr){str.start, dotpos}; } static struct bstr get_ext(struct bstr s) { int dotpos = bstrrchr(s, '.'); if (dotpos < 0) return (struct bstr){NULL, 0}; return bstr_splice(s, dotpos + 1, s.len); } bool mp_might_be_subtitle_file(const char *filename) { return test_ext(get_ext(bstr0(filename))) == STREAM_SUB; } static int compare_sub_filename(const void *a, const void *b) { const struct subfn *s1 = a; const struct subfn *s2 = b; return strcoll(s1->fname, s2->fname); } static int compare_sub_priority(const void *a, const void *b) { const struct subfn *s1 = a; const struct subfn *s2 = b; if (s1->priority > s2->priority) return -1; if (s1->priority < s2->priority) return 1; return strcoll(s1->fname, s2->fname); } static struct bstr guess_lang_from_filename(struct bstr name) { if (name.len < 2) return (struct bstr){NULL, 0}; int n = 0; int i = name.len - 1; if (name.start[i] == ')' || name.start[i] == ']') i--; while (i >= 0 && mp_isalpha(name.start[i])) { n++; if (n > 3) return (struct bstr){NULL, 0}; i--; } if (n < 2) return (struct bstr){NULL, 0}; return (struct bstr){name.start + i + 1, n}; } static void append_dir_subtitles(struct mpv_global *global, struct subfn **slist, int *nsub, struct bstr path, const char *fname, int limit_fuzziness) { void *tmpmem = talloc_new(NULL); struct MPOpts *opts = global->opts; struct mp_log *log = mp_log_new(tmpmem, global->log, "find_files"); if (mp_is_url(bstr0(fname))) goto out; struct bstr f_fname = bstr0(mp_basename(fname)); struct bstr f_fname_noext = bstrdup(tmpmem, strip_ext(f_fname)); bstr_lower(f_fname_noext); struct bstr f_fname_trim = bstr_strip(f_fname_noext); // 0 = nothing // 1 = any subtitle file // 2 = any sub file containing movie name // 3 = sub file containing movie name and the lang extension char *path0 = bstrdup0(tmpmem, path); DIR *d = opendir(path0); if (!d) goto out; mp_verbose(log, "Loading external files in %.*s\n", BSTR_P(path)); struct dirent *de; while ((de = readdir(d))) { struct bstr dename = bstr0(de->d_name); void *tmpmem2 = talloc_new(tmpmem); // retrieve various parts of the filename struct bstr tmp_fname_noext = bstrdup(tmpmem2, strip_ext(dename)); bstr_lower(tmp_fname_noext); struct bstr tmp_fname_ext = get_ext(dename); struct bstr tmp_fname_trim = bstr_strip(tmp_fname_noext); // check what it is (most likely) int type = test_ext(tmp_fname_ext); char **langs = NULL; int fuzz = -1; switch (type) { case STREAM_SUB: langs = opts->sub_lang; fuzz = opts->sub_auto; break; case STREAM_AUDIO: langs = opts->audio_lang; fuzz = opts->audiofile_auto; break; } if (fuzz < 0) goto next_sub; // we have a (likely) subtitle file int prio = 0; char *found_lang = NULL; if (langs) { if (bstr_startswith(tmp_fname_trim, f_fname_trim)) { struct bstr lang = guess_lang_from_filename(tmp_fname_trim); if (lang.len) { for (int n = 0; langs[n]; n++) { if (bstr_startswith0(lang, langs[n])) { prio = 4; // matches the movie name + lang extension found_lang = langs[n]; break; } } } } } if (!prio && bstrcmp(tmp_fname_trim, f_fname_trim) == 0) prio = 3; // matches the movie name if (!prio && bstr_find(tmp_fname_trim, f_fname_trim) >= 0 && fuzz >= 1) prio = 2; // contains the movie name if (!prio) { // doesn't contain the movie name // don't try in the mplayer subtitle directory if (!limit_fuzziness && fuzz >= 2) { prio = 1; } } mp_dbg(log, "Potential external file: \"%s\" Priority: %d\n", de->d_name, prio); if (prio) { prio += prio; char *subpath = mp_path_join(*slist, path, dename); if (mp_path_exists(subpath)) { MP_GROW_ARRAY(*slist, *nsub); struct subfn *sub = *slist + (*nsub)++; // annoying and redundant if (strncmp(subpath, "./", 2) == 0) subpath += 2; sub->type = type; sub->priority = prio; sub->fname = subpath; sub->lang = found_lang; } else talloc_free(subpath); } next_sub: talloc_free(tmpmem2); } closedir(d); out: talloc_free(tmpmem); } static bool case_endswith(const char *s, const char *end) { size_t len = strlen(s); size_t elen = strlen(end); return len >= elen && strcasecmp(s + len - elen, end) == 0; } // Drop .sub file if .idx file exists. // Assumes slist is sorted by compare_sub_filename. static void filter_subidx(struct subfn **slist, int *nsub) { const char *prev = NULL; for (int n = 0; n < *nsub; n++) { const char *fname = (*slist)[n].fname; if (case_endswith(fname, ".idx")) { prev = fname; } else if (case_endswith(fname, ".sub")) { if (prev && strncmp(prev, fname, strlen(fname) - 4) == 0) (*slist)[n].priority = -1; } } for (int n = *nsub - 1; n >= 0; n--) { if ((*slist)[n].priority < 0) MP_TARRAY_REMOVE_AT(*slist, *nsub, n); } } // Return a list of subtitles and audio files found, sorted by priority. // Last element is terminated with a fname==NULL entry. struct subfn *find_external_files(struct mpv_global *global, const char *fname) { struct MPOpts *opts = global->opts; struct subfn *slist = talloc_array_ptrtype(NULL, slist, 1); int n = 0; // Load subtitles from current media directory append_dir_subtitles(global, &slist, &n, mp_dirname(fname), fname, 0); if (opts->sub_auto >= 0) { // Load subtitles in dirs specified by sub-paths option if (opts->sub_paths) { for (int i = 0; opts->sub_paths[i]; i++) { char *path = mp_path_join(slist, mp_dirname(fname), bstr0(opts->sub_paths[i])); append_dir_subtitles(global, &slist, &n, bstr0(path), fname, 0); } } // Load subtitles in ~/.mpv/sub limiting sub fuzziness char *mp_subdir = mp_find_config_file(NULL, global, "sub/"); if (mp_subdir) append_dir_subtitles(global, &slist, &n, bstr0(mp_subdir), fname, 1); talloc_free(mp_subdir); } // Sort by name for filter_subidx() qsort(slist, n, sizeof(*slist), compare_sub_filename); filter_subidx(&slist, &n); // Sort subs by priority and append them qsort(slist, n, sizeof(*slist), compare_sub_priority); struct subfn z = {0}; MP_TARRAY_APPEND(NULL, slist, n, z); return slist; }
char *expand_format (char c, int quote) { WPanel *panel; char *(*quote_func)(const char *, int); if (quote) quote_func = name_quote; else quote_func = fake_name_quote; if (c == '%') return strdup ("%"); if (islower (c)) panel = cpanel; else { if (get_other_type () == view_listing){ panel = other_panel; } else return strdup (""); } if (!panel) panel = cpanel; c = tolower (c); switch (c){ case 'f': case 'p': return (*quote_func) (panel->dir.list [panel->selected].fname, 0); case 'b': return strip_ext((*quote_func) (panel->dir.list [panel->selected].fname, 0)); case 'd': return (*quote_func) (panel->cwd, 0); case 's': if (!panel->marked) return (*quote_func) (panel->dir.list [panel->selected].fname, 0); /* Fall through */ case 't': case 'u': { int length = 2, i; char *block, *tmp; for (i = 0; i < panel->count; i++) if (panel->dir.list [i].f.marked) length += strlen (panel->dir.list [i].fname) + 1; block = xmalloc (length*2+1, "expand_format"); *block = 0; for (i = 0; i < panel->count; i++) if (panel->dir.list [i].f.marked){ strcat (block, tmp = (*quote_func) (panel->dir.list [i].fname, 0)); free (tmp); strcat (block, " "); if (c == 'u') do_file_mark (panel, i, 0); } return block; } /* sub case block */ } /* switch */ return strdup (""); }