foobar2000 SDK  2015-08-03
input.cpp
Go to the documentation of this file.
1 #include "foobar2000.h"
2 
4 {
5  pfc::string_extension ext(p_path);
6  return g_find_service_by_path(p_out, p_path, ext );
7 }
8 
9 bool input_entry::g_find_service_by_path(service_ptr_t<input_entry> & p_out,const char * p_path, const char * p_ext)
10 {
13  while(e.next(ptr))
14  {
15  if (ptr->is_our_path(p_path,p_ext))
16  {
17  p_out = ptr;
18  return true;
19  }
20  }
21  return false;
22 }
23 
25 {
28  while(e.next(ptr))
29  {
30  if (ptr->is_our_content_type(p_content_type))
31  {
32  p_out = ptr;
33  return true;
34  }
35  }
36  return false;
37 }
38 
39 
40 #if 0
41 static void prepare_for_open(service_ptr_t<input_entry> & p_service,service_ptr_t<file> & p_file,const char * p_path,filesystem::t_open_mode p_open_mode,abort_callback & p_abort,bool p_from_redirect)
42 {
43  if (p_file.is_empty())
44  {
46  if (filesystem::g_get_interface(fs,p_path)) {
47  if (fs->supports_content_types()) {
48  fs->open(p_file,p_path,p_open_mode,p_abort);
49  }
50  }
51  }
52 
53  if (p_file.is_valid())
54  {
55  pfc::string8 content_type;
56  if (p_file->get_content_type(content_type))
57  {
58  if (input_entry::g_find_service_by_content_type(p_service,content_type))
59  return;
60  }
61  }
62 
63  if (input_entry::g_find_service_by_path(p_service,p_path))
64  {
65  if (p_from_redirect && p_service->is_redirect()) throw exception_io_unsupported_format();
66  return;
67  }
68 
69  throw exception_io_unsupported_format();
70 }
71 #endif
72 
73 namespace {
74 
75  bool g_find_inputs_by_content_type(pfc::list_base_t<service_ptr_t<input_entry> > & p_out,const char * p_content_type,bool p_from_redirect) {
78  bool ret = false;
79  while(e.next(ptr)) {
80  if (!(p_from_redirect && ptr->is_redirect())) {
81  if (ptr->is_our_content_type(p_content_type)) {p_out.add_item(ptr); ret = true;}
82  }
83  }
84  return ret;
85  }
86 
87  bool g_find_inputs_by_path(pfc::list_base_t<service_ptr_t<input_entry> > & p_out,const char * p_path,bool p_from_redirect) {
90  pfc::string_extension extension(p_path);
91  bool ret = false;
92  while(e.next(ptr)) {
93  if (!(p_from_redirect && ptr->is_redirect())) {
94  if (ptr->is_our_path(p_path,extension)) {p_out.add_item(ptr); ret = true;}
95  }
96  }
97  return ret;
98  }
99 
100  template<typename t_service> void g_open_from_list(service_ptr_t<t_service> & p_instance,pfc::list_base_const_t<service_ptr_t<input_entry> > const & p_list,service_ptr_t<file> const & p_filehint,const char * p_path,abort_callback & p_abort) {
101  const t_size count = p_list.get_count();
102  if (count == 1) {
103  p_list[0]->open(p_instance,p_filehint,p_path,p_abort);
104  } else {
105  unsigned bad_data_count = 0;
106  pfc::string8 bad_data_message;
107  for(t_size n=0;n<count;n++) {
108  try {
109  p_list[n]->open(p_instance,p_filehint,p_path,p_abort);
110  return;
111  } catch(exception_io_unsupported_format) {
112  //do nothing, skip over
113  } catch(exception_io_data const & e) {
114  if (bad_data_count ++ == 0) bad_data_message = e.what();
115  }
116  }
117  if (bad_data_count > 1) throw exception_io_data();
118  else if (bad_data_count == 0) pfc::throw_exception_with_message<exception_io_data>(bad_data_message);
119  else throw exception_io_unsupported_format();
120  }
121  }
122 
123  template<typename t_service> bool needs_write_access() {return false;}
124  template<> bool needs_write_access<input_info_writer>() {return true;}
125 
126  template<typename t_service> void g_open_t(service_ptr_t<t_service> & p_instance,service_ptr_t<file> const & p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) {
127  service_ptr_t<file> l_file = p_filehint;
128  if (l_file.is_empty()) {
130  if (filesystem::g_get_interface(fs,p_path)) {
131  if (fs->supports_content_types()) {
132  fs->open(l_file,p_path,needs_write_access<t_service>() ? filesystem::open_mode_write_existing : filesystem::open_mode_read,p_abort);
133  }
134  }
135  }
136 
137  if (l_file.is_valid()) {
138  pfc::string8 content_type;
139  if (l_file->get_content_type(content_type)) {
141  if (g_find_inputs_by_content_type(list,content_type,p_from_redirect)) {
142  g_open_from_list(p_instance,list,l_file,p_path,p_abort);
143  return;
144  }
145  }
146  }
147 
148  {
150  if (g_find_inputs_by_path(list,p_path,p_from_redirect)) {
151  g_open_from_list(p_instance,list,l_file,p_path,p_abort);
152  return;
153  }
154  }
155 
156  throw exception_io_unsupported_format();
157  }
158 };
159 
160 void input_entry::g_open_for_decoding(service_ptr_t<input_decoder> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) {
161  TRACK_CALL_TEXT("input_entry::g_open_for_decoding");
162 #if 1
163  g_open_t(p_instance,p_filehint,p_path,p_abort,p_from_redirect);
164 #else
165  service_ptr_t<file> filehint = p_filehint;
167 
168  prepare_for_open(entry,filehint,p_path,filesystem::open_mode_read,p_abort,p_from_redirect);
169 
170  entry->open_for_decoding(p_instance,filehint,p_path,p_abort);
171 #endif
172 
173 }
174 
175 void input_entry::g_open_for_info_read(service_ptr_t<input_info_reader> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) {
176  TRACK_CALL_TEXT("input_entry::g_open_for_info_read");
177 #if 1
178  g_open_t(p_instance,p_filehint,p_path,p_abort,p_from_redirect);
179 #else
180  service_ptr_t<file> filehint = p_filehint;
182 
183  prepare_for_open(entry,filehint,p_path,filesystem::open_mode_read,p_abort,p_from_redirect);
184 
185  entry->open_for_info_read(p_instance,filehint,p_path,p_abort);
186 #endif
187 }
188 
189 void input_entry::g_open_for_info_write(service_ptr_t<input_info_writer> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) {
190  TRACK_CALL_TEXT("input_entry::g_open_for_info_write");
191 #if 1
192  g_open_t(p_instance,p_filehint,p_path,p_abort,p_from_redirect);
193 #else
194  service_ptr_t<file> filehint = p_filehint;
196 
197  prepare_for_open(entry,filehint,p_path,filesystem::open_mode_write_existing,p_abort,p_from_redirect);
198 
199  entry->open_for_info_write(p_instance,filehint,p_path,p_abort);
200 #endif
201 }
202 
203 void input_entry::g_open_for_info_write_timeout(service_ptr_t<input_info_writer> & p_instance,service_ptr_t<file> p_filehint,const char * p_path,abort_callback & p_abort,double p_timeout,bool p_from_redirect) {
204  pfc::lores_timer timer;
205  timer.start();
206  for(;;) {
207  try {
208  g_open_for_info_write(p_instance,p_filehint,p_path,p_abort,p_from_redirect);
209  break;
210  } catch(exception_io_sharing_violation) {
211  if (timer.query() > p_timeout) throw;
212  p_abort.sleep(0.01);
213  }
214  }
215 }
216 
217 bool input_entry::g_is_supported_path(const char * p_path)
218 {
221  pfc::string_extension ext(p_path);
222  while(e.next(ptr))
223  {
224  if (ptr->is_our_path(p_path,ext)) return true;
225  }
226  return false;
227 }
228 
229 
230 
231 void input_open_file_helper(service_ptr_t<file> & p_file,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort)
232 {
233  if (p_file.is_empty()) {
234  switch(p_reason) {
235  default:
236  uBugCheck();
238  case input_open_decode:
239  filesystem::g_open(p_file,p_path,filesystem::open_mode_read,p_abort);
240  break;
242  filesystem::g_open(p_file,p_path,filesystem::open_mode_write_existing,p_abort);
243  break;
244  }
245  } else {
246  p_file->reopen(p_abort);
247  }
248 }
static bool g_find_service_by_content_type(service_ptr_t< input_entry > &p_out, const char *p_content_type)
Definition: input.cpp:24
static bool g_find_service_by_path(service_ptr_t< input_entry > &p_out, const char *p_path)
Definition: input.cpp:3
void start()
Definition: timers.h:93
bool is_empty() const
Definition: service.h:120
static void prepare_for_open(service_ptr_t< input_entry > &p_service, service_ptr_t< file > &p_file, const char *p_path, filesystem::t_open_mode p_open_mode, abort_callback &p_abort, bool p_from_redirect)
Definition: input.cpp:41
static bool g_is_supported_path(const char *p_path)
Definition: input.cpp:217
t_input_open_reason
Definition: input_impl.h:1
static void g_open_for_info_write(service_ptr_t< input_info_writer > &p_instance, service_ptr_t< file > p_filehint, const char *p_path, abort_callback &p_abort, bool p_from_redirect=false)
Definition: input.cpp:189
bool is_valid() const
Definition: service.h:119
static void g_open_for_info_read(service_ptr_t< input_info_reader > &p_instance, service_ptr_t< file > p_filehint, const char *p_path, abort_callback &p_abort, bool p_from_redirect=false)
Definition: input.cpp:175
void input_open_file_helper(service_ptr_t< file > &p_file, const char *p_path, t_input_open_reason p_reason, abort_callback &p_abort)
Helper function for input implementation use; ensures that file is open with relevant access mode...
Definition: input.cpp:231
size_t t_size
Definition: int_types.h:48
double query() const
Definition: timers.h:97
static void g_open_for_decoding(service_ptr_t< input_decoder > &p_instance, service_ptr_t< file > p_filehint, const char *p_path, abort_callback &p_abort, bool p_from_redirect=false)
Definition: input.cpp:160
Autopointer class to be used with all services. Manages reference counter calls behind-the-scenes.
Definition: service.h:55
static void g_open_for_info_write_timeout(service_ptr_t< input_info_writer > &p_instance, service_ptr_t< file > p_filehint, const char *p_path, abort_callback &p_abort, double p_timeout, bool p_from_redirect=false)
Definition: input.cpp:203
PFC_NORETURN void SHARED_EXPORT uBugCheck()
bool next(service_ptr_t< t_query > &p_out)
Definition: service.h:587