foobar2000 SDK  2015-08-03
file_info_const_impl.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 
3 // presorted - do not change without a proper strcmp resort
4 static const char * const standard_fieldnames[] = {
5  "ALBUM","ALBUM ARTIST","ARTIST","Album","Album Artist","Artist","COMMENT","Comment","DATE","DISCNUMBER","Date",
6  "Discnumber","GENRE","Genre","TITLE","TOTALTRACKS","TRACKNUMBER","Title","TotalTracks","Totaltracks","TrackNumber",
7  "Tracknumber","album","album artist","artist","comment","date","discnumber","genre","title","totaltracks","tracknumber",
8 };
9 
10 // presorted - do not change without a proper strcmp resort
11 static const char * const standard_infonames[] = {
12  "bitrate","bitspersample","channels","codec","codec_profile","encoding","samplerate","tagtype","tool",
13 };
14 
15 static const char * optimize_fieldname(const char * p_string) {
16  t_size index;
17  if (!pfc::binarySearch<pfc::comparator_strcmp>::run(standard_fieldnames,0,PFC_TABSIZE(standard_fieldnames),p_string,index)) return NULL;
18  return standard_fieldnames[index];
19 }
20 
21 static const char * optimize_infoname(const char * p_string) {
22  t_size index;
23  if (!pfc::binarySearch<pfc::comparator_strcmp>::run(standard_infonames,0,PFC_TABSIZE(standard_infonames),p_string,index)) return NULL;
24  return standard_infonames[index];
25 }
26 
27 /*
28 order of things
29 
30  meta entries
31  meta value map
32  info entries
33  string buffer
34 
35 */
36 
37 inline static char* stringbuffer_append(char * & buffer,const char * value)
38 {
39  char * ret = buffer;
40  while(*value) *(buffer++) = *(value++);
41  *(buffer++) = 0;
42  return ret;
43 }
44 
45 #ifdef __file_info_const_impl_have_hintmap__
46 
47 namespace {
48  class sort_callback_hintmap_impl : public pfc::sort_callback
49  {
50  public:
51  sort_callback_hintmap_impl(const file_info_const_impl::meta_entry * p_meta,file_info_const_impl::t_index * p_hintmap)
52  : m_meta(p_meta), m_hintmap(p_hintmap)
53  {
54  }
55 
56  int compare(t_size p_index1, t_size p_index2) const
57  {
58 // profiler(sort_callback_hintmap_impl_compare);
59  return pfc::stricmp_ascii(m_meta[m_hintmap[p_index1]].m_name,m_meta[m_hintmap[p_index2]].m_name);
60  }
61 
62  void swap(t_size p_index1, t_size p_index2)
63  {
64  pfc::swap_t<file_info_const_impl::t_index>(m_hintmap[p_index1],m_hintmap[p_index2]);
65  }
66  private:
67  const file_info_const_impl::meta_entry * m_meta;
69  };
70 
71  class bsearch_callback_hintmap_impl// : public pfc::bsearch_callback
72  {
73  public:
74  bsearch_callback_hintmap_impl(
75  const file_info_const_impl::meta_entry * p_meta,
76  const file_info_const_impl::t_index * p_hintmap,
77  const char * p_name,
78  t_size p_name_length)
79  : m_meta(p_meta), m_hintmap(p_hintmap), m_name(p_name), m_name_length(p_name_length)
80  {
81  }
82 
83  inline int test(t_size p_index) const
84  {
85  return pfc::stricmp_ascii_ex(m_meta[m_hintmap[p_index]].m_name,~0,m_name,m_name_length);
86  }
87 
88  private:
89  const file_info_const_impl::meta_entry * m_meta;
90  const file_info_const_impl::t_index * m_hintmap;
91  const char * m_name;
92  t_size m_name_length;
93  };
94 }
95 
96 #endif//__file_info_const_impl_have_hintmap__
97 
98 void file_info_const_impl::copy(const file_info & p_source)
99 {
100 // profiler(file_info_const_impl__copy);
101  t_size meta_size = 0;
102  t_size info_size = 0;
103  t_size valuemap_size = 0;
104  t_size stringbuffer_size = 0;
105 #ifdef __file_info_const_impl_have_hintmap__
106  t_size hintmap_size = 0;
107 #endif
108 
109  const char * optbuf[64];
110  size_t optwalk = 0;
111 
112  {
113 // profiler(file_info_const_impl__copy__pass1);
114  t_size index;
115  m_meta_count = pfc::downcast_guarded<t_index>(p_source.meta_get_count());
116  meta_size = m_meta_count * sizeof(meta_entry);
117 #ifdef __file_info_const_impl_have_hintmap__
118  hintmap_size = (m_meta_count > hintmap_cutoff) ? m_meta_count * sizeof(t_index) : 0;
119 #endif//__file_info_const_impl_have_hintmap__
120  for(index = 0; index < m_meta_count; index++ )
121  {
122  {
123  const char * name = p_source.meta_enum_name(index);
124  const char * opt = optimize_fieldname(name);
125  if (optwalk < _countof(optbuf)) optbuf[optwalk++] = opt;
126  if (opt == NULL) stringbuffer_size += strlen(name) + 1;
127  }
128 
129  t_size val; const t_size val_max = p_source.meta_enum_value_count(index);
130 
131  if (val_max == 1)
132  {
133  stringbuffer_size += strlen(p_source.meta_enum_value(index,0)) + 1;
134  }
135  else
136  {
137  valuemap_size += val_max * sizeof(char*);
138 
139  for(val = 0; val < val_max; val++ )
140  {
141  stringbuffer_size += strlen(p_source.meta_enum_value(index,val)) + 1;
142  }
143  }
144  }
145 
146  m_info_count = pfc::downcast_guarded<t_index>(p_source.info_get_count());
147  info_size = m_info_count * sizeof(info_entry);
148  for(index = 0; index < m_info_count; index++ )
149  {
150  const char * name = p_source.info_enum_name(index);
151  const char * opt = optimize_infoname(name);
152  if (optwalk < _countof(optbuf)) optbuf[optwalk++] = opt;
153  if (opt == NULL) stringbuffer_size += strlen(name) + 1;
154  stringbuffer_size += strlen(p_source.info_enum_value(index)) + 1;
155  }
156  }
157 
158 
159  {
160 // profiler(file_info_const_impl__copy__alloc);
161  m_buffer.set_size(
162 #ifdef __file_info_const_impl_have_hintmap__
163  hintmap_size +
164 #endif
165  meta_size + info_size + valuemap_size + stringbuffer_size);
166  }
167 
168  char * walk = m_buffer.get_ptr();
169 
170 #ifdef __file_info_const_impl_have_hintmap__
171  t_index* hintmap = (hintmap_size > 0) ? (t_index*) walk : NULL;
172  walk += hintmap_size;
173 #endif
174  meta_entry * meta = (meta_entry*) walk;
175  walk += meta_size;
176  char ** valuemap = (char**) walk;
177  walk += valuemap_size;
178  info_entry * info = (info_entry*) walk;
179  walk += info_size;
180  char * stringbuffer = walk;
181 
182  m_meta = meta;
183  m_info = info;
184 #ifdef __file_info_const_impl_have_hintmap__
185  m_hintmap = hintmap;
186 #endif
187 
188  optwalk = 0;
189  {
190 // profiler(file_info_const_impl__copy__pass2);
191  t_size index;
192  for( index = 0; index < m_meta_count; index ++ )
193  {
194  t_size val; const t_size val_max = p_source.meta_enum_value_count(index);
195 
196  {
197  const char * name = p_source.meta_enum_name(index);
198  const char * name_opt;
199 
200  if (optwalk < _countof(optbuf)) name_opt = optbuf[optwalk++];
201  else name_opt = optimize_fieldname(name);
202 
203  if (name_opt == NULL)
204  meta[index].m_name = stringbuffer_append(stringbuffer, name );
205  else
206  meta[index].m_name = name_opt;
207  }
208 
209  meta[index].m_valuecount = val_max;
210 
211  if (val_max == 1)
212  {
213  meta[index].m_valuemap = reinterpret_cast<const char * const *>(stringbuffer_append(stringbuffer, p_source.meta_enum_value(index,0) ));
214  }
215  else
216  {
217  meta[index].m_valuemap = valuemap;
218  for( val = 0; val < val_max ; val ++ )
219  *(valuemap ++ ) = stringbuffer_append(stringbuffer, p_source.meta_enum_value(index,val) );
220  }
221  }
222 
223  for( index = 0; index < m_info_count; index ++ )
224  {
225  const char * name = p_source.info_enum_name(index);
226  const char * name_opt;
227 
228  if (optwalk < _countof(optbuf)) name_opt = optbuf[optwalk++];
229  else name_opt = optimize_infoname(name);
230 
231  if (name_opt == NULL)
232  info[index].m_name = stringbuffer_append(stringbuffer, name );
233  else
234  info[index].m_name = name_opt;
235  info[index].m_value = stringbuffer_append(stringbuffer, p_source.info_enum_value(index) );
236  }
237  }
238 
239  m_length = p_source.get_length();
240  m_replaygain = p_source.get_replaygain();
241 #ifdef __file_info_const_impl_have_hintmap__
242  if (hintmap != NULL) {
243 // profiler(file_info_const_impl__copy__hintmap);
244  for(t_size n=0;n<m_meta_count;n++) hintmap[n]=n;
245  pfc::sort(sort_callback_hintmap_impl(meta,hintmap),m_meta_count);
246  }
247 #endif//__file_info_const_impl_have_hintmap__
248 }
249 
250 
252 {
253  m_meta_count = m_info_count = 0; m_length = 0; m_replaygain.reset();
254 }
255 
256 t_size file_info_const_impl::meta_find_ex(const char * p_name,t_size p_name_length) const
257 {
258 #ifdef __file_info_const_impl_have_hintmap__
259  if (m_hintmap != NULL) {
260  t_size result = ~0;
261  if (!pfc::bsearch_inline_t(m_meta_count,bsearch_callback_hintmap_impl(m_meta,m_hintmap,p_name,p_name_length),result)) return ~0;
262  else return m_hintmap[result];
263  } else {
264  return file_info::meta_find_ex(p_name,p_name_length);
265  }
266 #else
267  return file_info::meta_find_ex(p_name,p_name_length);
268 #endif
269 }
270 
271 
273 {
274  return m_meta[p_index].m_valuecount;
275 }
276 
277 const char* file_info_const_impl::meta_enum_value(t_size p_index,t_size p_value_number) const
278 {
279  const meta_entry & entry = m_meta[p_index];
280  if (entry.m_valuecount == 1)
281  return reinterpret_cast<const char*>(entry.m_valuemap);
282  else
283  return entry.m_valuemap[p_value_number];
284 }
void sort(pfc::sort_callback &p_callback, t_size p_num)
Definition: sort.cpp:225
virtual double get_length() const =0
Retrieves audio duration, in seconds. Note that the reported duration should not be assumed to be th...
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...
Decoder Validator v1 readme Usage Select a single file handled by the decoder you want to test
Definition: readme.txt:4
virtual int compare(t_size p_index1, t_size p_index2) const =0
int stricmp_ascii_ex(const char *const s1, t_size const len1, const char *const s2, t_size const len2)
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 const char *const standard_fieldnames[]
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...
bool bsearch_inline_t(t_size p_count, const t_callback &p_callback, t_size &p_result)
Definition: bsearch_inline.h:6
Main interface class for information about some playable object.
Definition: file_info.h:73
size_t t_size
Definition: int_types.h:48
static char * stringbuffer_append(char *&buffer, const char *value)
static const char * optimize_infoname(const char *p_string)
virtual t_size meta_get_count() const =0
Retrieves count of metadata entries.
t_size meta_enum_value_count(t_size p_index) const
Retrieves count of values in metadata entry of specified index. The value is always equal to or great...
const char * meta_enum_value(t_size p_index, t_size p_value_number) const
Retrieves specified value from specified metadata entry. Return value is a null-terminated UTF-8 enco...
void copy(const file_info &p_source)
Copies entire file_info contents from specified file_info object.
t_size meta_find_ex(const char *p_name, t_size p_name_length) const
Finds index of metadata entry of specified name. Returns infinite when not found. ...
static const char * optimize_fieldname(const char *p_string)
virtual t_size meta_find_ex(const char *p_name, t_size p_name_length) const
Finds index of metadata entry of specified name. Returns infinite when not found. ...
Definition: file_info.cpp:8
virtual void swap(t_size p_index1, t_size p_index2)=0
int stricmp_ascii(const char *s1, const char *s2)
static const char *const standard_infonames[]
virtual replaygain_info get_replaygain() const =0
Retrieves ReplayGain information.
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...
virtual t_size info_get_count() const =0
Retrieves number of technical info entries.
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...