Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/SDK/file_info_merge.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #include "foobar2000-sdk-pch.h" | |
| 2 #include "file_info.h" | |
| 3 | |
| 4 static t_size merge_tags_calc_rating_by_index(const file_info & p_info,t_size p_index) { | |
| 5 t_size n,m = p_info.meta_enum_value_count(p_index); | |
| 6 t_size ret = 0; | |
| 7 for(n=0;n<m;n++) | |
| 8 ret += strlen(p_info.meta_enum_value(p_index,n)) + 10;//yes, strlen on utf8 data, plus a slight bump to prefer multivalue over singlevalue w/ separator | |
| 9 return ret; | |
| 10 } | |
| 11 #if 0 | |
| 12 static t_size merge_tags_calc_rating(const file_info & p_info,const char * p_field) { | |
| 13 t_size field_index = p_info.meta_find(p_field); | |
| 14 if (field_index != ~0) { | |
| 15 return merge_tags_calc_rating_by_index(p_info,field_index); | |
| 16 } else { | |
| 17 return 0; | |
| 18 } | |
| 19 } | |
| 20 | |
| 21 static void merge_tags_copy_info(const char * field,const file_info * from,file_info * to) | |
| 22 { | |
| 23 const char * val = from->info_get(field); | |
| 24 if (val) to->info_set(field,val); | |
| 25 } | |
| 26 #endif | |
| 27 | |
| 28 namespace { | |
| 29 struct meta_merge_entry { | |
| 30 meta_merge_entry() : m_rating(0) {} | |
| 31 t_size m_rating; | |
| 32 pfc::array_t<const char *> m_data; | |
| 33 }; | |
| 34 | |
| 35 class meta_merge_map_enumerator { | |
| 36 public: | |
| 37 meta_merge_map_enumerator(file_info & p_out) : m_out(p_out) { | |
| 38 m_out.meta_remove_all(); | |
| 39 } | |
| 40 void operator() (const char * p_name, const meta_merge_entry & p_entry) { | |
| 41 if (p_entry.m_data.get_size() > 0) { | |
| 42 t_size index = m_out.__meta_add_unsafe(p_name,p_entry.m_data[0]); | |
| 43 for(t_size walk = 1; walk < p_entry.m_data.get_size(); ++walk) { | |
| 44 m_out.meta_add_value(index,p_entry.m_data[walk]); | |
| 45 } | |
| 46 } | |
| 47 } | |
| 48 private: | |
| 49 file_info & m_out; | |
| 50 }; | |
| 51 } | |
| 52 | |
| 53 static void merge_meta(file_info & p_out,const pfc::list_base_const_t<const file_info*> & p_in) { | |
| 54 pfc::map_t<const char *,meta_merge_entry,pfc::comparator_stricmp_ascii> map; | |
| 55 for(t_size in_walk = 0; in_walk < p_in.get_count(); in_walk++) { | |
| 56 const file_info & in = * p_in[in_walk]; | |
| 57 for(t_size meta_walk = 0, meta_count = in.meta_get_count(); meta_walk < meta_count; meta_walk++ ) { | |
| 58 meta_merge_entry & entry = map.find_or_add(in.meta_enum_name(meta_walk)); | |
| 59 t_size rating = merge_tags_calc_rating_by_index(in,meta_walk); | |
| 60 if (rating > entry.m_rating) { | |
| 61 entry.m_rating = rating; | |
| 62 const t_size value_count = in.meta_enum_value_count(meta_walk); | |
| 63 entry.m_data.set_size(value_count); | |
| 64 for(t_size value_walk = 0; value_walk < value_count; value_walk++ ) { | |
| 65 entry.m_data[value_walk] = in.meta_enum_value(meta_walk,value_walk); | |
| 66 } | |
| 67 } | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 meta_merge_map_enumerator en(p_out); | |
| 72 map.enumerate(en); | |
| 73 } | |
| 74 | |
| 75 void file_info::merge(const pfc::list_base_const_t<const file_info*> & p_in) | |
| 76 { | |
| 77 t_size in_count = p_in.get_count(); | |
| 78 if (in_count == 0) | |
| 79 { | |
| 80 meta_remove_all(); | |
| 81 return; | |
| 82 } | |
| 83 else if (in_count == 1) | |
| 84 { | |
| 85 const file_info * info = p_in[0]; | |
| 86 | |
| 87 copy_meta(*info); | |
| 88 | |
| 89 set_replaygain(replaygain_info::g_merge(get_replaygain(),info->get_replaygain())); | |
| 90 | |
| 91 overwrite_info(*info); | |
| 92 | |
| 93 //copy_info_single_by_name(*info,"tagtype"); | |
| 94 | |
| 95 return; | |
| 96 } | |
| 97 | |
| 98 merge_meta(*this,p_in); | |
| 99 | |
| 100 { | |
| 101 pfc::string8_fastalloc tagtype; | |
| 102 replaygain_info rg = get_replaygain(); | |
| 103 t_size in_ptr; | |
| 104 for(in_ptr = 0; in_ptr < in_count; in_ptr++ ) | |
| 105 { | |
| 106 const file_info * info = p_in[in_ptr]; | |
| 107 rg = replaygain_info::g_merge(rg, info->get_replaygain()); | |
| 108 t_size field_ptr, field_max = info->info_get_count(); | |
| 109 for(field_ptr = 0; field_ptr < field_max; field_ptr++ ) | |
| 110 { | |
| 111 const char * field_name = info->info_enum_name(field_ptr), * field_value = info->info_enum_value(field_ptr); | |
| 112 if (*field_value) | |
| 113 { | |
| 114 if (!pfc::stricmp_ascii(field_name,"tagtype")) | |
| 115 { | |
| 116 if (!tagtype.is_empty()) tagtype += "|"; | |
| 117 tagtype += field_value; | |
| 118 } | |
| 119 } | |
| 120 } | |
| 121 } | |
| 122 if (!tagtype.is_empty()) info_set("tagtype",tagtype); | |
| 123 set_replaygain(rg); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 void file_info::overwrite_info(const file_info & p_source) { | |
| 128 t_size count = p_source.info_get_count(); | |
| 129 for(t_size n=0;n<count;n++) { | |
| 130 info_set(p_source.info_enum_name(n),p_source.info_enum_value(n)); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 | |
| 135 void file_info::merge_fallback(const file_info & source) { | |
| 136 set_replaygain( replaygain_info::g_merge(get_replaygain(), source.get_replaygain() ) ); | |
| 137 if (get_length() <= 0) set_length(source.get_length()); | |
| 138 t_size count = source.info_get_count(); | |
| 139 for(t_size infoWalk = 0; infoWalk < count; ++infoWalk) { | |
| 140 const char * name = source.info_enum_name(infoWalk); | |
| 141 if (!info_exists(name)) __info_add_unsafe(name, source.info_enum_value(infoWalk)); | |
| 142 } | |
| 143 count = source.meta_get_count(); | |
| 144 for(t_size metaWalk = 0; metaWalk < count; ++metaWalk) { | |
| 145 const char * name = source.meta_enum_name(metaWalk); | |
| 146 if (!meta_exists(name)) _copy_meta_single_nocheck(source, metaWalk); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 static const char _tagtype[] = "tagtype"; | |
| 151 | |
| 152 static bool isSC( const char * n ) { | |
| 153 return pfc::string_has_prefix_i(n, "Apple SoundCheck" ); | |
| 154 } | |
| 155 | |
| 156 void file_info::_set_tag(const file_info & tag) { | |
| 157 this->copy_meta(tag); | |
| 158 this->set_replaygain( replaygain_info::g_merge( this->get_replaygain(), tag.get_replaygain() ) ); | |
| 159 | |
| 160 const size_t iCount = tag.info_get_count(); | |
| 161 for( size_t iWalk = 0; iWalk < iCount; ++iWalk ) { | |
| 162 auto n = tag.info_enum_name(iWalk); | |
| 163 if ( pfc::stringEqualsI_ascii( n, _tagtype ) || isSC(n) ) { | |
| 164 this->info_set(n, tag.info_enum_value( iWalk ) ); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 #ifdef FOOBAR2000_FILE_INFO_PICTURES | |
| 169 { | |
| 170 auto p = tag.info_get("pictures"); | |
| 171 if ( p != nullptr ) this->info_set("pictures", p); | |
| 172 } | |
| 173 #endif | |
| 174 } | |
| 175 | |
| 176 void file_info::_add_tag(const file_info & otherTag) { | |
| 177 this->set_replaygain( replaygain_info::g_merge( this->get_replaygain(), otherTag.get_replaygain() ) ); | |
| 178 | |
| 179 const char * tt1 = this->info_get(_tagtype); | |
| 180 const char * tt2 = otherTag.info_get(_tagtype); | |
| 181 if (tt2) { | |
| 182 if (tt1) { | |
| 183 this->info_set(_tagtype, PFC_string_formatter() << tt1 << "|" << tt2); | |
| 184 } else { | |
| 185 this->info_set(_tagtype, tt2); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 { | |
| 190 const size_t iCount = otherTag.info_get_count(); | |
| 191 for( size_t w = 0; w < iCount; ++ w ) { | |
| 192 auto n = otherTag.info_enum_name(w); | |
| 193 if (isSC(n) && !this->info_get(n)) { | |
| 194 this->info_set( n, otherTag.info_enum_value(w) ); | |
| 195 } | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 #ifdef FOOBAR2000_FILE_INFO_PICTURES | |
| 200 if (this->info_get("pictures") == nullptr) { | |
| 201 auto p = otherTag.info_get("pictures"); | |
| 202 if ( p != nullptr ) info_set("pictures", p); | |
| 203 } | |
| 204 #endif | |
| 205 } |
