Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/SDK/filesystem_helper.h @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #pragma once | |
| 2 | |
| 3 #include <functional> | |
| 4 #include "filesystem.h" | |
| 5 | |
| 6 namespace foobar2000_io { | |
| 7 typedef std::function< void (const char *, t_filestats const & , bool ) > listDirectoryFunc_t; | |
| 8 void listDirectory( const char * path, abort_callback & aborter, listDirectoryFunc_t func); | |
| 9 | |
| 10 #ifdef _WIN32 | |
| 11 pfc::string8 stripParentFolders( const char * inPath ); | |
| 12 #endif | |
| 13 | |
| 14 void retryOnSharingViolation( std::function<void () > f, double timeout, abort_callback & a); | |
| 15 void retryOnSharingViolation( double timeout, abort_callback & a, std::function<void() > f); | |
| 16 | |
| 17 // **** WINDOWS SUCKS **** | |
| 18 // Special version of retryOnSharingViolation with workarounds for known MoveFile() bugs. | |
| 19 void retryFileMove( double timeout, abort_callback & a, std::function<void()> f); | |
| 20 | |
| 21 // **** WINDOWS SUCKS **** | |
| 22 // Special version of retryOnSharingViolation with workarounds for known idiotic problems with folder removal. | |
| 23 void retryFileDelete( double timeout, abort_callback & a, std::function<void()> f); | |
| 24 | |
| 25 class listDirectoryCallbackImpl : public directory_callback { | |
| 26 public: | |
| 27 listDirectoryCallbackImpl() {} | |
| 28 listDirectoryCallbackImpl( listDirectoryFunc_t f ) : m_func(f) {} | |
| 29 bool on_entry(filesystem *, abort_callback &, const char * p_url, bool p_is_subdirectory, const t_filestats & p_stats) override { | |
| 30 m_func(p_url, p_stats, p_is_subdirectory); | |
| 31 return true; | |
| 32 } | |
| 33 listDirectoryFunc_t m_func; | |
| 34 }; | |
| 35 | |
| 36 #ifdef _WIN32 | |
| 37 pfc::string8 winGetVolumePath(const char * fb2kPath ); | |
| 38 DWORD winVolumeFlags( const char * fb2kPath ); | |
| 39 #endif | |
| 40 } | |
| 41 | |
| 42 | |
| 43 pfc::string8 file_path_canonical(const char* src); | |
| 44 pfc::string8 file_path_display(const char* src); | |
| 45 | |
| 46 namespace fb2k { | |
| 47 //! Sane replacement for pfc::string_filename_ext(), which isn't safe to use in cross-platform code. | |
| 48 //! @returns Filename with extension extracted from path. | |
| 49 pfc::string8 filename_ext( const char * path ); | |
| 50 pfc::string8 filename_ext( const char * path, filesystem::ptr & fs_reuse); | |
| 51 //! Sane replacement for pfc::string_filename(), which isn't safe to use in cross-platform code | |
| 52 //! @returns Filename without extension extracted from path. | |
| 53 pfc::string8 filename( const char * path ); | |
| 54 } | |
| 55 | |
| 56 class stream_reader_memblock_ref : public stream_reader | |
| 57 { | |
| 58 public: | |
| 59 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) { | |
| 60 pfc::assert_byte_type<typename t_array::t_item>(); | |
| 61 } | |
| 62 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) {} | |
| 63 stream_reader_memblock_ref() : m_data(NULL), m_data_size(0), m_pointer(0) {} | |
| 64 | |
| 65 template<typename t_array> void set_data(const t_array & data) { | |
| 66 pfc::assert_byte_type<typename t_array::t_item>(); | |
| 67 set_data(data.get_ptr(), data.get_size()); | |
| 68 } | |
| 69 | |
| 70 void set_data(const void * data, t_size dataSize) { | |
| 71 m_pointer = 0; | |
| 72 m_data = reinterpret_cast<const unsigned char*>(data); | |
| 73 m_data_size = dataSize; | |
| 74 } | |
| 75 | |
| 76 t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 77 p_abort.check(); | |
| 78 t_size delta = pfc::min_t(p_bytes, get_remaining()); | |
| 79 memcpy(p_buffer,m_data+m_pointer,delta); | |
| 80 m_pointer += delta; | |
| 81 return delta; | |
| 82 } | |
| 83 void read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 84 p_abort.check(); | |
| 85 if (p_bytes > get_remaining()) throw exception_io_data_truncation(); | |
| 86 memcpy(p_buffer,m_data+m_pointer,p_bytes); | |
| 87 m_pointer += p_bytes; | |
| 88 } | |
| 89 t_filesize skip(t_filesize p_bytes,abort_callback & p_abort) { | |
| 90 p_abort.check(); | |
| 91 t_size remaining = get_remaining(); | |
| 92 if (p_bytes >= remaining) { | |
| 93 m_pointer = m_data_size; return remaining; | |
| 94 } else { | |
| 95 m_pointer += (t_size)p_bytes; return p_bytes; | |
| 96 } | |
| 97 } | |
| 98 void skip_object(t_filesize p_bytes,abort_callback & p_abort) { | |
| 99 p_abort.check(); | |
| 100 if (p_bytes > get_remaining()) { | |
| 101 throw exception_io_data_truncation(); | |
| 102 } else { | |
| 103 m_pointer += (t_size)p_bytes; | |
| 104 } | |
| 105 } | |
| 106 void seek_(t_size offset) { | |
| 107 PFC_ASSERT( offset <= m_data_size ); | |
| 108 m_pointer = offset; | |
| 109 } | |
| 110 const void * get_ptr_() const {return m_data + m_pointer;} | |
| 111 t_size get_remaining() const {return m_data_size - m_pointer;} | |
| 112 void reset() {m_pointer = 0;} | |
| 113 private: | |
| 114 const unsigned char * m_data; | |
| 115 t_size m_data_size,m_pointer; | |
| 116 }; | |
| 117 | |
| 118 template<typename buffer_t> | |
| 119 class stream_writer_buffer_simple_t : public stream_writer { | |
| 120 public: | |
| 121 void write(const void * p_buffer, t_size p_bytes, abort_callback & p_abort) { | |
| 122 p_abort.check(); | |
| 123 t_size base = m_buffer.get_size(); | |
| 124 if (base + p_bytes < base) throw std::bad_alloc(); | |
| 125 m_buffer.set_size(base + p_bytes); | |
| 126 memcpy((t_uint8*)m_buffer.get_ptr() + base, p_buffer, p_bytes); | |
| 127 } | |
| 128 typedef buffer_t t_buffer; // other classes reference this | |
| 129 t_buffer m_buffer; | |
| 130 }; | |
| 131 | |
| 132 typedef stream_writer_buffer_simple_t< pfc::array_t<t_uint8, pfc::alloc_fast> > stream_writer_buffer_simple; | |
| 133 | |
| 134 template<class t_storage> | |
| 135 class stream_writer_buffer_append_ref_t : public stream_writer | |
| 136 { | |
| 137 public: | |
| 138 stream_writer_buffer_append_ref_t(t_storage & p_output) : m_output(p_output) {} | |
| 139 void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 140 PFC_STATIC_ASSERT( sizeof(m_output[0]) == 1 ); | |
| 141 p_abort.check(); | |
| 142 t_size base = m_output.get_size(); | |
| 143 if (base + p_bytes < base) throw std::bad_alloc(); | |
| 144 m_output.set_size(base + p_bytes); | |
| 145 memcpy( (t_uint8*) m_output.get_ptr() + base, p_buffer, p_bytes ); | |
| 146 } | |
| 147 private: | |
| 148 t_storage & m_output; | |
| 149 }; | |
| 150 | |
| 151 class stream_reader_limited_ref : public stream_reader { | |
| 152 public: | |
| 153 stream_reader_limited_ref(stream_reader * p_reader,t_filesize p_limit) : m_reader(p_reader), m_remaining(p_limit) {} | |
| 154 | |
| 155 t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 156 if (p_bytes > m_remaining) p_bytes = (t_size)m_remaining; | |
| 157 | |
| 158 t_size done = m_reader->read(p_buffer,p_bytes,p_abort); | |
| 159 m_remaining -= done; | |
| 160 return done; | |
| 161 } | |
| 162 | |
| 163 inline t_filesize get_remaining() const {return m_remaining;} | |
| 164 | |
| 165 t_filesize skip(t_filesize p_bytes,abort_callback & p_abort) { | |
| 166 if (p_bytes > m_remaining) p_bytes = m_remaining; | |
| 167 t_filesize done = m_reader->skip(p_bytes,p_abort); | |
| 168 m_remaining -= done; | |
| 169 return done; | |
| 170 } | |
| 171 | |
| 172 void flush_remaining(abort_callback & p_abort) { | |
| 173 if (m_remaining > 0) skip_object(m_remaining,p_abort); | |
| 174 } | |
| 175 | |
| 176 private: | |
| 177 stream_reader * m_reader; | |
| 178 t_filesize m_remaining; | |
| 179 }; | |
| 180 | |
| 181 class stream_writer_chunk_dwordheader : public stream_writer | |
| 182 { | |
| 183 public: | |
| 184 stream_writer_chunk_dwordheader(const service_ptr_t<file> & p_writer) : m_writer(p_writer) {} | |
| 185 | |
| 186 void initialize(abort_callback & p_abort) { | |
| 187 m_headerposition = m_writer->get_position(p_abort); | |
| 188 m_written = 0; | |
| 189 m_writer->write_lendian_t((t_uint32)0,p_abort); | |
| 190 } | |
| 191 | |
| 192 void finalize(abort_callback & p_abort) { | |
| 193 t_filesize end_offset; | |
| 194 end_offset = m_writer->get_position(p_abort); | |
| 195 m_writer->seek(m_headerposition,p_abort); | |
| 196 m_writer->write_lendian_t(pfc::downcast_guarded<t_uint32>(m_written),p_abort); | |
| 197 m_writer->seek(end_offset,p_abort); | |
| 198 } | |
| 199 | |
| 200 void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 201 m_writer->write(p_buffer,p_bytes,p_abort); | |
| 202 m_written += p_bytes; | |
| 203 } | |
| 204 | |
| 205 private: | |
| 206 service_ptr_t<file> m_writer; | |
| 207 t_filesize m_headerposition; | |
| 208 t_filesize m_written; | |
| 209 }; | |
| 210 | |
| 211 class stream_writer_chunk : public stream_writer | |
| 212 { | |
| 213 public: | |
| 214 stream_writer_chunk(stream_writer * p_writer) : m_writer(p_writer), m_buffer_state(0) {} | |
| 215 | |
| 216 void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort); | |
| 217 | |
| 218 void flush(abort_callback & p_abort);//must be called after writing before object is destroyed | |
| 219 | |
| 220 private: | |
| 221 stream_writer * m_writer; | |
| 222 unsigned m_buffer_state; | |
| 223 unsigned char m_buffer[255]; | |
| 224 }; | |
| 225 | |
| 226 class stream_reader_chunk : public stream_reader | |
| 227 { | |
| 228 public: | |
| 229 stream_reader_chunk(stream_reader * p_reader) : m_reader(p_reader), m_buffer_state(0), m_buffer_size(0), m_eof(false) {} | |
| 230 | |
| 231 t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort); | |
| 232 | |
| 233 void flush(abort_callback & p_abort);//must be called after reading before object is destroyed | |
| 234 | |
| 235 static void g_skip(stream_reader * p_stream,abort_callback & p_abort); | |
| 236 | |
| 237 private: | |
| 238 stream_reader * m_reader; | |
| 239 t_size m_buffer_state, m_buffer_size; | |
| 240 bool m_eof; | |
| 241 unsigned char m_buffer[255]; | |
| 242 }; | |
| 243 | |
| 244 class stream_reader_dummy : public stream_reader { t_size read(void *,t_size,abort_callback &) override {return 0;} }; | |
| 245 | |
| 246 | |
| 247 | |
| 248 | |
| 249 | |
| 250 | |
| 251 | |
| 252 | |
| 253 | |
| 254 | |
| 255 | |
| 256 | |
| 257 | |
| 258 | |
| 259 | |
| 260 | |
| 261 | |
| 262 | |
| 263 template<bool isBigEndian = false> class stream_reader_formatter { | |
| 264 public: | |
| 265 stream_reader_formatter(stream_reader & p_stream,abort_callback & p_abort) : m_stream(p_stream), m_abort(p_abort) {} | |
| 266 | |
| 267 template<typename t_int> void read_int(t_int & p_out) { | |
| 268 if (isBigEndian) m_stream.read_bendian_t(p_out,m_abort); | |
| 269 else m_stream.read_lendian_t(p_out,m_abort); | |
| 270 } | |
| 271 | |
| 272 void read_raw(void * p_buffer,t_size p_bytes) { | |
| 273 m_stream.read_object(p_buffer,p_bytes,m_abort); | |
| 274 } | |
| 275 | |
| 276 void skip(t_size p_bytes) {m_stream.skip_object(p_bytes,m_abort);} | |
| 277 | |
| 278 template<typename TArray> void read_raw(TArray& data) { | |
| 279 pfc::assert_byte_type<typename TArray::t_item>(); | |
| 280 read_raw(data.get_ptr(),data.get_size()); | |
| 281 } | |
| 282 template<typename TArray> void read_byte_block(TArray & data) { | |
| 283 pfc::assert_byte_type<typename TArray::t_item>(); | |
| 284 t_uint32 size; read_int(size); data.set_size(size); | |
| 285 read_raw(data); | |
| 286 } | |
| 287 template<typename TArray> void read_array(TArray & data) { | |
| 288 t_uint32 size; *this >> size; data.set_size(size); | |
| 289 for(t_uint32 walk = 0; walk < size; ++walk) *this >> data[walk]; | |
| 290 } | |
| 291 void read_string_nullterm( pfc::string_base & ret ) { | |
| 292 m_stream.read_string_nullterm( ret, m_abort ); | |
| 293 } | |
| 294 pfc::string8 read_string_nullterm() { | |
| 295 pfc::string8 ret; this->read_string_nullterm(ret); return ret; | |
| 296 } | |
| 297 pfc::string8 read_string() { | |
| 298 return m_stream.read_string(m_abort); | |
| 299 } | |
| 300 stream_reader & m_stream; | |
| 301 abort_callback & m_abort; | |
| 302 }; | |
| 303 | |
| 304 template<bool isBigEndian = false> class stream_writer_formatter { | |
| 305 public: | |
| 306 stream_writer_formatter(stream_writer & p_stream,abort_callback & p_abort) : m_stream(p_stream), m_abort(p_abort) {} | |
| 307 | |
| 308 template<typename t_int> void write_int(t_int p_int) { | |
| 309 if (isBigEndian) m_stream.write_bendian_t(p_int,m_abort); | |
| 310 else m_stream.write_lendian_t(p_int,m_abort); | |
| 311 } | |
| 312 | |
| 313 void write_raw(const void * p_buffer,t_size p_bytes) { | |
| 314 m_stream.write_object(p_buffer,p_bytes,m_abort); | |
| 315 } | |
| 316 template<typename TArray> void write_raw(const TArray& data) { | |
| 317 pfc::assert_byte_type<typename TArray::t_item>(); | |
| 318 write_raw(data.get_ptr(),data.get_size()); | |
| 319 } | |
| 320 | |
| 321 template<typename TArray> void write_byte_block(const TArray& data) { | |
| 322 pfc::assert_byte_type<typename TArray::t_item>(); | |
| 323 write_int( pfc::downcast_guarded<t_uint32>(data.get_size()) ); | |
| 324 write_raw( data ); | |
| 325 } | |
| 326 template<typename TArray> void write_array(const TArray& data) { | |
| 327 const t_uint32 size = pfc::downcast_guarded<t_uint32>(data.get_size()); | |
| 328 *this << size; | |
| 329 for(t_uint32 walk = 0; walk < size; ++walk) *this << data[walk]; | |
| 330 } | |
| 331 | |
| 332 void write_string(const char * str) { | |
| 333 const t_size len = strlen(str); | |
| 334 *this << pfc::downcast_guarded<t_uint32>(len); | |
| 335 write_raw(str, len); | |
| 336 } | |
| 337 void write_string(const char * str, t_size len_) { | |
| 338 const t_size len = pfc::strlen_max(str, len_); | |
| 339 *this << pfc::downcast_guarded<t_uint32>(len); | |
| 340 write_raw(str, len); | |
| 341 } | |
| 342 void write_string_nullterm( const char * str ) { | |
| 343 this->write_raw( str, strlen(str)+1 ); | |
| 344 } | |
| 345 | |
| 346 stream_writer & m_stream; | |
| 347 abort_callback & m_abort; | |
| 348 }; | |
| 349 | |
| 350 | |
| 351 #define __DECLARE_INT_OVERLOADS(TYPE) \ | |
| 352 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;} \ | |
| 353 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;} | |
| 354 | |
| 355 __DECLARE_INT_OVERLOADS(char); | |
| 356 __DECLARE_INT_OVERLOADS(signed char); | |
| 357 __DECLARE_INT_OVERLOADS(unsigned char); | |
| 358 __DECLARE_INT_OVERLOADS(signed short); | |
| 359 __DECLARE_INT_OVERLOADS(unsigned short); | |
| 360 | |
| 361 __DECLARE_INT_OVERLOADS(signed int); | |
| 362 __DECLARE_INT_OVERLOADS(unsigned int); | |
| 363 | |
| 364 __DECLARE_INT_OVERLOADS(signed long); | |
| 365 __DECLARE_INT_OVERLOADS(unsigned long); | |
| 366 | |
| 367 __DECLARE_INT_OVERLOADS(signed long long); | |
| 368 __DECLARE_INT_OVERLOADS(unsigned long long); | |
| 369 | |
| 370 __DECLARE_INT_OVERLOADS(wchar_t); | |
| 371 | |
| 372 | |
| 373 #undef __DECLARE_INT_OVERLOADS | |
| 374 | |
| 375 template<typename TVal> class _IsTypeByte { | |
| 376 public: | |
| 377 enum {value = pfc::is_same_type<TVal,char>::value || pfc::is_same_type<TVal,unsigned char>::value || pfc::is_same_type<TVal,signed char>::value}; | |
| 378 }; | |
| 379 | |
| 380 template<bool isBigEndian,typename TVal,size_t Count> stream_reader_formatter<isBigEndian> & operator>>(stream_reader_formatter<isBigEndian> & p_stream,TVal (& p_array)[Count]) { | |
| 381 if constexpr (_IsTypeByte<TVal>::value) { | |
| 382 p_stream.read_raw(p_array,Count); | |
| 383 } else { | |
| 384 for(t_size walk = 0; walk < Count; ++walk) p_stream >> p_array[walk]; | |
| 385 } | |
| 386 return p_stream; | |
| 387 } | |
| 388 | |
| 389 template<bool isBigEndian,typename TVal,size_t Count> stream_writer_formatter<isBigEndian> & operator<<(stream_writer_formatter<isBigEndian> & p_stream,TVal const (& p_array)[Count]) { | |
| 390 if constexpr (_IsTypeByte<TVal>::value) { | |
| 391 p_stream.write_raw(p_array,Count); | |
| 392 } else { | |
| 393 for(t_size walk = 0; walk < Count; ++walk) p_stream << p_array[walk]; | |
| 394 } | |
| 395 return p_stream; | |
| 396 } | |
| 397 | |
| 398 #define FB2K_STREAM_READER_OVERLOAD(type) \ | |
| 399 template<bool isBigEndian> stream_reader_formatter<isBigEndian> & operator>>(stream_reader_formatter<isBigEndian> & stream,type & value) | |
| 400 | |
| 401 #define FB2K_STREAM_WRITER_OVERLOAD(type) \ | |
| 402 template<bool isBigEndian> stream_writer_formatter<isBigEndian> & operator<<(stream_writer_formatter<isBigEndian> & stream,const type & value) | |
| 403 | |
| 404 FB2K_STREAM_READER_OVERLOAD(GUID) { | |
| 405 return stream >> value.Data1 >> value.Data2 >> value.Data3 >> value.Data4; | |
| 406 } | |
| 407 | |
| 408 FB2K_STREAM_WRITER_OVERLOAD(GUID) { | |
| 409 return stream << value.Data1 << value.Data2 << value.Data3 << value.Data4; | |
| 410 } | |
| 411 | |
| 412 FB2K_STREAM_READER_OVERLOAD(pfc::string) { | |
| 413 t_uint32 len; stream >> len; | |
| 414 value = stream.m_stream.read_string_ex(len,stream.m_abort); | |
| 415 return stream; | |
| 416 } | |
| 417 | |
| 418 FB2K_STREAM_WRITER_OVERLOAD(pfc::string) { | |
| 419 stream << pfc::downcast_guarded<t_uint32>(value.length()); | |
| 420 stream.write_raw(value.ptr(),value.length()); | |
| 421 return stream; | |
| 422 } | |
| 423 | |
| 424 FB2K_STREAM_READER_OVERLOAD(pfc::string_base) { | |
| 425 stream.m_stream.read_string(value, stream.m_abort); | |
| 426 return stream; | |
| 427 } | |
| 428 FB2K_STREAM_WRITER_OVERLOAD(pfc::string_base) { | |
| 429 const char * val = value.get_ptr(); | |
| 430 const t_size len = strlen(val); | |
| 431 stream << pfc::downcast_guarded<t_uint32>(len); | |
| 432 stream.write_raw(val,len); | |
| 433 return stream; | |
| 434 } | |
| 435 | |
| 436 | |
| 437 FB2K_STREAM_WRITER_OVERLOAD(float) { | |
| 438 union { | |
| 439 float f; t_uint32 i; | |
| 440 } u; u.f = value; | |
| 441 return stream << u.i; | |
| 442 } | |
| 443 | |
| 444 FB2K_STREAM_READER_OVERLOAD(float) { | |
| 445 union { float f; t_uint32 i;} u; | |
| 446 stream >> u.i; value = u.f; | |
| 447 return stream; | |
| 448 } | |
| 449 | |
| 450 FB2K_STREAM_WRITER_OVERLOAD(double) { | |
| 451 union { | |
| 452 double f; t_uint64 i; | |
| 453 } u; u.f = value; | |
| 454 return stream << u.i; | |
| 455 } | |
| 456 | |
| 457 FB2K_STREAM_READER_OVERLOAD(double) { | |
| 458 union { double f; t_uint64 i;} u; | |
| 459 stream >> u.i; value = u.f; | |
| 460 return stream; | |
| 461 } | |
| 462 | |
| 463 FB2K_STREAM_WRITER_OVERLOAD(bool) { | |
| 464 t_uint8 temp = value ? 1 : 0; | |
| 465 return stream << temp; | |
| 466 } | |
| 467 FB2K_STREAM_READER_OVERLOAD(bool) { | |
| 468 t_uint8 temp; stream >> temp; value = temp != 0; | |
| 469 return stream; | |
| 470 } | |
| 471 | |
| 472 template<bool BE = false> | |
| 473 class stream_writer_formatter_simple : public stream_writer_formatter<BE> { | |
| 474 public: | |
| 475 stream_writer_formatter_simple() : stream_writer_formatter<BE>(_m_stream,fb2k::noAbort), m_buffer(_m_stream.m_buffer) {} | |
| 476 | |
| 477 typedef stream_writer_buffer_simple::t_buffer t_buffer; | |
| 478 t_buffer & m_buffer; | |
| 479 private: | |
| 480 stream_writer_buffer_simple _m_stream; | |
| 481 }; | |
| 482 | |
| 483 template<bool BE = false> | |
| 484 class stream_reader_formatter_simple_ref : public stream_reader_formatter<BE> { | |
| 485 public: | |
| 486 stream_reader_formatter_simple_ref(const void * source, t_size sourceSize) : stream_reader_formatter<BE>(_m_stream,fb2k::noAbort), _m_stream(source,sourceSize) {} | |
| 487 template<typename TSource> stream_reader_formatter_simple_ref(const TSource& source) : stream_reader_formatter<BE>(_m_stream,fb2k::noAbort), _m_stream(source) {} | |
| 488 stream_reader_formatter_simple_ref() : stream_reader_formatter<BE>(_m_stream,fb2k::noAbort) {} | |
| 489 | |
| 490 void set_data(const void * source, t_size sourceSize) {_m_stream.set_data(source,sourceSize);} | |
| 491 template<typename TSource> void set_data(const TSource & source) {_m_stream.set_data(source);} | |
| 492 | |
| 493 void reset() {_m_stream.reset();} | |
| 494 t_size get_remaining() {return _m_stream.get_remaining();} | |
| 495 | |
| 496 const void * get_ptr_() const {return _m_stream.get_ptr_();} | |
| 497 private: | |
| 498 stream_reader_memblock_ref _m_stream; | |
| 499 }; | |
| 500 | |
| 501 template<bool BE = false> | |
| 502 class stream_reader_formatter_simple : public stream_reader_formatter_simple_ref<BE> { | |
| 503 public: | |
| 504 stream_reader_formatter_simple() {} | |
| 505 stream_reader_formatter_simple(const void * source, t_size sourceSize) {set_data(source,sourceSize);} | |
| 506 template<typename TSource> stream_reader_formatter_simple(const TSource & source) {set_data(source);} | |
| 507 | |
| 508 void set_data(const void * source, t_size sourceSize) { | |
| 509 m_content.set_data_fromptr(reinterpret_cast<const t_uint8*>(source), sourceSize); | |
| 510 onContentChange(); | |
| 511 } | |
| 512 template<typename TSource> void set_data(const TSource & source) { | |
| 513 m_content = source; | |
| 514 onContentChange(); | |
| 515 } | |
| 516 private: | |
| 517 void onContentChange() { | |
| 518 stream_reader_formatter_simple_ref<BE>::set_data(m_content); | |
| 519 } | |
| 520 pfc::array_t<t_uint8> m_content; | |
| 521 }; | |
| 522 | |
| 523 | |
| 524 | |
| 525 | |
| 526 | |
| 527 | |
| 528 template<bool isBigEndian> class _stream_reader_formatter_translator { | |
| 529 public: | |
| 530 _stream_reader_formatter_translator(stream_reader_formatter<isBigEndian> & stream) : m_stream(stream) {} | |
| 531 typedef _stream_reader_formatter_translator<isBigEndian> t_self; | |
| 532 template<typename t_what> t_self & operator||(t_what & out) {m_stream >> out; return *this;} | |
| 533 private: | |
| 534 stream_reader_formatter<isBigEndian> & m_stream; | |
| 535 }; | |
| 536 template<bool isBigEndian> class _stream_writer_formatter_translator { | |
| 537 public: | |
| 538 _stream_writer_formatter_translator(stream_writer_formatter<isBigEndian> & stream) : m_stream(stream) {} | |
| 539 typedef _stream_writer_formatter_translator<isBigEndian> t_self; | |
| 540 template<typename t_what> t_self & operator||(const t_what & in) {m_stream << in; return *this;} | |
| 541 private: | |
| 542 stream_writer_formatter<isBigEndian> & m_stream; | |
| 543 }; | |
| 544 | |
| 545 #define FB2K_STREAM_RECORD_OVERLOAD(type, code) \ | |
| 546 FB2K_STREAM_READER_OVERLOAD(type) { \ | |
| 547 _stream_reader_formatter_translator<isBigEndian> streamEx(stream); \ | |
| 548 streamEx || code; \ | |
| 549 return stream; \ | |
| 550 } \ | |
| 551 FB2K_STREAM_WRITER_OVERLOAD(type) { \ | |
| 552 _stream_writer_formatter_translator<isBigEndian> streamEx(stream); \ | |
| 553 streamEx || code; \ | |
| 554 return stream; \ | |
| 555 } | |
| 556 | |
| 557 | |
| 558 | |
| 559 | |
| 560 #define FB2K_RETRY_ON_EXCEPTION(OP, ABORT, TIMEOUT, EXCEPTION) \ | |
| 561 { \ | |
| 562 pfc::lores_timer timer; timer.start(); \ | |
| 563 for(;;) { \ | |
| 564 try { {OP;} break; } \ | |
| 565 catch(const EXCEPTION &) { if (timer.query() > TIMEOUT) throw;} \ | |
| 566 ABORT.sleep(0.05); \ | |
| 567 } \ | |
| 568 } | |
| 569 | |
| 570 #define FB2K_RETRY_ON_EXCEPTION2(OP, ABORT, TIMEOUT, EXCEPTION1, EXCEPTION2) \ | |
| 571 { \ | |
| 572 pfc::lores_timer timer; timer.start(); \ | |
| 573 for(;;) { \ | |
| 574 try { {OP;} break; } \ | |
| 575 catch(const EXCEPTION1 &) { if (timer.query() > TIMEOUT) throw;} \ | |
| 576 catch(const EXCEPTION2 &) { if (timer.query() > TIMEOUT) throw;} \ | |
| 577 ABORT.sleep(0.05); \ | |
| 578 } \ | |
| 579 } | |
| 580 | |
| 581 #define FB2K_RETRY_ON_EXCEPTION3(OP, ABORT, TIMEOUT, EXCEPTION1, EXCEPTION2, EXCEPTION3) \ | |
| 582 { \ | |
| 583 pfc::lores_timer timer; timer.start(); \ | |
| 584 for(;;) { \ | |
| 585 try { {OP;} break; } \ | |
| 586 catch(const EXCEPTION1 &) { if (timer.query() > TIMEOUT) throw;} \ | |
| 587 catch(const EXCEPTION2 &) { if (timer.query() > TIMEOUT) throw;} \ | |
| 588 catch(const EXCEPTION3 &) { if (timer.query() > TIMEOUT) throw;} \ | |
| 589 ABORT.sleep(0.05); \ | |
| 590 } \ | |
| 591 } | |
| 592 | |
| 593 #define FB2K_RETRY_ON_SHARING_VIOLATION(OP, ABORT, TIMEOUT) FB2K_RETRY_ON_EXCEPTION(OP, ABORT, TIMEOUT, exception_io_sharing_violation) | |
| 594 | |
| 595 // **** WINDOWS SUCKS **** | |
| 596 // File move ops must be retried on all these because you get access-denied when someone is holding open handles to something you're trying to move, or already-exists on something you just told Windows to move away | |
| 597 #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) | |
| 598 | |
| 599 class fileRestorePositionScope { | |
| 600 public: | |
| 601 fileRestorePositionScope(file::ptr f, abort_callback & a) : m_file(f), m_abort(a) { | |
| 602 m_offset = f->get_position(a); | |
| 603 } | |
| 604 ~fileRestorePositionScope() { | |
| 605 try { | |
| 606 if (!m_abort.is_aborting()) m_file->seek(m_offset, m_abort); | |
| 607 } catch(...) {} | |
| 608 } | |
| 609 private: | |
| 610 file::ptr m_file; | |
| 611 t_filesize m_offset; | |
| 612 abort_callback & m_abort; | |
| 613 }; | |
| 614 | |
| 615 | |
| 616 //! Debug self-test function for testing a file object implementation, performs various behavior validity checks, random access etc. Output goes to fb2k console. | |
| 617 //! Returns true on success, false on failure (buggy file object implementation). | |
| 618 bool fb2kFileSelfTest(file::ptr f, abort_callback & aborter); |
