diff options
Diffstat (limited to 'src/libaudcore/tuple.cc')
-rw-r--r-- | src/libaudcore/tuple.cc | 156 |
1 files changed, 93 insertions, 63 deletions
diff --git a/src/libaudcore/tuple.cc b/src/libaudcore/tuple.cc index 52fd29b..4cd29b6 100644 --- a/src/libaudcore/tuple.cc +++ b/src/libaudcore/tuple.cc @@ -62,13 +62,14 @@ struct TupleData uint64_t setmask; // which fields are present Index<TupleVal> vals; // ordered list of field values - int *subtunes; /**< Array of int containing subtune index numbers. + short * subtunes; /**< Array of int containing subtune index numbers. Can be nullptr if indexing is linear or if there are no subtunes. */ - int nsubtunes; /**< Number of subtunes, if any. Values greater than 0 + short nsubtunes; /**< Number of subtunes, if any. Values greater than 0 mean that there are subtunes and #subtunes array may be set. */ + short state; int refcount; TupleData (); @@ -85,7 +86,7 @@ struct TupleData TupleVal * lookup (int field, bool add, bool remove); void set_int (int field, int x); void set_str (int field, const char * str); - void set_subtunes (int nsubs, const int * subs); + void set_subtunes (short nsubs, const short * subs); static TupleData * ref (TupleData * tuple); static void unref (TupleData * tuple); @@ -107,27 +108,28 @@ static const struct { {"title", Tuple::String, FallbackTitle}, {"artist", Tuple::String, FallbackArtist}, {"album", Tuple::String, FallbackAlbum}, + {"album-artist", Tuple::String, -1}, {"comment", Tuple::String, -1}, {"genre", Tuple::String, -1}, + {"year", Tuple::Int, -1}, + + {"composer", Tuple::String, -1}, + {"performer", Tuple::String, -1}, + {"copyright", Tuple::String, -1}, + {"date", Tuple::String, -1}, {"track-number", Tuple::Int, -1}, {"length", Tuple::Int, -1}, - {"year", Tuple::Int, -1}, - {"quality", Tuple::String, -1}, + + {"bitrate", Tuple::Int, -1}, {"codec", Tuple::String, -1}, + {"quality", Tuple::String, -1}, {"file-name", Tuple::String, -1}, {"file-path", Tuple::String, -1}, {"file-ext", Tuple::String, -1}, - {"album-artist", Tuple::String, -1}, - {"composer", Tuple::String, -1}, - {"performer", Tuple::String, -1}, - {"copyright", Tuple::String, -1}, - {"date", Tuple::String, -1}, - {"mbid", Tuple::String, -1}, - {"mime-type", Tuple::String, -1}, - {"bitrate", Tuple::Int, -1}, + {"audio-file", Tuple::String, -1}, {"subsong-id", Tuple::Int, -1}, {"subsong-num", Tuple::Int, -1}, @@ -162,6 +164,7 @@ static const FieldDictEntry field_dict[] = { {"album", Tuple::Album}, {"album-artist", Tuple::AlbumArtist}, {"artist", Tuple::Artist}, + {"audio-file", Tuple::AudioFile}, {"bitrate", Tuple::Bitrate}, {"codec", Tuple::Codec}, {"comment", Tuple::Comment}, @@ -180,8 +183,6 @@ static const FieldDictEntry field_dict[] = { {"gain-track-peak", Tuple::TrackPeak}, {"genre", Tuple::Genre}, {"length", Tuple::Length}, - {"mbid", Tuple::MusicBrainz}, - {"mime-type", Tuple::MIMEType}, {"performer", Tuple::Performer}, {"quality", Tuple::Quality}, {"segment-end", Tuple::EndTime}, @@ -277,17 +278,17 @@ void TupleData::set_str (int field, const char * str) new (& val->str) String (str); } -void TupleData::set_subtunes (int nsubs, const int * subs) +void TupleData::set_subtunes (short nsubs, const short * subs) { nsubtunes = nsubs; - delete subtunes; + delete[] subtunes; subtunes = nullptr; - if (subs) + if (nsubs && subs) { - subtunes = new int[nsubs]; - memcpy (subtunes, subs, sizeof (int) * nsubs); + subtunes = new short[nsubs]; + memcpy (subtunes, subs, sizeof subtunes[0] * nsubs); } } @@ -295,12 +296,14 @@ TupleData::TupleData () : setmask (0), subtunes (nullptr), nsubtunes (0), + state (Tuple::Initial), refcount (1) {} TupleData::TupleData (const TupleData & other) : setmask (other.setmask), subtunes (nullptr), nsubtunes (0), + state (other.state), refcount (1) { vals.insert (0, other.vals.len ()); @@ -345,8 +348,8 @@ TupleData::~TupleData () bool TupleData::is_same (const TupleData & other) { - if (setmask != other.setmask || nsubtunes != other.nsubtunes || - (! subtunes) != (! other.subtunes)) + if (state != other.state || setmask != other.setmask || + nsubtunes != other.nsubtunes || (! subtunes) != (! other.subtunes)) return false; auto a = vals.begin (); @@ -371,7 +374,7 @@ bool TupleData::is_same (const TupleData & other) } } - if (subtunes && memcmp (subtunes, other.subtunes, sizeof (int) * nsubtunes)) + if (subtunes && memcmp (subtunes, other.subtunes, sizeof subtunes[0] * nsubtunes)) return false; return true; @@ -427,6 +430,17 @@ EXPORT Tuple Tuple::ref () const return tuple; } +EXPORT Tuple::State Tuple::state () const +{ + return data ? (Tuple::State) data->state : Initial; +} + +EXPORT void Tuple::set_state (State st) +{ + data = TupleData::copy_on_write (data); + data->state = st; +} + EXPORT Tuple::ValueType Tuple::get_value_type (Field field) const { assert (is_valid_field (field)); @@ -553,18 +567,18 @@ EXPORT void Tuple::set_format (const char * format, int chans, int rate, int bra set_int (Bitrate, brate); } -EXPORT void Tuple::set_subtunes (int n_subtunes, const int * subtunes) +EXPORT void Tuple::set_subtunes (short n_subtunes, const short * subtunes) { data = TupleData::copy_on_write (data); data->set_subtunes (n_subtunes, subtunes); } -EXPORT int Tuple::get_n_subtunes () const +EXPORT short Tuple::get_n_subtunes() const { return data ? data->nsubtunes : 0; } -EXPORT int Tuple::get_nth_subtune (int n) const +EXPORT short Tuple::get_nth_subtune (short n) const { if (! data || n < 0 || n >= data->nsubtunes) return -1; @@ -644,10 +658,10 @@ EXPORT bool Tuple::fetch_stream_info (VFSFile & stream) * be modified, and the string returned will use the same memory. May return * nullptr. */ -static char * split_folder (char * path) +static char * split_folder (char * path, char sep) { char * c; - while ((c = strrchr (path, G_DIR_SEPARATOR))) + while ((c = strrchr (path, sep))) { * c = 0; if (c[1]) @@ -657,31 +671,33 @@ static char * split_folder (char * path) return path[0] ? path : nullptr; } -/* Separates the domain name from an internet URI. The string passed will be - * modified, and the string returned will share the same memory. May return - * nullptr. Examples: +/* These two functions separate the domain name from an internet URL. Examples: * "http://some.domain.org/folder/file.mp3" -> "some.domain.org" * "http://some.stream.fm:8000" -> "some.stream.fm" */ -static char * domain_name (char * name) +static const char * find_domain (const char * name) { if (! strncmp (name, "http://", 7)) - name += 7; - else if (! strncmp (name, "https://", 8)) - name += 8; - else if (! strncmp (name, "mms://", 6)) - name += 6; - else - return nullptr; + return name + 7; + if (! strncmp (name, "https://", 8)) + return name + 8; + if (! strncmp (name, "mms://", 6)) + return name + 6; + + return nullptr; +} +static StringBuf extract_domain (const char * start) +{ + StringBuf name = str_copy (start); char * c; if ((c = strchr (name, '/'))) - * c = 0; + name.resize (c - name); if ((c = strchr (name, ':'))) - * c = 0; + name.resize (c - name); if ((c = strchr (name, '?'))) - * c = 0; + name.resize (c - name); return name; } @@ -701,10 +717,22 @@ EXPORT void Tuple::generate_fallbacks () data = TupleData::copy_on_write (data); + // use album artist, if present + if (! artist && (artist = get_str (AlbumArtist))) + { + data->set_str (FallbackArtist, artist); + + if (album) + return; // nothing left to do + } + auto filepath = get_str (Path); if (! filepath) return; + const char * s; + char sep; + if (! strcmp (filepath, "cdda://")) { // audio CD: @@ -713,38 +741,40 @@ EXPORT void Tuple::generate_fallbacks () if (! album) data->set_str (FallbackAlbum, _("Audio CD")); } - else if (strstr (filepath, "://")) + else if ((s = find_domain (filepath))) { - // URL: + // internet URL: // use the domain name as the album - if (album) - return; - - StringBuf buf = str_copy (filepath); - const char * domain = domain_name (buf); - - if (domain) - data->set_str (FallbackAlbum, domain); + if (! album) + data->set_str (FallbackAlbum, extract_domain (s)); } else { - // local file: + // any other URI: // use the top two path elements as the artist and album - if (artist && album) - return; - - StringBuf buf; -#ifdef _WIN32 - if (filepath[0] && filepath[1] == ':' && filepath[2] == '\\') - buf.steal (str_copy (filepath + 3)); + if ((s = strstr (filepath, "://"))) + { + s += 3; + sep = '/'; + } else + { +#ifdef _WIN32 + if (g_ascii_isalpha (filepath[0]) && filepath[1] == ':') + s = filepath + 2; + else #endif - buf.steal (str_copy (filepath)); + s = filepath; + + sep = G_DIR_SEPARATOR; + } + + StringBuf buf = str_copy (s); - char * first = split_folder (buf); - char * second = (first && first > buf) ? split_folder (buf) : nullptr; + char * first = split_folder (buf, sep); + char * second = (first && first > buf) ? split_folder (buf, sep) : nullptr; // skip common strings and avoid duplicates for (auto skip : (const char *[]) {"~", "music", artist, album, get_str (Genre)}) |