foobar2000 SDK  2015-08-03
filesystem_helper.h
Go to the documentation of this file.
1 #include <functional>
2 
3 namespace foobar2000_io {
4  typedef std::function< void (const char *, t_filestats const & , bool ) > listDirectoryFunc_t;
5  void listDirectory( const char * path, abort_callback & aborter, listDirectoryFunc_t func);
6 }
7 
8 
9 //helper
11 public:
12  file_path_canonical(const char * src) {filesystem::g_get_canonical_path(src,m_data);}
13  operator const char * () const {return m_data.get_ptr();}
14  const char * get_ptr() const {return m_data.get_ptr();}
15  t_size get_length() const {return m_data.get_length();}
16 private:
18 };
19 
21 public:
22  file_path_display(const char * src) {filesystem::g_get_display_path(src,m_data);}
23  operator const char * () const {return m_data.get_ptr();}
24  const char * get_ptr() const {return m_data.get_ptr();}
25  t_size get_length() const {return m_data.get_length();}
26 private:
28 };
29 
30 
31 class NOVTABLE reader_membuffer_base : public file_readonly {
32 public:
33  reader_membuffer_base() : m_offset(0) {}
34 
35  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort);
36 
37  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {throw exception_io_denied();}
38 
39  t_filesize get_size(abort_callback & p_abort) {return get_buffer_size();}
40  t_filesize get_position(abort_callback & p_abort) {return m_offset;}
41  void seek(t_filesize position,abort_callback & p_abort);
42  void reopen(abort_callback & p_abort) {seek(0,p_abort);}
43 
44  bool can_seek() {return true;}
45  bool is_in_memory() {return true;}
46 
47 protected:
48  virtual const void * get_buffer() = 0;
49  virtual t_size get_buffer_size() = 0;
50  virtual t_filetimestamp get_timestamp(abort_callback & p_abort) = 0;
51  virtual bool get_content_type(pfc::string_base &) {return false;}
52  inline void seek_internal(t_size p_offset) {if (p_offset > get_buffer_size()) throw exception_io_seek_out_of_range(); m_offset = p_offset;}
53 private:
55 };
56 
58 public:
59  reader_membuffer_simple(const void * ptr, t_size size, t_filetimestamp ts = filetimestamp_invalid, bool is_remote = false) : m_isRemote(is_remote), m_ts(ts) {
60  m_data.set_size_discard(size);
61  memcpy(m_data.get_ptr(), ptr, size);
62  }
63  const void * get_buffer() {return m_data.get_ptr();}
64  t_size get_buffer_size() {return m_data.get_size();}
65  t_filetimestamp get_timestamp(abort_callback & p_abort) {return m_ts;}
66  bool is_remote() {return m_isRemote;}
67 private:
70  bool m_isRemote;
71 };
72 
74 {
75 public:
76  t_filetimestamp get_timestamp(abort_callback & p_abort) {return m_timestamp;}
77  bool is_remote() {return m_remote;}
78 
80  static bool g_create(service_ptr_t<file> & p_out,const service_ptr_t<file> & p_src,abort_callback & p_abort) {
82  if (!ptr->init(p_src,p_abort)) return false;
83  p_out = ptr.get_ptr();
84  return true;
85  }
87  if (m_contentType.is_empty()) return false;
88  out = m_contentType; return true;
89  }
90 private:
91  const void * get_buffer() {return m_buffer.get_ptr();}
92  t_size get_buffer_size() {return m_buffer.get_size();}
93 
94  bool init(const service_ptr_t<file> & p_src,abort_callback & p_abort) {
95  if (p_src->is_in_memory()) return false;//already buffered
96  if (!p_src->get_content_type(m_contentType)) m_contentType.reset();
97  m_remote = p_src->is_remote();
98 
99  t_size size = pfc::downcast_guarded<t_size>(p_src->get_size(p_abort));
100 
101  m_buffer.set_size(size);
102 
103  p_src->reopen(p_abort);
104 
105  p_src->read_object(m_buffer.get_ptr(),size,p_abort);
106 
107  m_timestamp = p_src->get_timestamp(p_abort);
108 
109  return true;
110  }
111 
112 
115  bool m_remote;
117 
118 };
119 
124 
125 public:
126  static file::ptr g_create(file::ptr base, t_filesize offset, t_filesize size, abort_callback & abort) {
128  if (offset + size < offset) throw pfc::exception_overflow();
129  r->init(base, offset, offset + size, abort);
130  return r;
131  }
132  reader_limited() {begin=0;end=0;}
134  r = p_r;
135  begin = p_begin;
136  end = p_end;
137  reopen(p_abort);
138  }
139 
140  void init(const service_ptr_t<file> & p_r,t_filesize p_begin,t_filesize p_end,abort_callback & p_abort) {
141  r = p_r;
142  begin = p_begin;
143  end = p_end;
144  reopen(p_abort);
145  }
146 
147  t_filetimestamp get_timestamp(abort_callback & p_abort) {return r->get_timestamp(p_abort);}
148 
149  t_size read(void *p_buffer, t_size p_bytes,abort_callback & p_abort) {
150  t_filesize pos;
151  pos = r->get_position(p_abort);
152  if (p_bytes > end - pos) p_bytes = (t_size)(end - pos);
153  return r->read(p_buffer,p_bytes,p_abort);
154  }
155 
156  t_filesize get_size(abort_callback & p_abort) {return end-begin;}
157 
159  return r->get_position(p_abort) - begin;
160  }
161 
162  void seek(t_filesize position,abort_callback & p_abort) {
163  r->seek(position+begin,p_abort);
164  }
165  bool can_seek() {return r->can_seek();}
166  bool is_remote() {return r->is_remote();}
167 
168  bool get_content_type(pfc::string_base &) {return false;}
169 
170  void reopen(abort_callback & p_abort) {
171  seekInternal(begin, p_abort);
172  }
173 private:
174  void seekInternal( t_filesize position, abort_callback & abort ) {
175  if (r->can_seek()) {
176  r->seek(position, abort);
177  } else {
178  t_filesize positionWas = r->get_position(abort);
179  if (positionWas == filesize_invalid || positionWas > position) {
180  r->reopen(abort);
181  try { r->skip_object(position, abort); }
182  catch (exception_io_data) { throw exception_io_seek_out_of_range(); }
183  } else {
184  t_filesize skipMe = position - positionWas;
185  if (skipMe > 0) {
186  try { r->skip_object(skipMe, abort); }
187  catch (exception_io_data) { throw exception_io_seek_out_of_range(); }
188  }
189  }
190  }
191  }
192 };
193 
195 {
196 public:
197  template<typename t_array> stream_reader_memblock_ref(const t_array & p_array) : m_data(p_array.get_ptr()), m_data_size(p_array.get_size()), m_pointer(0) {
199  }
200  stream_reader_memblock_ref(const void * p_data,t_size p_data_size) : m_data((const unsigned char*)p_data), m_data_size(p_data_size), m_pointer(0) {}
201  stream_reader_memblock_ref() : m_data(NULL), m_data_size(0), m_pointer(0) {}
202 
203  template<typename t_array> void set_data(const t_array & data) {
205  set_data(data.get_ptr(), data.get_size());
206  }
207 
208  void set_data(const void * data, t_size dataSize) {
209  m_pointer = 0;
210  m_data = reinterpret_cast<const unsigned char*>(data);
211  m_data_size = dataSize;
212  }
213 
214  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
215  t_size delta = pfc::min_t(p_bytes, get_remaining());
216  memcpy(p_buffer,m_data+m_pointer,delta);
217  m_pointer += delta;
218  return delta;
219  }
220  void read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
221  if (p_bytes > get_remaining()) throw exception_io_data_truncation();
222  memcpy(p_buffer,m_data+m_pointer,p_bytes);
223  m_pointer += p_bytes;
224  }
226  t_size remaining = get_remaining();
227  if (p_bytes >= remaining) {
228  m_pointer = m_data_size; return remaining;
229  } else {
230  m_pointer += (t_size)p_bytes; return p_bytes;
231  }
232  }
233  void skip_object(t_filesize p_bytes,abort_callback & p_abort) {
234  if (p_bytes > get_remaining()) {
235  throw exception_io_data_truncation();
236  } else {
237  m_pointer += (t_size)p_bytes;
238  }
239  }
240  void seek_(t_size offset) {
241  PFC_ASSERT( offset <= m_data_size );
242  m_pointer = offset;
243  }
244  const void * get_ptr_() const {return m_data + m_pointer;}
245  t_size get_remaining() const {return m_data_size - m_pointer;}
246  void reset() {m_pointer = 0;}
247 private:
248  const unsigned char * m_data;
249  t_size m_data_size,m_pointer;
250 };
251 
253 public:
254  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
255  p_abort.check();
256  t_size base = m_buffer.get_size();
257  if (base + p_bytes < base) throw std::bad_alloc();
258  m_buffer.set_size(base + p_bytes);
259  memcpy( (t_uint8*) m_buffer.get_ptr() + base, p_buffer, p_bytes );
260  }
261 
263 
265 };
266 
267 template<class t_storage>
269 {
270 public:
271  stream_writer_buffer_append_ref_t(t_storage & p_output) : m_output(p_output) {}
272  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
273  PFC_STATIC_ASSERT( sizeof(m_output[0]) == 1 );
274  p_abort.check();
275  t_size base = m_output.get_size();
276  if (base + p_bytes < base) throw std::bad_alloc();
277  m_output.set_size(base + p_bytes);
278  memcpy( (t_uint8*) m_output.get_ptr() + base, p_buffer, p_bytes );
279  }
280 private:
281  t_storage & m_output;
282 };
283 
285 public:
286  stream_reader_limited_ref(stream_reader * p_reader,t_filesize p_limit) : m_reader(p_reader), m_remaining(p_limit) {}
287 
288  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
289  if (p_bytes > m_remaining) p_bytes = (t_size)m_remaining;
290 
291  t_size done = m_reader->read(p_buffer,p_bytes,p_abort);
292  m_remaining -= done;
293  return done;
294  }
295 
296  inline t_filesize get_remaining() const {return m_remaining;}
297 
299  if (p_bytes > m_remaining) p_bytes = m_remaining;
300  t_filesize done = m_reader->skip(p_bytes,p_abort);
301  m_remaining -= done;
302  return done;
303  }
304 
305  void flush_remaining(abort_callback & p_abort) {
306  if (m_remaining > 0) skip_object(m_remaining,p_abort);
307  }
308 
309 private:
312 };
313 
315 {
316 public:
317  stream_writer_chunk_dwordheader(const service_ptr_t<file> & p_writer) : m_writer(p_writer) {}
318 
319  void initialize(abort_callback & p_abort) {
320  m_headerposition = m_writer->get_position(p_abort);
321  m_written = 0;
322  m_writer->write_lendian_t((t_uint32)0,p_abort);
323  }
324 
325  void finalize(abort_callback & p_abort) {
326  t_filesize end_offset;
327  end_offset = m_writer->get_position(p_abort);
328  m_writer->seek(m_headerposition,p_abort);
329  m_writer->write_lendian_t(pfc::downcast_guarded<t_uint32>(m_written),p_abort);
330  m_writer->seek(end_offset,p_abort);
331  }
332 
333  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
334  m_writer->write(p_buffer,p_bytes,p_abort);
335  m_written += p_bytes;
336  }
337 
338 private:
342 };
343 
345 {
346 public:
347  stream_writer_chunk(stream_writer * p_writer) : m_writer(p_writer), m_buffer_state(0) {}
348 
349  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort);
350 
351  void flush(abort_callback & p_abort);//must be called after writing before object is destroyed
352 
353 private:
355  unsigned m_buffer_state;
356  unsigned char m_buffer[255];
357 };
358 
360 {
361 public:
362  stream_reader_chunk(stream_reader * p_reader) : m_reader(p_reader), m_buffer_state(0), m_buffer_size(0), m_eof(false) {}
363 
364  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort);
365 
366  void flush(abort_callback & p_abort);//must be called after reading before object is destroyed
367 
368  static void g_skip(stream_reader * p_stream,abort_callback & p_abort);
369 
370 private:
372  t_size m_buffer_state, m_buffer_size;
373  bool m_eof;
374  unsigned char m_buffer[255];
375 };
376 
377 class stream_reader_dummy : public stream_reader { t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {return 0;} };
378 
379 
380 
381 
382 
383 
384 
385 
386 
387 
388 
389 
390 
391 
392 
393 
394 
395 
396 template<bool isBigEndian = false> class stream_reader_formatter {
397 public:
398  stream_reader_formatter(stream_reader & p_stream,abort_callback & p_abort) : m_stream(p_stream), m_abort(p_abort) {}
399 
400  template<typename t_int> void read_int(t_int & p_out) {
401  if (isBigEndian) m_stream.read_bendian_t(p_out,m_abort);
402  else m_stream.read_lendian_t(p_out,m_abort);
403  }
404 
405  void read_raw(void * p_buffer,t_size p_bytes) {
406  m_stream.read_object(p_buffer,p_bytes,m_abort);
407  }
408 
409  void skip(t_size p_bytes) {m_stream.skip_object(p_bytes,m_abort);}
410 
411  template<typename TArray> void read_raw(TArray& data) {
413  read_raw(data.get_ptr(),data.get_size());
414  }
415  template<typename TArray> void read_byte_block(TArray & data) {
417  t_uint32 size; read_int(size); data.set_size(size);
418  read_raw(data);
419  }
420  template<typename TArray> void read_array(TArray & data) {
421  t_uint32 size; *this >> size; data.set_size(size);
422  for(t_uint32 walk = 0; walk < size; ++walk) *this >> data[walk];
423  }
425  m_stream.read_string_nullterm( out, m_abort );
426  }
429 };
430 
431 template<bool isBigEndian = false> class stream_writer_formatter {
432 public:
433  stream_writer_formatter(stream_writer & p_stream,abort_callback & p_abort) : m_stream(p_stream), m_abort(p_abort) {}
434 
435  template<typename t_int> void write_int(t_int p_int) {
436  if (isBigEndian) m_stream.write_bendian_t(p_int,m_abort);
437  else m_stream.write_lendian_t(p_int,m_abort);
438  }
439 
440  void write_raw(const void * p_buffer,t_size p_bytes) {
441  m_stream.write_object(p_buffer,p_bytes,m_abort);
442  }
443  template<typename TArray> void write_raw(const TArray& data) {
445  write_raw(data.get_ptr(),data.get_size());
446  }
447 
448  template<typename TArray> void write_byte_block(const TArray& data) {
450  write_int( pfc::downcast_guarded<t_uint32>(data.get_size()) );
451  write_raw( data );
452  }
453  template<typename TArray> void write_array(const TArray& data) {
454  const t_uint32 size = pfc::downcast_guarded<t_uint32>(data.get_size());
455  *this << size;
456  for(t_uint32 walk = 0; walk < size; ++walk) *this << data[walk];
457  }
458 
459  void write_string(const char * str) {
460  const t_size len = strlen(str);
461  *this << pfc::downcast_guarded<t_uint32>(len);
462  write_raw(str, len);
463  }
464  void write_string(const char * str, t_size len_) {
465  const t_size len = pfc::strlen_max(str, len_);
466  *this << pfc::downcast_guarded<t_uint32>(len);
467  write_raw(str, len);
468  }
469  void write_string_nullterm( const char * str ) {
470  this->write_raw( str, strlen(str)+1 );
471  }
472 
475 };
476 
477 
478 #define __DECLARE_INT_OVERLOADS(TYPE) \
479  template<bool isBigEndian> inline stream_reader_formatter<isBigEndian> & operator>>(stream_reader_formatter<isBigEndian> & p_stream,TYPE & p_int) {typename pfc::sized_int_t<sizeof(TYPE)>::t_unsigned temp;p_stream.read_int(temp); p_int = (TYPE) temp; return p_stream;} \
480  template<bool isBigEndian> inline stream_writer_formatter<isBigEndian> & operator<<(stream_writer_formatter<isBigEndian> & p_stream,TYPE p_int) {p_stream.write_int((typename pfc::sized_int_t<sizeof(TYPE)>::t_unsigned)p_int); return p_stream;}
481 
483 __DECLARE_INT_OVERLOADS(signed char);
484 __DECLARE_INT_OVERLOADS(unsigned char);
485 __DECLARE_INT_OVERLOADS(signed short);
486 __DECLARE_INT_OVERLOADS(unsigned short);
487 
488 __DECLARE_INT_OVERLOADS(signed int);
489 __DECLARE_INT_OVERLOADS(unsigned int);
490 
491 __DECLARE_INT_OVERLOADS(signed long);
492 __DECLARE_INT_OVERLOADS(unsigned long);
493 
494 __DECLARE_INT_OVERLOADS(signed long long);
495 __DECLARE_INT_OVERLOADS(unsigned long long);
496 
497 __DECLARE_INT_OVERLOADS(wchar_t);
498 
499 
500 #undef __DECLARE_INT_OVERLOADS
501 
502 template<typename TVal> class _IsTypeByte {
503 public:
505 };
506 
507 template<bool isBigEndian,typename TVal,size_t Count> stream_reader_formatter<isBigEndian> & operator>>(stream_reader_formatter<isBigEndian> & p_stream,TVal (& p_array)[Count]) {
509  p_stream.read_raw(p_array,Count);
510  } else {
511  for(t_size walk = 0; walk < Count; ++walk) p_stream >> p_array[walk];
512  }
513  return p_stream;
514 }
515 
516 template<bool isBigEndian,typename TVal,size_t Count> stream_writer_formatter<isBigEndian> & operator<<(stream_writer_formatter<isBigEndian> & p_stream,TVal const (& p_array)[Count]) {
518  p_stream.write_raw(p_array,Count);
519  } else {
520  for(t_size walk = 0; walk < Count; ++walk) p_stream << p_array[walk];
521  }
522  return p_stream;
523 }
524 
525 #define FB2K_STREAM_READER_OVERLOAD(type) \
526  template<bool isBigEndian> stream_reader_formatter<isBigEndian> & operator>>(stream_reader_formatter<isBigEndian> & stream,type & value)
527 
528 #define FB2K_STREAM_WRITER_OVERLOAD(type) \
529  template<bool isBigEndian> stream_writer_formatter<isBigEndian> & operator<<(stream_writer_formatter<isBigEndian> & stream,const type & value)
530 
532  return stream >> value.Data1 >> value.Data2 >> value.Data3 >> value.Data4;
533 }
534 
536  return stream << value.Data1 << value.Data2 << value.Data3 << value.Data4;
537 }
538 
540  t_uint32 len; stream >> len;
541  value = stream.m_stream.read_string_ex(len,stream.m_abort);
542  return stream;
543 }
544 
546  stream << pfc::downcast_guarded<t_uint32>(value.length());
547  stream.write_raw(value.ptr(),value.length());
548  return stream;
549 }
550 
552  stream.m_stream.read_string(value, stream.m_abort);
553  return stream;
554 }
556  const char * val = value.get_ptr();
557  const t_size len = strlen(val);
558  stream << pfc::downcast_guarded<t_uint32>(len);
559  stream.write_raw(val,len);
560  return stream;
561 }
562 
563 
565  union {
566  float f; t_uint32 i;
567  } u; u.f = value;
568  return stream << u.i;
569 }
570 
572  union { float f; t_uint32 i;} u;
573  stream >> u.i; value = u.f;
574  return stream;
575 }
576 
578  union {
579  double f; t_uint64 i;
580  } u; u.f = value;
581  return stream << u.i;
582 }
583 
585  union { double f; t_uint64 i;} u;
586  stream >> u.i; value = u.f;
587  return stream;
588 }
589 
591  t_uint8 temp = value ? 1 : 0;
592  return stream << temp;
593 }
595  t_uint8 temp; stream >> temp; value = temp != 0;
596  return stream;
597 }
598 
599 template<bool BE = false>
601 public:
602  stream_writer_formatter_simple() : stream_writer_formatter<BE>(_m_stream,_m_abort), m_buffer(_m_stream.m_buffer) {}
603 
605  t_buffer & m_buffer;
606 private:
609 };
610 
611 template<bool BE = false>
613 public:
614  stream_reader_formatter_simple_ref(const void * source, t_size sourceSize) : stream_reader_formatter<BE>(_m_stream,_m_abort), _m_stream(source,sourceSize) {}
615  template<typename TSource> stream_reader_formatter_simple_ref(const TSource& source) : stream_reader_formatter<BE>(_m_stream,_m_abort), _m_stream(source) {}
617 
618  void set_data(const void * source, t_size sourceSize) {_m_stream.set_data(source,sourceSize);}
619  template<typename TSource> void set_data(const TSource & source) {_m_stream.set_data(source);}
620 
621  void reset() {_m_stream.reset();}
622  t_size get_remaining() {return _m_stream.get_remaining();}
623 
624  const void * get_ptr_() const {return _m_stream.get_ptr_();}
625 private:
628 };
629 
630 template<bool BE = false>
632 public:
634  stream_reader_formatter_simple(const void * source, t_size sourceSize) {set_data(source,sourceSize);}
635  template<typename TSource> stream_reader_formatter_simple(const TSource & source) {set_data(source);}
636 
637  void set_data(const void * source, t_size sourceSize) {
638  m_content.set_data_fromptr(reinterpret_cast<const t_uint8*>(source), sourceSize);
639  onContentChange();
640  }
641  template<typename TSource> void set_data(const TSource & source) {
642  m_content = source;
643  onContentChange();
644  }
645 private:
648  }
650 };
651 
652 
653 
654 
655 
656 
657 template<bool isBigEndian> class _stream_reader_formatter_translator {
658 public:
661  template<typename t_what> t_self & operator||(t_what & out) {m_stream >> out; return *this;}
662 private:
664 };
665 template<bool isBigEndian> class _stream_writer_formatter_translator {
666 public:
669  template<typename t_what> t_self & operator||(const t_what & in) {m_stream << in; return *this;}
670 private:
672 };
673 
674 #define FB2K_STREAM_RECORD_OVERLOAD(type, code) \
675  FB2K_STREAM_READER_OVERLOAD(type) { \
676  _stream_reader_formatter_translator<isBigEndian> streamEx(stream); \
677  streamEx || code; \
678  return stream; \
679  } \
680  FB2K_STREAM_WRITER_OVERLOAD(type) { \
681  _stream_writer_formatter_translator<isBigEndian> streamEx(stream); \
682  streamEx || code; \
683  return stream; \
684  }
685 
686 
687 
688 
689 #define FB2K_RETRY_ON_EXCEPTION(OP, ABORT, TIMEOUT, EXCEPTION) \
690  { \
691  pfc::lores_timer timer; timer.start(); \
692  for(;;) { \
693  try { {OP;} break; } \
694  catch(EXCEPTION) { if (timer.query() > TIMEOUT) throw;} \
695  ABORT.sleep(0.05); \
696  } \
697  }
698 
699 #define FB2K_RETRY_ON_EXCEPTION2(OP, ABORT, TIMEOUT, EXCEPTION1, EXCEPTION2) \
700  { \
701  pfc::lores_timer timer; timer.start(); \
702  for(;;) { \
703  try { {OP;} break; } \
704  catch(EXCEPTION1) { if (timer.query() > TIMEOUT) throw;} \
705  catch(EXCEPTION2) { if (timer.query() > TIMEOUT) throw;} \
706  ABORT.sleep(0.05); \
707  } \
708  }
709 
710 #define FB2K_RETRY_ON_EXCEPTION3(OP, ABORT, TIMEOUT, EXCEPTION1, EXCEPTION2, EXCEPTION3) \
711  { \
712  pfc::lores_timer timer; timer.start(); \
713  for(;;) { \
714  try { {OP;} break; } \
715  catch(EXCEPTION1) { if (timer.query() > TIMEOUT) throw;} \
716  catch(EXCEPTION2) { if (timer.query() > TIMEOUT) throw;} \
717  catch(EXCEPTION3) { if (timer.query() > TIMEOUT) throw;} \
718  ABORT.sleep(0.05); \
719  } \
720  }
721 
722 #define FB2K_RETRY_ON_SHARING_VIOLATION(OP, ABORT, TIMEOUT) FB2K_RETRY_ON_EXCEPTION(OP, ABORT, TIMEOUT, exception_io_sharing_violation)
723 
724 // **** WINDOWS SUCKS ****
725 // File move ops must be retried on all these because you get access-denied when some idiot is holding open handles to something you're trying to move, or already-exists on something you just told Windows to move away
726 #define FB2K_RETRY_FILE_MOVE(OP, ABORT, TIMEOUT) FB2K_RETRY_ON_EXCEPTION3(OP, ABORT, TIMEOUT, exception_io_sharing_violation, exception_io_denied, exception_io_already_exists)
727 
729 public:
730  fileRestorePositionScope(file::ptr f, abort_callback & a) : m_file(f), m_abort(a) {
731  m_offset = f->get_position(a);
732  }
734  try {
735  if (!m_abort.is_aborting()) m_file->seek(m_offset, m_abort);
736  } catch(...) {}
737  }
738 private:
739  file::ptr m_file;
742 };
743 
744 
745 // A more clever version of reader_membuffer_*.
746 // Behaves more nicely with large files within 32bit address space.
747 class reader_bigmem : public file_readonly {
748 public:
749  reader_bigmem() : m_offset() {}
750  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
751  pfc::min_acc( p_bytes, remaining() );
752  m_mem.read( p_buffer, p_bytes, m_offset );
753  m_offset += p_bytes;
754  return p_bytes;
755  }
756  void read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
757  if (p_bytes > remaining()) throw exception_io_data_truncation();
758  m_mem.read( p_buffer, p_bytes, m_offset );
759  m_offset += p_bytes;
760  }
762  pfc::min_acc( p_bytes, (t_filesize) remaining() );
763  m_offset += (size_t) p_bytes;
764  return p_bytes;
765  }
766  void skip_object(t_filesize p_bytes,abort_callback & p_abort) {
767  if (p_bytes > remaining()) throw exception_io_data_truncation();
768  m_offset += (size_t) p_bytes;
769  }
770 
771  t_filesize get_size(abort_callback & p_abort) {p_abort.check(); return m_mem.size();}
772  t_filesize get_position(abort_callback & p_abort) {p_abort.check(); return m_offset;}
773  void seek(t_filesize p_position,abort_callback & p_abort) {
774  if (p_position > m_mem.size()) throw exception_io_seek_out_of_range();
775  m_offset = (size_t) p_position;
776  }
777  bool can_seek() {return true;}
778  bool is_in_memory() {return true;}
779  void reopen(abort_callback & p_abort) {seek(0, p_abort);}
780 
781  // To be overridden by individual derived classes
782  bool get_content_type(pfc::string_base & p_out) {return false;}
784  bool is_remote() {return false;}
785 protected:
786  void resize(size_t newSize) {
787  m_offset = 0;
788  m_mem.resize( newSize );
789  }
790  size_t remaining() const {return m_mem.size() - m_offset;}
792  size_t m_offset;
793 };
794 
796 public:
798 
799  void init(file::ptr source, abort_callback & abort) {
800  source->reopen(abort);
801  t_filesize fs = source->get_size(abort);
802  if (fs > 1024*1024*1024) { // reject > 1GB
803  throw std::bad_alloc();
804  }
805  size_t s = (size_t) fs;
806  resize(s);
807  for(size_t walk = 0; walk < m_mem._sliceCount(); ++walk) {
808  source->read( m_mem._slicePtr(walk), m_mem._sliceSize(walk), abort );
809  }
810 
811  if (!source->get_content_type( m_contentType ) ) m_contentType.reset();
812  m_isRemote = source->is_remote();
813  m_ts = source->get_timestamp( abort );
814  }
815 
817  if (m_contentType.is_empty()) return false;
818  p_out = m_contentType; return true;
819  }
820  t_filetimestamp get_timestamp(abort_callback & p_abort) {return m_ts;}
821  bool is_remote() {return m_isRemote;}
822 private:
826 };
827 
828 class file_chain : public file {
829 public:
830  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
831  return m_file->read(p_buffer, p_bytes, p_abort);
832  }
833  void read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
834  m_file->read_object(p_buffer, p_bytes, p_abort);
835  }
837  return m_file->skip( p_bytes, p_abort );
838  }
839  void skip_object(t_filesize p_bytes,abort_callback & p_abort) {
840  m_file->skip_object(p_bytes, p_abort);
841  }
842  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
843  m_file->write( p_buffer, p_bytes, p_abort );
844  }
845 
847  return m_file->get_size( p_abort );
848  }
849 
851  return m_file->get_position( p_abort );
852  }
853 
854  void resize(t_filesize p_size,abort_callback & p_abort) {
855  m_file->resize( p_size, p_abort );
856  }
857 
858  void seek(t_filesize p_position,abort_callback & p_abort) {
859  m_file->seek( p_position, p_abort );
860  }
861 
862  void seek_ex(t_sfilesize p_position,t_seek_mode p_mode,abort_callback & p_abort) {
863  m_file->seek_ex( p_position, p_mode, p_abort );
864  }
865 
866  bool can_seek() {return m_file->can_seek();}
867  bool get_content_type(pfc::string_base & p_out) {return m_file->get_content_type( p_out );}
868  bool is_in_memory() {return m_file->is_in_memory();}
869  void on_idle(abort_callback & p_abort) {m_file->on_idle(p_abort);}
870 #if FOOBAR2000_TARGET_VERSION >= 2000
871  t_filestats get_stats(abort_callback & abort) { return m_file->get_stats(abort); }
872 #else
873  t_filetimestamp get_timestamp(abort_callback & p_abort) {return m_file->get_timestamp( p_abort );}
874 #endif
875  void reopen(abort_callback & p_abort) {m_file->reopen( p_abort );}
876  bool is_remote() {return m_file->is_remote();}
877 
878  file_chain( file::ptr chain ) : m_file(chain) {}
879 private:
880  file::ptr m_file;
881 };
882 
884 public:
885  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {throw exception_io_denied();}
886  void resize(t_filesize p_size,abort_callback & p_abort) {throw exception_io_denied();}
887  file_chain_readonly( file::ptr chain ) : file_chain(chain) {}
888  static file::ptr create( file::ptr chain ) { return new service_impl_t< file_chain_readonly > ( chain ); }
889 };
890 
893 bool fb2kFileSelfTest(file::ptr f, abort_callback & aborter);
size_t remaining() const
void reopen(abort_callback &p_abort)
void read(const service_ptr_t< file > &p_file, abort_callback &p_abort, pfc::string_base &p_out, bool &is_utf8)
__DECLARE_INT_OVERLOADS(char)
void read_object(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
void read_object(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
void reopen(abort_callback &p_abort)
t_filesize get_size(HANDLE p_handle)
t_filetimestamp get_timestamp(abort_callback &p_abort)
t_filesize get_position(abort_callback &p_abort)
t_filesize get_position(abort_callback &p_abort)
void write_string(const char *str)
t_filesize get_position(abort_callback &p_abort)
t_size read(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
t_int64 t_sfilesize
Type used for file size related variables when a signed value is needed.
Definition: filesystem.h:10
uint8_t t_uint8
Definition: int_types.h:9
Template implementing reference-counting features of service_base. Intended for dynamic instantiation...
Definition: service_impl.h:4
reader_membuffer_simple(const void *ptr, t_size size, t_filetimestamp ts=filetimestamp_invalid, bool is_remote=false)
bool get_content_type(pfc::string_base &p_out)
This class is used to signal underlying worker code whether user has decided to abort a potentially t...
T min_t(const T &item1, const T &item2)
Definition: primitives.h:556
t_filetimestamp get_timestamp(abort_callback &p_abort)
void seek(HANDLE p_handle, t_sfilesize p_position, file::t_seek_mode p_mode)
FB2K_STREAM_READER_OVERLOAD(GUID)
Definition: pfc.h:71
pfc::bigmem m_mem
void read_array(TArray &data)
void set_data(const void *source, t_size sourceSize)
const char * get_ptr() const
uint64_t t_uint64
Definition: int_types.h:3
stream_reader_formatter_simple_ref(const TSource &source)
stream_writer_buffer_simple _m_stream
T * get_ptr() const
Definition: service.h:117
t_filesize skip(t_filesize p_bytes, abort_callback &p_abort)
file_chain_readonly(file::ptr chain)
static void g_get_canonical_path(const char *path, pfc::string_base &out)
Definition: filesystem.cpp:74
void write(const void *p_buffer, t_size p_bytes, abort_callback &p_abort)
file_path_display(const char *src)
t_filesize skip(t_filesize p_bytes, abort_callback &p_abort)
stream_writer_buffer_append_ref_t(t_storage &p_output)
abort_callback_impl abort_callback_dummy
static file::ptr create(file::ptr chain)
virtual bool get_content_type(pfc::string_base &)
void write_string_nullterm(const char *str)
reader_limited(const service_ptr_t< file > &p_r, t_filesize p_begin, t_filesize p_end, abort_callback &p_abort)
fileRestorePositionScope(file::ptr f, abort_callback &a)
const char * get_ptr() const
t_self & operator||(const t_what &in)
t_filesize get_size(abort_callback &p_abort)
stream_reader_memblock_ref(const t_array &p_array)
void write_byte_block(const TArray &data)
void write_array(const TArray &data)
void listDirectory(const char *path, abort_callback &aborter, listDirectoryFunc_t func)
void set_data(const TSource &source)
t_size read(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
stream_reader_formatter(stream_reader &p_stream, abort_callback &p_abort)
t_filesize get_position(abort_callback &p_abort)
void resize(t_filesize p_size, abort_callback &p_abort)
void write(const void *p_buffer, t_size p_bytes, abort_callback &p_abort)
static const t_filesize filesize_invalid
Invalid/unknown file size constant. Also see: t_filesize.
Definition: filesystem.h:16
stream_writer_chunk_dwordheader(const service_ptr_t< file > &p_writer)
t_size get_length() const
void init(const service_ptr_t< file > &p_r, t_filesize p_begin, t_filesize p_end, abort_callback &p_abort)
static file::ptr g_create(file::ptr base, t_filesize offset, t_filesize size, abort_callback &abort)
t_filetimestamp get_timestamp(abort_callback &p_abort)
void skip_object(t_filesize p_bytes, abort_callback &p_abort)
void flush_remaining(abort_callback &p_abort)
int t_int
Definition: int_types.h:11
void set_data(const void *data, t_size dataSize)
t_filetimestamp get_timestamp(abort_callback &p_abort)
file_chain(file::ptr chain)
t_filesize skip(t_filesize p_bytes, abort_callback &p_abort)
void read_raw(TArray &data)
stream_reader_formatter< isBigEndian > & m_stream
service_ptr_t< file > r
t_size read(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
t_size read(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
void initialize(abort_callback &p_abort)
stream_reader_formatter_simple(const TSource &source)
void seek(t_filesize p_position, abort_callback &p_abort)
const t_filetimestamp filetimestamp_invalid
Invalid/unknown file timestamp constant. Also see: t_filetimestamp.
Definition: filesystem.h:14
Contains various I/O related structures and interfaces.
Definition: filetimetools.h:1
stream_reader_memblock_ref _m_stream
void seekInternal(t_filesize position, abort_callback &abort)
t_filesize get_size(abort_callback &p_abort)
t_filestats get_stats(abort_callback &abort)
stream_reader_formatter< isBigEndian > & operator>>(stream_reader_formatter< isBigEndian > &p_stream, TVal(&p_array)[Count])
t_size strlen_max(const char *ptr, t_size max)
Definition: string_base.h:91
static bool g_create(service_ptr_t< file > &p_out, const service_ptr_t< file > &p_src, abort_callback &p_abort)
Returns false when the object could not be mirrored (too big) or did not need mirroring.
size_t t_size
Definition: int_types.h:48
t_filesize get_size(abort_callback &p_abort)
stream_reader_memblock_ref(const void *p_data, t_size p_data_size)
void resize(t_filesize p_size, abort_callback &p_abort)
bool fb2kFileSelfTest(file::ptr f, abort_callback &aborter)
Debug self-test function for testing a file object implementation, performs various behavior validity...
void skip(t_size p_bytes)
stream_writer_formatter< isBigEndian > & m_stream
stream_writer_buffer_simple::t_buffer t_buffer
void skip_object(t_filesize p_bytes, abort_callback &p_abort)
stream_writer_formatter(stream_writer &p_stream, abort_callback &p_abort)
t_filesize skip(t_filesize p_bytes, abort_callback &p_abort)
t_filetimestamp get_timestamp(abort_callback &p_abort)
void read_string_nullterm(pfc::string_base &out)
t_filetimestamp get_timestamp(abort_callback &p_abort)
file::ptr m_file
pfc::array_t< t_uint8 > m_content
bool get_content_type(pfc::string_base &out)
void write(const service_ptr_t< file > &p_file, abort_callback &p_abort, const char *p_string, bool is_utf8)
stream_writer_chunk(stream_writer *p_writer)
bool get_content_type(pfc::string_base &)
void reopen(abort_callback &p_abort)
void resize(size_t newSize)
void set_data(const TSource &source)
t_size read(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
t_uint64 t_filetimestamp
Type used for file timestamp related variables. 64-bit value representing the number of 100-nanosecon...
Definition: filesystem.h:12
void read_byte_block(TArray &data)
void write_int(t_int p_int)
void write_raw(const TArray &data)
void seek(t_filesize p_position, abort_callback &p_abort)
static void g_get_display_path(const char *path, pfc::string_base &out)
Definition: filesystem.cpp:87
void reopen(abort_callback &p_abort)
std::function< void(const char *, t_filestats const &, bool) > listDirectoryFunc_t
void write(const void *p_buffer, t_size p_bytes, abort_callback &p_abort)
t_uint64 t_filesize
Type used for file size related variables.
Definition: filesystem.h:8
void write(const void *p_buffer, t_size p_bytes, abort_callback &p_abort)
void seek(t_filesize position, abort_callback &p_abort)
bool init(const service_ptr_t< file > &p_src, abort_callback &p_abort)
stream_reader_limited_ref(stream_reader *p_reader, t_filesize p_limit)
void set_data(const void *source, t_size sourceSize)
void read_int(t_int &p_out)
void init(file::ptr source, abort_callback &abort)
pfc::array_staticsize_t< t_uint8 > m_data
t_size get_length() const
bool get_content_type(pfc::string_base &p_out)
void seek_internal(t_size p_offset)
pfc::array_t< char > m_buffer
void seek_ex(t_sfilesize p_position, t_seek_mode p_mode, abort_callback &p_abort)
stream_reader_chunk(stream_reader *p_reader)
const void * get_ptr_() const
const unsigned char * m_data
New EXPERIMENTAL string class, allowing efficient copies and returning from functions. Does not implement the string_base interface so you still need string8 in many cases. Safe to pass between DLLs, but since a reference is used, objects possibly created by other DLLs must be released before owning DLLs are unloaded.
Definition: stringNew.h:19
void skip_object(t_filesize p_bytes, abort_callback &p_abort)
stream_reader_formatter_simple(const void *source, t_size sourceSize)
stream_writer * m_writer
void read_object(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
_stream_writer_formatter_translator< isBigEndian > t_self
void on_idle(abort_callback &p_abort)
_stream_reader_formatter_translator(stream_reader_formatter< isBigEndian > &stream)
void write(const void *p_buffer, t_size p_bytes, abort_callback &p_abort)
void read_raw(void *p_buffer, t_size p_bytes)
pfc::array_t< t_uint8, pfc::alloc_fast > t_buffer
void write_raw(const void *p_buffer, t_size p_bytes)
stream_reader_formatter_simple_ref(const void *source, t_size sourceSize)
t_filesize get_remaining() const
t_size read(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
void write(const void *p_buffer, t_size p_bytes, abort_callback &p_abort)
void write_string(const char *str, t_size len_)
t_filesize get_size(abort_callback &p_abort)
void set_data(const t_array &data)
file_path_canonical(const char *src)
stream_reader * m_reader
_stream_reader_formatter_translator< isBigEndian > t_self
void min_acc(t_val &p_acc, const t_val &p_val)
Definition: primitives.h:829
_stream_writer_formatter_translator(stream_writer_formatter< isBigEndian > &stream)
FB2K_STREAM_WRITER_OVERLOAD(GUID)
void finalize(abort_callback &p_abort)
pfc::array_t< t_uint8, pfc::alloc_fast > m_buffer
uint32_t t_uint32
Definition: int_types.h:5
bool get_content_type(pfc::string_base &p_out)