foobar2000 SDK  2015-01-14
filesystem_helper.h
Go to the documentation of this file.
1 //helper
3 public:
4  file_path_canonical(const char * src) {filesystem::g_get_canonical_path(src,m_data);}
5  operator const char * () const {return m_data.get_ptr();}
6  const char * get_ptr() const {return m_data.get_ptr();}
7  t_size get_length() const {return m_data.get_length();}
8 private:
10 };
11 
13 public:
14  file_path_display(const char * src) {filesystem::g_get_display_path(src,m_data);}
15  operator const char * () const {return m_data.get_ptr();}
16  const char * get_ptr() const {return m_data.get_ptr();}
17  t_size get_length() const {return m_data.get_length();}
18 private:
20 };
21 
22 
23 class NOVTABLE reader_membuffer_base : public file_readonly {
24 public:
25  reader_membuffer_base() : m_offset(0) {}
26 
27  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort);
28 
29  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {throw exception_io_denied();}
30 
31  t_filesize get_size(abort_callback & p_abort) {return get_buffer_size();}
32  t_filesize get_position(abort_callback & p_abort) {return m_offset;}
33  void seek(t_filesize position,abort_callback & p_abort);
34  void reopen(abort_callback & p_abort) {seek(0,p_abort);}
35 
36  bool can_seek() {return true;}
37  bool is_in_memory() {return true;}
38 
39 protected:
40  virtual const void * get_buffer() = 0;
41  virtual t_size get_buffer_size() = 0;
42  virtual t_filetimestamp get_timestamp(abort_callback & p_abort) = 0;
43  virtual bool get_content_type(pfc::string_base &) {return false;}
44  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;}
45 private:
47 };
48 
50 public:
53  memcpy(m_data.get_ptr(), ptr, size);
54  }
55  const void * get_buffer() {return m_data.get_ptr();}
58  bool is_remote() {return m_isRemote;}
59 private:
62  bool m_isRemote;
63 };
64 
66 {
67 public:
69  bool is_remote() {return m_remote;}
70 
72  static bool g_create(service_ptr_t<file> & p_out,const service_ptr_t<file> & p_src,abort_callback & p_abort) {
74  if (!ptr->init(p_src,p_abort)) return false;
75  p_out = ptr.get_ptr();
76  return true;
77  }
79  if (m_contentType.is_empty()) return false;
80  out = m_contentType; return true;
81  }
82 private:
83  const void * get_buffer() {return m_buffer.get_ptr();}
85 
86  bool init(const service_ptr_t<file> & p_src,abort_callback & p_abort) {
87  if (p_src->is_in_memory()) return false;//already buffered
88  if (!p_src->get_content_type(m_contentType)) m_contentType.reset();
89  m_remote = p_src->is_remote();
90 
91  t_size size = pfc::downcast_guarded<t_size>(p_src->get_size(p_abort));
92 
93  m_buffer.set_size(size);
94 
95  p_src->reopen(p_abort);
96 
97  p_src->read_object(m_buffer.get_ptr(),size,p_abort);
98 
99  m_timestamp = p_src->get_timestamp(p_abort);
100 
101  return true;
102  }
103 
104 
107  bool m_remote;
109 
110 };
111 
116 
117 public:
118  static file::ptr g_create(file::ptr base, t_filesize offset, t_filesize size, abort_callback & abort) {
120  if (offset + size < offset) throw pfc::exception_overflow();
121  r->init(base, offset, offset + size, abort);
122  return r;
123  }
124  reader_limited() {begin=0;end=0;}
126  r = p_r;
127  begin = p_begin;
128  end = p_end;
129  reopen(p_abort);
130  }
131 
132  void init(const service_ptr_t<file> & p_r,t_filesize p_begin,t_filesize p_end,abort_callback & p_abort) {
133  r = p_r;
134  begin = p_begin;
135  end = p_end;
136  reopen(p_abort);
137  }
138 
139  t_filetimestamp get_timestamp(abort_callback & p_abort) {return r->get_timestamp(p_abort);}
140 
141  t_size read(void *p_buffer, t_size p_bytes,abort_callback & p_abort) {
142  t_filesize pos;
143  pos = r->get_position(p_abort);
144  if (p_bytes > end - pos) p_bytes = (t_size)(end - pos);
145  return r->read(p_buffer,p_bytes,p_abort);
146  }
147 
148  t_filesize get_size(abort_callback & p_abort) {return end-begin;}
149 
151  return r->get_position(p_abort) - begin;
152  }
153 
154  void seek(t_filesize position,abort_callback & p_abort) {
155  r->seek(position+begin,p_abort);
156  }
157  bool can_seek() {return r->can_seek();}
158  bool is_remote() {return r->is_remote();}
159 
160  bool get_content_type(pfc::string_base &) {return false;}
161 
162  void reopen(abort_callback & p_abort) {
163  seekInternal(begin, p_abort);
164  }
165 private:
166  void seekInternal( t_filesize position, abort_callback & abort ) {
167  if (r->can_seek()) {
168  r->seek(position, abort);
169  } else {
170  t_filesize positionWas = r->get_position(abort);
171  if (positionWas == filesize_invalid || positionWas > position) {
172  r->reopen(abort);
173  try { r->skip_object(position, abort); }
174  catch (exception_io_data) { throw exception_io_seek_out_of_range(); }
175  } else {
176  t_filesize skipMe = position - positionWas;
177  if (skipMe > 0) {
178  try { r->skip_object(skipMe, abort); }
179  catch (exception_io_data) { throw exception_io_seek_out_of_range(); }
180  }
181  }
182  }
183  }
184 };
185 
187 {
188 public:
189  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) {
191  }
192  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) {}
194 
195  template<typename t_array> void set_data(const t_array & data) {
197  set_data(data.get_ptr(), data.get_size());
198  }
199 
200  void set_data(const void * data, t_size dataSize) {
201  m_pointer = 0;
202  m_data = reinterpret_cast<const unsigned char*>(data);
203  m_data_size = dataSize;
204  }
205 
206  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
207  t_size delta = pfc::min_t(p_bytes, get_remaining());
208  memcpy(p_buffer,m_data+m_pointer,delta);
209  m_pointer += delta;
210  return delta;
211  }
212  void read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
213  if (p_bytes > get_remaining()) throw exception_io_data_truncation();
214  memcpy(p_buffer,m_data+m_pointer,p_bytes);
215  m_pointer += p_bytes;
216  }
218  t_size remaining = get_remaining();
219  if (p_bytes >= remaining) {
220  m_pointer = m_data_size; return remaining;
221  } else {
222  m_pointer += (t_size)p_bytes; return p_bytes;
223  }
224  }
225  void skip_object(t_filesize p_bytes,abort_callback & p_abort) {
226  if (p_bytes > get_remaining()) {
227  throw exception_io_data_truncation();
228  } else {
229  m_pointer += (t_size)p_bytes;
230  }
231  }
232  void seek_(t_size offset) {
233  PFC_ASSERT( offset <= m_data_size );
234  m_pointer = offset;
235  }
236  const void * get_ptr_() const {return m_data + m_pointer;}
238  void reset() {m_pointer = 0;}
239 private:
240  const unsigned char * m_data;
242 };
243 
245 public:
246  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
247  p_abort.check();
248  t_size base = m_buffer.get_size();
249  if (base + p_bytes < base) throw std::bad_alloc();
250  m_buffer.set_size(base + p_bytes);
251  memcpy( (t_uint8*) m_buffer.get_ptr() + base, p_buffer, p_bytes );
252  }
253 
255 
257 };
258 
259 template<class t_storage>
261 {
262 public:
263  stream_writer_buffer_append_ref_t(t_storage & p_output) : m_output(p_output) {}
264  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
265  PFC_STATIC_ASSERT( sizeof(m_output[0]) == 1 );
266  p_abort.check();
267  t_size base = m_output.get_size();
268  if (base + p_bytes < base) throw std::bad_alloc();
269  m_output.set_size(base + p_bytes);
270  memcpy( (t_uint8*) m_output.get_ptr() + base, p_buffer, p_bytes );
271  }
272 private:
273  t_storage & m_output;
274 };
275 
277 public:
278  stream_reader_limited_ref(stream_reader * p_reader,t_filesize p_limit) : m_reader(p_reader), m_remaining(p_limit) {}
279 
280  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
281  if (p_bytes > m_remaining) p_bytes = (t_size)m_remaining;
282 
283  t_size done = m_reader->read(p_buffer,p_bytes,p_abort);
284  m_remaining -= done;
285  return done;
286  }
287 
288  inline t_filesize get_remaining() const {return m_remaining;}
289 
291  if (p_bytes > m_remaining) p_bytes = m_remaining;
292  t_filesize done = m_reader->skip(p_bytes,p_abort);
293  m_remaining -= done;
294  return done;
295  }
296 
297  void flush_remaining(abort_callback & p_abort) {
298  if (m_remaining > 0) skip_object(m_remaining,p_abort);
299  }
300 
301 private:
304 };
305 
307 {
308 public:
310 
311  void initialize(abort_callback & p_abort) {
312  m_headerposition = m_writer->get_position(p_abort);
313  m_written = 0;
314  m_writer->write_lendian_t((t_uint32)0,p_abort);
315  }
316 
317  void finalize(abort_callback & p_abort) {
318  t_filesize end_offset;
319  end_offset = m_writer->get_position(p_abort);
320  m_writer->seek(m_headerposition,p_abort);
321  m_writer->write_lendian_t(pfc::downcast_guarded<t_uint32>(m_written),p_abort);
322  m_writer->seek(end_offset,p_abort);
323  }
324 
325  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
326  m_writer->write(p_buffer,p_bytes,p_abort);
327  m_written += p_bytes;
328  }
329 
330 private:
334 };
335 
337 {
338 public:
340 
341  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort);
342 
343  void flush(abort_callback & p_abort);//must be called after writing before object is destroyed
344 
345 private:
347  unsigned m_buffer_state;
348  unsigned char m_buffer[255];
349 };
350 
352 {
353 public:
354  stream_reader_chunk(stream_reader * p_reader) : m_reader(p_reader), m_buffer_state(0), m_buffer_size(0), m_eof(false) {}
355 
356  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort);
357 
358  void flush(abort_callback & p_abort);//must be called after reading before object is destroyed
359 
360  static void g_skip(stream_reader * p_stream,abort_callback & p_abort);
361 
362 private:
365  bool m_eof;
366  unsigned char m_buffer[255];
367 };
368 
369 class stream_reader_dummy : public stream_reader { t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {return 0;} };
370 
371 
372 
373 
374 
375 
376 
377 
378 
379 
380 
381 
382 
383 
384 
385 
386 
387 
388 template<bool isBigEndian = false> class stream_reader_formatter {
389 public:
390  stream_reader_formatter(stream_reader & p_stream,abort_callback & p_abort) : m_stream(p_stream), m_abort(p_abort) {}
391 
392  template<typename t_int> void read_int(t_int & p_out) {
393  if (isBigEndian) m_stream.read_bendian_t(p_out,m_abort);
394  else m_stream.read_lendian_t(p_out,m_abort);
395  }
396 
397  void read_raw(void * p_buffer,t_size p_bytes) {
398  m_stream.read_object(p_buffer,p_bytes,m_abort);
399  }
400 
401  void skip(t_size p_bytes) {m_stream.skip_object(p_bytes,m_abort);}
402 
403  template<typename TArray> void read_raw(TArray& data) {
405  read_raw(data.get_ptr(),data.get_size());
406  }
407  template<typename TArray> void read_byte_block(TArray & data) {
409  t_uint32 size; read_int(size); data.set_size(size);
410  read_raw(data);
411  }
412  template<typename TArray> void read_array(TArray & data) {
413  t_uint32 size; *this >> size; data.set_size(size);
414  for(t_uint32 walk = 0; walk < size; ++walk) *this >> data[walk];
415  }
417  m_stream.read_string_nullterm( out, m_abort );
418  }
421 };
422 
423 template<bool isBigEndian = false> class stream_writer_formatter {
424 public:
425  stream_writer_formatter(stream_writer & p_stream,abort_callback & p_abort) : m_stream(p_stream), m_abort(p_abort) {}
426 
427  template<typename t_int> void write_int(t_int p_int) {
428  if (isBigEndian) m_stream.write_bendian_t(p_int,m_abort);
429  else m_stream.write_lendian_t(p_int,m_abort);
430  }
431 
432  void write_raw(const void * p_buffer,t_size p_bytes) {
433  m_stream.write_object(p_buffer,p_bytes,m_abort);
434  }
435  template<typename TArray> void write_raw(const TArray& data) {
437  write_raw(data.get_ptr(),data.get_size());
438  }
439 
440  template<typename TArray> void write_byte_block(const TArray& data) {
442  write_int( pfc::downcast_guarded<t_uint32>(data.get_size()) );
443  write_raw( data );
444  }
445  template<typename TArray> void write_array(const TArray& data) {
446  const t_uint32 size = pfc::downcast_guarded<t_uint32>(data.get_size());
447  *this << size;
448  for(t_uint32 walk = 0; walk < size; ++walk) *this << data[walk];
449  }
450 
451  void write_string(const char * str) {
452  const t_size len = strlen(str);
453  *this << pfc::downcast_guarded<t_uint32>(len);
454  write_raw(str, len);
455  }
456  void write_string(const char * str, t_size len_) {
457  const t_size len = pfc::strlen_max(str, len_);
458  *this << pfc::downcast_guarded<t_uint32>(len);
459  write_raw(str, len);
460  }
461  void write_string_nullterm( const char * str ) {
462  this->write_raw( str, strlen(str)+1 );
463  }
464 
467 };
468 
469 
470 #define __DECLARE_INT_OVERLOADS(TYPE) \
471  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;} \
472  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;}
473 
475 __DECLARE_INT_OVERLOADS(signed char);
476 __DECLARE_INT_OVERLOADS(unsigned char);
477 __DECLARE_INT_OVERLOADS(signed short);
478 __DECLARE_INT_OVERLOADS(unsigned short);
479 
480 __DECLARE_INT_OVERLOADS(signed int);
481 __DECLARE_INT_OVERLOADS(unsigned int);
482 
483 __DECLARE_INT_OVERLOADS(signed long);
484 __DECLARE_INT_OVERLOADS(unsigned long);
485 
486 __DECLARE_INT_OVERLOADS(signed long long);
487 __DECLARE_INT_OVERLOADS(unsigned long long);
488 
489 __DECLARE_INT_OVERLOADS(wchar_t);
490 
491 
492 #undef __DECLARE_INT_OVERLOADS
493 
494 template<typename TVal> class _IsTypeByte {
495 public:
497 };
498 
499 template<bool isBigEndian,typename TVal,size_t Count> stream_reader_formatter<isBigEndian> & operator>>(stream_reader_formatter<isBigEndian> & p_stream,TVal (& p_array)[Count]) {
501  p_stream.read_raw(p_array,Count);
502  } else {
503  for(t_size walk = 0; walk < Count; ++walk) p_stream >> p_array[walk];
504  }
505  return p_stream;
506 }
507 
508 template<bool isBigEndian,typename TVal,size_t Count> stream_writer_formatter<isBigEndian> & operator<<(stream_writer_formatter<isBigEndian> & p_stream,TVal const (& p_array)[Count]) {
510  p_stream.write_raw(p_array,Count);
511  } else {
512  for(t_size walk = 0; walk < Count; ++walk) p_stream << p_array[walk];
513  }
514  return p_stream;
515 }
516 
517 #define FB2K_STREAM_READER_OVERLOAD(type) \
518  template<bool isBigEndian> stream_reader_formatter<isBigEndian> & operator>>(stream_reader_formatter<isBigEndian> & stream,type & value)
519 
520 #define FB2K_STREAM_WRITER_OVERLOAD(type) \
521  template<bool isBigEndian> stream_writer_formatter<isBigEndian> & operator<<(stream_writer_formatter<isBigEndian> & stream,const type & value)
522 
524  return stream >> value.Data1 >> value.Data2 >> value.Data3 >> value.Data4;
525 }
526 
528  return stream << value.Data1 << value.Data2 << value.Data3 << value.Data4;
529 }
530 
532  t_uint32 len; stream >> len;
533  value = stream.m_stream.read_string_ex(len,stream.m_abort);
534  return stream;
535 }
536 
538  stream << pfc::downcast_guarded<t_uint32>(value.length());
539  stream.write_raw(value.ptr(),value.length());
540  return stream;
541 }
542 
544  stream.m_stream.read_string(value, stream.m_abort);
545  return stream;
546 }
548  const char * val = value.get_ptr();
549  const t_size len = strlen(val);
550  stream << pfc::downcast_guarded<t_uint32>(len);
551  stream.write_raw(val,len);
552  return stream;
553 }
554 
555 
557  union {
558  float f; t_uint32 i;
559  } u; u.f = value;
560  return stream << u.i;
561 }
562 
564  union { float f; t_uint32 i;} u;
565  stream >> u.i; value = u.f;
566  return stream;
567 }
568 
570  union {
571  double f; t_uint64 i;
572  } u; u.f = value;
573  return stream << u.i;
574 }
575 
577  union { double f; t_uint64 i;} u;
578  stream >> u.i; value = u.f;
579  return stream;
580 }
581 
583  t_uint8 temp = value ? 1 : 0;
584  return stream << temp;
585 }
587  t_uint8 temp; stream >> temp; value = temp != 0;
588  return stream;
589 }
590 
591 template<bool BE = false>
593 public:
595 
597  t_buffer & m_buffer;
598 private:
601 };
602 
603 template<bool BE = false>
605 public:
606  stream_reader_formatter_simple_ref(const void * source, t_size sourceSize) : stream_reader_formatter<BE>(_m_stream,_m_abort), _m_stream(source,sourceSize) {}
607  template<typename TSource> stream_reader_formatter_simple_ref(const TSource& source) : stream_reader_formatter<BE>(_m_stream,_m_abort), _m_stream(source) {}
609 
610  void set_data(const void * source, t_size sourceSize) {_m_stream.set_data(source,sourceSize);}
611  template<typename TSource> void set_data(const TSource & source) {_m_stream.set_data(source);}
612 
613  void reset() {_m_stream.reset();}
615 
616  const void * get_ptr_() const {return _m_stream.get_ptr_();}
617 private:
620 };
621 
622 template<bool BE = false>
624 public:
626  stream_reader_formatter_simple(const void * source, t_size sourceSize) {set_data(source,sourceSize);}
627  template<typename TSource> stream_reader_formatter_simple(const TSource & source) {set_data(source);}
628 
629  void set_data(const void * source, t_size sourceSize) {
630  m_content.set_data_fromptr(reinterpret_cast<const t_uint8*>(source), sourceSize);
631  onContentChange();
632  }
633  template<typename TSource> void set_data(const TSource & source) {
634  m_content = source;
635  onContentChange();
636  }
637 private:
640  }
642 };
643 
644 
645 
646 
647 
648 
649 template<bool isBigEndian> class _stream_reader_formatter_translator {
650 public:
653  template<typename t_what> t_self & operator||(t_what & out) {m_stream >> out; return *this;}
654 private:
656 };
657 template<bool isBigEndian> class _stream_writer_formatter_translator {
658 public:
661  template<typename t_what> t_self & operator||(const t_what & in) {m_stream << in; return *this;}
662 private:
664 };
665 
666 #define FB2K_STREAM_RECORD_OVERLOAD(type, code) \
667  FB2K_STREAM_READER_OVERLOAD(type) { \
668  _stream_reader_formatter_translator<isBigEndian> streamEx(stream); \
669  streamEx || code; \
670  return stream; \
671  } \
672  FB2K_STREAM_WRITER_OVERLOAD(type) { \
673  _stream_writer_formatter_translator<isBigEndian> streamEx(stream); \
674  streamEx || code; \
675  return stream; \
676  }
677 
678 
679 
680 
681 #define FB2K_RETRY_ON_EXCEPTION(OP, ABORT, TIMEOUT, EXCEPTION) \
682  { \
683  pfc::lores_timer timer; timer.start(); \
684  for(;;) { \
685  try { {OP;} break; } \
686  catch(EXCEPTION) { if (timer.query() > TIMEOUT) throw;} \
687  ABORT.sleep(0.05); \
688  } \
689  }
690 
691 #define FB2K_RETRY_ON_EXCEPTION2(OP, ABORT, TIMEOUT, EXCEPTION1, EXCEPTION2) \
692  { \
693  pfc::lores_timer timer; timer.start(); \
694  for(;;) { \
695  try { {OP;} break; } \
696  catch(EXCEPTION1) { if (timer.query() > TIMEOUT) throw;} \
697  catch(EXCEPTION2) { if (timer.query() > TIMEOUT) throw;} \
698  ABORT.sleep(0.05); \
699  } \
700  }
701 
702 #define FB2K_RETRY_ON_EXCEPTION3(OP, ABORT, TIMEOUT, EXCEPTION1, EXCEPTION2, EXCEPTION3) \
703  { \
704  pfc::lores_timer timer; timer.start(); \
705  for(;;) { \
706  try { {OP;} break; } \
707  catch(EXCEPTION1) { if (timer.query() > TIMEOUT) throw;} \
708  catch(EXCEPTION2) { if (timer.query() > TIMEOUT) throw;} \
709  catch(EXCEPTION3) { if (timer.query() > TIMEOUT) throw;} \
710  ABORT.sleep(0.05); \
711  } \
712  }
713 
714 #define FB2K_RETRY_ON_SHARING_VIOLATION(OP, ABORT, TIMEOUT) FB2K_RETRY_ON_EXCEPTION(OP, ABORT, TIMEOUT, exception_io_sharing_violation)
715 
716 // **** WINDOWS SUCKS ****
717 // 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
718 #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)
719 
721 public:
723  m_offset = f->get_position(a);
724  }
726  try {
727  if (!m_abort.is_aborting()) m_file->seek(m_offset, m_abort);
728  } catch(...) {}
729  }
730 private:
731  file::ptr m_file;
734 };
735 
736 
737 // A more clever version of reader_membuffer_*.
738 // Behaves more nicely with large files within 32bit address space.
739 class reader_bigmem : public file_readonly {
740 public:
742  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
743  pfc::min_acc( p_bytes, remaining() );
744  m_mem.read( p_buffer, p_bytes, m_offset );
745  m_offset += p_bytes;
746  return p_bytes;
747  }
748  void read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
749  if (p_bytes > remaining()) throw exception_io_data_truncation();
750  m_mem.read( p_buffer, p_bytes, m_offset );
751  m_offset += p_bytes;
752  }
754  pfc::min_acc( p_bytes, (t_filesize) remaining() );
755  m_offset += (size_t) p_bytes;
756  return p_bytes;
757  }
758  void skip_object(t_filesize p_bytes,abort_callback & p_abort) {
759  if (p_bytes > remaining()) throw exception_io_data_truncation();
760  m_offset += (size_t) p_bytes;
761  }
762 
763  t_filesize get_size(abort_callback & p_abort) {p_abort.check(); return m_mem.size();}
764  t_filesize get_position(abort_callback & p_abort) {p_abort.check(); return m_offset;}
765  void seek(t_filesize p_position,abort_callback & p_abort) {
766  if (p_position > m_mem.size()) throw exception_io_seek_out_of_range();
767  m_offset = (size_t) p_position;
768  }
769  bool can_seek() {return true;}
770  bool is_in_memory() {return true;}
771  void reopen(abort_callback & p_abort) {seek(0, p_abort);}
772 
773  // To be overridden by individual derived classes
774  bool get_content_type(pfc::string_base & p_out) {return false;}
776  bool is_remote() {return false;}
777 protected:
778  void resize(size_t newSize) {
779  m_offset = 0;
780  m_mem.resize( newSize );
781  }
782  size_t remaining() const {return m_mem.size() - m_offset;}
784  size_t m_offset;
785 };
786 
788 public:
790 
791  void init(file::ptr source, abort_callback & abort) {
792  source->reopen(abort);
793  t_filesize fs = source->get_size(abort);
794  if (fs > 1024*1024*1024) { // reject > 1GB
795  throw std::bad_alloc();
796  }
797  size_t s = (size_t) fs;
798  resize(s);
799  for(size_t walk = 0; walk < m_mem._sliceCount(); ++walk) {
800  source->read( m_mem._slicePtr(walk), m_mem._sliceSize(walk), abort );
801  }
802 
803  if (!source->get_content_type( m_contentType ) ) m_contentType.reset();
804  m_isRemote = source->is_remote();
805  m_ts = source->get_timestamp( abort );
806  }
807 
809  if (m_contentType.is_empty()) return false;
810  p_out = m_contentType; return true;
811  }
813  bool is_remote() {return m_isRemote;}
814 private:
818 };
819 
820 class file_chain : public file {
821 public:
822  t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
823  return m_file->read(p_buffer, p_bytes, p_abort);
824  }
825  void read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
826  m_file->read_object(p_buffer, p_bytes, p_abort);
827  }
829  return m_file->skip( p_bytes, p_abort );
830  }
831  void skip_object(t_filesize p_bytes,abort_callback & p_abort) {
832  m_file->skip_object(p_bytes, p_abort);
833  }
834  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
835  m_file->write( p_buffer, p_bytes, p_abort );
836  }
837 
839  return m_file->get_size( p_abort );
840  }
841 
843  return m_file->get_position( p_abort );
844  }
845 
846  void resize(t_filesize p_size,abort_callback & p_abort) {
847  m_file->resize( p_size, p_abort );
848  }
849 
850  void seek(t_filesize p_position,abort_callback & p_abort) {
851  m_file->seek( p_position, p_abort );
852  }
853 
854  void seek_ex(t_sfilesize p_position,t_seek_mode p_mode,abort_callback & p_abort) {
855  m_file->seek_ex( p_position, p_mode, p_abort );
856  }
857 
858  bool can_seek() {return m_file->can_seek();}
859  bool get_content_type(pfc::string_base & p_out) {return m_file->get_content_type( p_out );}
860  bool is_in_memory() {return m_file->is_in_memory();}
861  void on_idle(abort_callback & p_abort) {m_file->on_idle(p_abort);}
862 #if FOOBAR2000_TARGET_VERSION >= 2000
863  t_filestats get_stats(abort_callback & abort) { return m_file->get_stats(abort); }
864 #else
865  t_filetimestamp get_timestamp(abort_callback & p_abort) {return m_file->get_timestamp( p_abort );}
866 #endif
867  void reopen(abort_callback & p_abort) {m_file->reopen( p_abort );}
868  bool is_remote() {return m_file->is_remote();}
869 
870  file_chain( file::ptr chain ) : m_file(chain) {}
871 private:
872  file::ptr m_file;
873 };
874 
876 public:
877  void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {throw exception_io_denied();}
878  void resize(t_filesize p_size,abort_callback & p_abort) {throw exception_io_denied();}
879  file_chain_readonly( file::ptr chain ) : file_chain(chain) {}
880  static file::ptr create( file::ptr chain ) { return new service_impl_t< file_chain_readonly > ( chain ); }
881 };
882 
885 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)
const t_item * get_ptr() const
Definition: array.h:52
t_int64 t_sfilesize
Type used for file size related variables when a signed value is needed.
Definition: filesystem.h:10
const t_item * get_ptr() const
Definition: array.h:213
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)
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:53
pfc::bigmem m_mem
void flush(abort_callback &p_abort)
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)
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)
size_t _sliceCount()
Definition: other.h:298
abort_callback_impl abort_callback_dummy
static file::ptr create(file::ptr chain)
virtual bool get_content_type(pfc::string_base &)
size_t _sliceSize(size_t which)
Definition: other.h:299
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 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
t_size get_length() const
Definition: string_base.h:394
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)
size_t size() const
Definition: other.h:267
unsigned char m_buffer[255]
void skip_object(t_filesize p_bytes, abort_callback &p_abort)
void flush_remaining(abort_callback &p_abort)
uint8_t * _slicePtr(size_t which)
Definition: other.h:297
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
void write(const void *p_buffer, t_size p_bytes, abort_callback &p_abort)
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
stream_reader_memblock_ref _m_stream
const char * get_ptr() const
Definition: string_base.h:381
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 set_size(t_size p_size)
Definition: array.h:104
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(void *ptrOut, size_t bytes, size_t offset)
Definition: other.h:273
void read_string_nullterm(pfc::string_base &out)
t_filetimestamp get_timestamp(abort_callback &p_abort)
void flush(abort_callback &p_abort)
file::ptr m_file
pfc::array_t< t_uint8 > m_content
bool get_content_type(pfc::string_base &out)
static void g_skip(stream_reader *p_stream, abort_callback &p_abort)
bool is_empty() const
Definition: string_base.h:212
t_size read(void *p_buffer, t_size p_bytes, abort_callback &p_abort)
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 set_data_fromptr(const t_source *p_buffer, t_size p_count)
Warning: buffer pointer must not point to buffer allocated by this array (fixme). ...
Definition: array.h:139
void write_raw(const TArray &data)
void seek(t_filesize p_position, abort_callback &p_abort)
void reopen(abort_callback &p_abort)
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 resize(size_t newSize)
Definition: other.h:251
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
unsigned char m_buffer[255]
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)
t_size get_size() const
Definition: array.h:51
pfc::array_t< t_uint8, pfc::alloc_fast > t_buffer
void set_size_discard(t_size p_size)
Definition: array.h:36
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)
t_size get_size() const
Definition: array.h:130
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)