foobar2000 SDK  2015-08-03
file_info_merge.cpp
Go to the documentation of this file.
1 #include "foobar2000.h"
2 
3 static t_size merge_tags_calc_rating_by_index(const file_info & p_info,t_size p_index) {
4  t_size n,m = p_info.meta_enum_value_count(p_index);
5  t_size ret = 0;
6  for(n=0;n<m;n++)
7  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
8  return ret;
9 }
10 #if 0
11 static t_size merge_tags_calc_rating(const file_info & p_info,const char * p_field) {
12  t_size field_index = p_info.meta_find(p_field);
13  if (field_index != ~0) {
14  return merge_tags_calc_rating_by_index(p_info,field_index);
15  } else {
16  return 0;
17  }
18 }
19 
20 static void merge_tags_copy_info(const char * field,const file_info * from,file_info * to)
21 {
22  const char * val = from->info_get(field);
23  if (val) to->info_set(field,val);
24 }
25 #endif
26 
27 namespace {
28  struct meta_merge_entry {
29  meta_merge_entry() : m_rating(0) {}
30  t_size m_rating;
32  };
33 
34  class meta_merge_map_enumerator {
35  public:
36  meta_merge_map_enumerator(file_info & p_out) : m_out(p_out) {
37  m_out.meta_remove_all();
38  }
39  void operator() (const char * p_name, const meta_merge_entry & p_entry) {
40  if (p_entry.m_data.get_size() > 0) {
41  t_size index = m_out.__meta_add_unsafe(p_name,p_entry.m_data[0]);
42  for(t_size walk = 1; walk < p_entry.m_data.get_size(); ++walk) {
43  m_out.meta_add_value(index,p_entry.m_data[walk]);
44  }
45  }
46  }
47  private:
48  file_info & m_out;
49  };
50 }
51 
54  for(t_size in_walk = 0; in_walk < p_in.get_count(); in_walk++) {
55  const file_info & in = * p_in[in_walk];
56  for(t_size meta_walk = 0, meta_count = in.meta_get_count(); meta_walk < meta_count; meta_walk++ ) {
57  meta_merge_entry & entry = map.find_or_add(in.meta_enum_name(meta_walk));
58  t_size rating = merge_tags_calc_rating_by_index(in,meta_walk);
59  if (rating > entry.m_rating) {
60  entry.m_rating = rating;
61  const t_size value_count = in.meta_enum_value_count(meta_walk);
62  entry.m_data.set_size(value_count);
63  for(t_size value_walk = 0; value_walk < value_count; value_walk++ ) {
64  entry.m_data[value_walk] = in.meta_enum_value(meta_walk,value_walk);
65  }
66  }
67  }
68  }
69 
70  meta_merge_map_enumerator en(p_out);
71  map.enumerate(en);
72 }
73 
75 {
76  t_size in_count = p_in.get_count();
77  if (in_count == 0)
78  {
79  meta_remove_all();
80  return;
81  }
82  else if (in_count == 1)
83  {
84  const file_info * info = p_in[0];
85 
86  copy_meta(*info);
87 
88  set_replaygain(replaygain_info::g_merge(get_replaygain(),info->get_replaygain()));
89 
90  overwrite_info(*info);
91 
92  //copy_info_single_by_name(*info,"tagtype");
93 
94  return;
95  }
96 
97  merge_meta(*this,p_in);
98 
99  {
100  pfc::string8_fastalloc tagtype;
101  replaygain_info rg = get_replaygain();
102  t_size in_ptr;
103  for(in_ptr = 0; in_ptr < in_count; in_ptr++ )
104  {
105  const file_info * info = p_in[in_ptr];
106  rg = replaygain_info::g_merge(rg, info->get_replaygain());
107  t_size field_ptr, field_max = info->info_get_count();
108  for(field_ptr = 0; field_ptr < field_max; field_ptr++ )
109  {
110  const char * field_name = info->info_enum_name(field_ptr), * field_value = info->info_enum_value(field_ptr);
111  if (*field_value)
112  {
113  if (!pfc::stricmp_ascii(field_name,"tagtype"))
114  {
115  if (!tagtype.is_empty()) tagtype += "|";
116  tagtype += field_value;
117  }
118  }
119  }
120  }
121  if (!tagtype.is_empty()) info_set("tagtype",tagtype);
122  set_replaygain(rg);
123  }
124 }
125 
126 void file_info::overwrite_info(const file_info & p_source) {
127  t_size count = p_source.info_get_count();
128  for(t_size n=0;n<count;n++) {
129  info_set(p_source.info_enum_name(n),p_source.info_enum_value(n));
130  }
131 }
132 
133 
134 void file_info::merge_fallback(const file_info & source) {
135  set_replaygain( replaygain_info::g_merge(get_replaygain(), source.get_replaygain() ) );
136  if (get_length() <= 0) set_length(source.get_length());
137  t_size count = source.info_get_count();
138  for(t_size infoWalk = 0; infoWalk < count; ++infoWalk) {
139  const char * name = source.info_enum_name(infoWalk);
140  if (!info_exists(name)) __info_add_unsafe(name, source.info_enum_value(infoWalk));
141  }
142  count = source.meta_get_count();
143  for(t_size metaWalk = 0; metaWalk < count; ++metaWalk) {
144  const char * name = source.meta_enum_name(metaWalk);
145  if (!meta_exists(name)) _copy_meta_single_nocheck(source, metaWalk);
146  }
147 }
148 
149 static const char _tagtype[] = "tagtype";
150 
151 void file_info::_set_tag(const file_info & tag) {
152  this->copy_meta(tag);
153  this->set_replaygain( replaygain_info::g_merge( this->get_replaygain(), tag.get_replaygain() ) );
154  const char * tt = tag.info_get(_tagtype);
155  if (tt) this->info_set(_tagtype, tt);
156 }
157 
158 void file_info::_add_tag(const file_info & otherTag) {
159  this->set_replaygain( replaygain_info::g_merge( this->get_replaygain(), otherTag.get_replaygain() ) );
160 
161  const char * tt1 = this->info_get(_tagtype);
162  const char * tt2 = otherTag.info_get(_tagtype);
163  if (tt2) {
164  if (tt1) {
165  this->info_set(_tagtype, PFC_string_formatter() << tt1 << "|" << tt2);
166  } else {
167  this->info_set(_tagtype, tt2);
168  }
169  }
170 
171 }
Definition: map.h:16
virtual double get_length() const =0
Retrieves audio duration, in seconds. Note that the reported duration should not be assumed to be th...
void merge(const pfc::list_base_const_t< const file_info * > &p_sources)
void enumerate(t_callback &p_callback) const
Definition: map.h:125
void _set_tag(const file_info &tag)
void info(const char *p_message)
Definition: console.cpp:4
virtual t_size meta_enum_value_count(t_size p_index) const =0
Retrieves count of values in metadata entry of specified index. The value is always equal to or great...
const char * info_get(const char *p_name) const
Definition: file_info.h:171
static void merge_meta(file_info &p_out, const pfc::list_base_const_t< const file_info * > &p_in)
virtual const char * info_enum_value(t_size p_index) const =0
Retrieves the value of specified technical info entry. Return value is a null-terminated UTF-8 encode...
static void merge_tags_copy_info(const char *field, const file_info *from, file_info *to)
virtual const char * meta_enum_value(t_size p_index, t_size p_value_number) const =0
Retrieves specified value from specified metadata entry. Return value is a null-terminated UTF-8 enco...
void merge_fallback(const file_info &fallback)
Structure containing ReplayGain scan results from some playable object, also providing various helper...
Definition: file_info.h:2
static t_size merge_tags_calc_rating_by_index(const file_info &p_info, t_size p_index)
t_storage_value & find_or_add(_t_key const &p_key)
Definition: map.h:29
Main interface class for information about some playable object.
Definition: file_info.h:73
static t_size merge_tags_calc_rating(const file_info &p_info, const char *p_field)
size_t t_size
Definition: int_types.h:48
virtual t_size get_count() const =0
virtual t_size meta_get_count() const =0
Retrieves count of metadata entries.
t_size info_set(const char *p_name, const char *p_value)
Definition: file_info.h:167
static const char _tagtype[]
static replaygain_info g_merge(replaygain_info r1, replaygain_info r2)
void _add_tag(const file_info &otherTag)
int stricmp_ascii(const char *s1, const char *s2)
virtual replaygain_info get_replaygain() const =0
Retrieves ReplayGain information.
string8_t< pfc::alloc_fast_aggressive > string8_fastalloc
Definition: string_base.h:436
virtual const char * info_enum_name(t_size p_index) const =0
Retrieves the name of specified technical info entry. Return value is a null-terminated UTF-8 encoded...
t_size meta_find(const char *p_name) const
Definition: file_info.h:154
virtual t_size info_get_count() const =0
Retrieves number of technical info entries.
void overwrite_info(const file_info &p_source)
virtual const char * meta_enum_name(t_size p_index) const =0
Retrieves the name of metadata entry of specified index. Return value is a null-terminated UTF-8 enco...