Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/SDK/fsItem.cpp @ 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 #include "foobar2000-sdk-pch.h" | |
| 2 | |
| 3 | |
| 4 t_filestats2 fsItemBase::getStatsOpportunist() { | |
| 5 return filestats2_invalid; | |
| 6 } | |
| 7 | |
| 8 void fsItemBase::remove(abort_callback& aborter) { | |
| 9 getFS()->remove(this->canonicalPath()->c_str(), aborter); | |
| 10 } | |
| 11 | |
| 12 fb2k::stringRef fsItemBase::shortName() { | |
| 13 return nameWithExt(); | |
| 14 } | |
| 15 | |
| 16 file::ptr fsItemFile::openRead(abort_callback& aborter) { | |
| 17 return open(filesystem::open_mode_read, aborter); | |
| 18 } | |
| 19 file::ptr fsItemFile::openWriteExisting(abort_callback& aborter) { | |
| 20 return open(filesystem::open_mode_write_existing, aborter); | |
| 21 } | |
| 22 file::ptr fsItemFile::openWriteNew(abort_callback& aborter) { | |
| 23 return open(filesystem::open_mode_write_new, aborter); | |
| 24 } | |
| 25 | |
| 26 void fsItemFolder::removeRecur(abort_callback& aborter) { | |
| 27 auto list = this->listContents(listMode::filesAndFolders | listMode::hidden | listMode::suppressStats, aborter); | |
| 28 for (auto i : list->typed< fsItemBase >()) { | |
| 29 fsItemFolderPtr f; | |
| 30 if (f &= i) f->removeRecur(aborter); | |
| 31 else i->remove(aborter); | |
| 32 } | |
| 33 | |
| 34 this->remove(aborter); | |
| 35 } | |
| 36 | |
| 37 void fsItemFile::copyToOther(fsItemFilePtr other, abort_callback& aborter) { | |
| 38 aborter.check(); | |
| 39 | |
| 40 auto fSource = this->openRead(aborter); | |
| 41 auto fTarget = other->openWriteNew(aborter); | |
| 42 file::g_transfer_file(fSource, fTarget, aborter); | |
| 43 | |
| 44 // fTarget->commit(aborter); | |
| 45 | |
| 46 // we cannot transfer other properties, this should be overridden for such | |
| 47 } | |
| 48 | |
| 49 fsItemPtr fsItemBase::copyTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) { | |
| 50 aborter.check(); | |
| 51 { | |
| 52 fsItemFilePtr f; | |
| 53 if (f &= this) { | |
| 54 auto target = folder->createFile(desiredName, createMode, aborter); | |
| 55 f->copyToOther(target, aborter); | |
| 56 return std::move(target); | |
| 57 } | |
| 58 } | |
| 59 { | |
| 60 fsItemFolderPtr f; | |
| 61 if (f &= this) { | |
| 62 auto target = folder->createFolder(desiredName, createMode, aborter); | |
| 63 auto contents = f->listContents(listMode::filesAndFolders | listMode::hidden | listMode::suppressStats, aborter); | |
| 64 for (auto item : contents->typed<fsItemBase>()) { | |
| 65 item->copyTo(target, createMode, aborter); | |
| 66 } | |
| 67 return std::move(target); | |
| 68 } | |
| 69 } | |
| 70 PFC_ASSERT(!"Should not get here, bad fsItemBase object"); | |
| 71 return nullptr; | |
| 72 } | |
| 73 | |
| 74 fsItemPtr fsItemBase::copyTo(fsItemFolderPtr folder, unsigned createMode, abort_callback& aborter) { | |
| 75 auto temp = this->nameWithExt(); | |
| 76 return this->copyTo(folder, temp->c_str(), createMode, aborter); | |
| 77 } | |
| 78 | |
| 79 fsItemPtr fsItemBase::moveTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) { | |
| 80 auto ret = this->copyTo(folder, desiredName, createMode, aborter); | |
| 81 fsItemFolder::ptr asFolder; | |
| 82 if (asFolder &= this) { | |
| 83 asFolder->removeRecur(aborter); | |
| 84 } else { | |
| 85 this->remove(aborter); | |
| 86 } | |
| 87 return ret; | |
| 88 } | |
| 89 | |
| 90 fsItemPtr fsItemBase::moveTo(fsItemFolderPtr folder, unsigned createMode, abort_callback& aborter) { | |
| 91 auto fn = this->nameWithExt(); | |
| 92 return this->moveTo(folder, fn->c_str(), createMode, aborter); | |
| 93 } | |
| 94 fb2k::memBlockRef fsItemFile::readWhole(size_t sizeSanity, abort_callback& aborter) { | |
| 95 auto file = this->openRead(aborter); | |
| 96 auto size64 = file->get_size_ex(aborter); | |
| 97 if (size64 > sizeSanity) throw exception_io_data(); | |
| 98 auto size = (size_t)size64; | |
| 99 pfc::mem_block block; | |
| 100 block.resize(size); | |
| 101 file->read_object(block.ptr(), size, aborter); | |
| 102 return fb2k::memBlock::blockWithData(std::move(block)); | |
| 103 } | |
| 104 | |
| 105 namespace { | |
| 106 static void uniqueFn(pfc::string8& fn, unsigned add) { | |
| 107 if (add > 0) { | |
| 108 pfc::string8 fnOnly = pfc::remove_ext_v2(fn); | |
| 109 pfc::string8 ext = pfc::extract_ext_v2(fn); | |
| 110 fn = std::move(fnOnly); | |
| 111 fn << " (" << add << ")"; | |
| 112 if (ext.length() > 0) fn << "." << ext; | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 using namespace fb2k; | |
| 117 class fsItemFileStd : public fsItemFile { | |
| 118 public: | |
| 119 fsItemFileStd(filesystem::ptr fs, stringRef canonicalPath, t_filestats2 const & opportunistStats) : m_fs(fs), m_path(canonicalPath), m_opportunistStats(opportunistStats) { | |
| 120 m_opportunistStats.set_folder(false); | |
| 121 m_opportunistStats.set_remote(fs->is_remote(canonicalPath->c_str())); | |
| 122 } | |
| 123 | |
| 124 filesystem::ptr getFS() override { return m_fs; } | |
| 125 | |
| 126 bool isRemote() override { return m_fs->is_remote(m_path->c_str()); } | |
| 127 | |
| 128 t_filestats2 getStats2(uint32_t s2flags, abort_callback& a) override { | |
| 129 auto s = m_fs->get_stats2_(m_path->c_str(), s2flags, a); | |
| 130 PFC_ASSERT((s2flags & stats2_fileOrFolder) == 0 || !s.is_folder()); | |
| 131 return s; | |
| 132 } | |
| 133 | |
| 134 fb2k::stringRef canonicalPath() override { return m_path; } | |
| 135 | |
| 136 fb2k::stringRef nameWithExt() override { | |
| 137 pfc::string8 temp; | |
| 138 m_fs->extract_filename_ext(m_path->c_str(), temp); | |
| 139 return makeString(temp); | |
| 140 } | |
| 141 fb2k::stringRef shortName() override { | |
| 142 pfc::string8 temp; | |
| 143 if (m_fs->get_display_name_short_(m_path->c_str(), temp)) return makeString(temp); | |
| 144 return nameWithExt(); | |
| 145 } | |
| 146 t_filestats2 getStatsOpportunist() override { | |
| 147 return m_opportunistStats; | |
| 148 } | |
| 149 file::ptr open(uint32_t openMode, abort_callback& aborter) override { | |
| 150 file::ptr ret; | |
| 151 m_fs->open(ret, m_path->c_str(), openMode, aborter); | |
| 152 return ret; | |
| 153 } | |
| 154 fb2k::memBlockRef readWhole(size_t sizeSanity, abort_callback& aborter) override { | |
| 155 // Prefer fs->readWholeFile over fsItemFile methods as the fs object might implement it | |
| 156 return m_fs->readWholeFile(m_path->c_str(), sizeSanity, aborter); | |
| 157 } | |
| 158 fsItemPtr moveTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) override { | |
| 159 for (unsigned add = 0; ; ++add) { | |
| 160 pfc::string8 fn(desiredName); uniqueFn(fn, add); | |
| 161 pfc::string8 dst(folder->canonicalPath()->c_str()); | |
| 162 dst.end_with(m_fs->pathSeparator()); | |
| 163 dst += fn; | |
| 164 bool bDidExist = false; | |
| 165 try { | |
| 166 if (createMode == createMode::allowExisting) m_fs->move_overwrite(m_path->c_str(), dst, aborter); | |
| 167 else m_fs->move(m_path->c_str(), dst, aborter); | |
| 168 } catch (exception_io_already_exists const &) { | |
| 169 bDidExist = true; | |
| 170 } | |
| 171 | |
| 172 switch (createMode) { | |
| 173 case createMode::allowExisting: | |
| 174 break; // OK | |
| 175 case createMode::failIfExists: | |
| 176 if (bDidExist) throw exception_io_already_exists(); | |
| 177 break; // OK | |
| 178 case createMode::generateUniqueName: | |
| 179 if (bDidExist) { | |
| 180 continue; // the for loop | |
| 181 } | |
| 182 break; // OK | |
| 183 default: | |
| 184 PFC_ASSERT(!"Should not get here"); | |
| 185 break; | |
| 186 } | |
| 187 auto stats = m_opportunistStats; | |
| 188 stats.set_file(); | |
| 189 return m_fs->makeItemFileStd(dst, stats); | |
| 190 } | |
| 191 } | |
| 192 private: | |
| 193 const filesystem::ptr m_fs; | |
| 194 const stringRef m_path; | |
| 195 t_filestats2 m_opportunistStats; | |
| 196 }; | |
| 197 class fsItemFolderStd : public fsItemFolder { | |
| 198 public: | |
| 199 fsItemFolderStd(filesystem::ptr fs, stringRef canonicalPath, t_filestats2 const & opportunistStats) : m_fs(fs), m_path(canonicalPath), m_opportunistStats(opportunistStats) { | |
| 200 m_opportunistStats.set_folder(true); | |
| 201 m_opportunistStats.set_remote(fs->is_remote(canonicalPath->c_str())); | |
| 202 } | |
| 203 | |
| 204 filesystem::ptr getFS() override { return m_fs; } | |
| 205 | |
| 206 t_filestats2 getStatsOpportunist() override { | |
| 207 return m_opportunistStats; | |
| 208 } | |
| 209 | |
| 210 bool isRemote() override { return m_fs->is_remote(m_path->c_str()); } | |
| 211 | |
| 212 t_filestats2 getStats2(uint32_t s2flags, abort_callback& a) override { | |
| 213 auto s = m_fs->get_stats2_(m_path->c_str(), s2flags, a); | |
| 214 PFC_ASSERT((s2flags & stats2_fileOrFolder) == 0 || s.is_folder() ); | |
| 215 return s; | |
| 216 } | |
| 217 | |
| 218 fb2k::stringRef canonicalPath() override { return m_path; } | |
| 219 | |
| 220 fb2k::stringRef nameWithExt() override { | |
| 221 pfc::string8 temp; | |
| 222 m_fs->extract_filename_ext(m_path->c_str(), temp); | |
| 223 return makeString(temp); | |
| 224 } | |
| 225 fb2k::stringRef shortName() override { | |
| 226 pfc::string8 temp; | |
| 227 if (m_fs->get_display_name_short_(m_path->c_str(), temp)) return makeString(temp); | |
| 228 return nameWithExt(); | |
| 229 } | |
| 230 fb2k::arrayRef listContents(unsigned listMode, abort_callback& aborter) override { | |
| 231 auto out = arrayMutable::empty(); | |
| 232 filesystem::list_callback_t cb = [&] ( const char * p, t_filestats2 const & stats ) { | |
| 233 if (stats.is_folder()) { | |
| 234 if (listMode & listMode::folders) out->add(new service_impl_t< fsItemFolderStd >(m_fs, makeString(p), stats)); | |
| 235 } else { | |
| 236 if (listMode & listMode::files) out->add(new service_impl_t< fsItemFileStd >(m_fs, makeString(p), stats)); | |
| 237 } | |
| 238 }; | |
| 239 m_fs->list_directory_(m_path->c_str(), cb, listMode, aborter); | |
| 240 return out->copyConst(); | |
| 241 } | |
| 242 | |
| 243 fsItemFile::ptr findChildFile(const char* fileName, abort_callback& aborter) override { | |
| 244 auto sub = subPath(fileName); | |
| 245 auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); | |
| 246 if (!stats.is_folder()) { | |
| 247 return m_fs->makeItemFileStd(sub->c_str(), stats); | |
| 248 } | |
| 249 throw exception_io_not_found(); | |
| 250 } | |
| 251 fsItemFolder::ptr findChildFolder(const char* fileName, abort_callback& aborter) override { | |
| 252 auto sub = subPath(fileName); | |
| 253 auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); | |
| 254 if (stats.is_folder()) { | |
| 255 return m_fs->makeItemFolderStd(sub->c_str(), stats); | |
| 256 } | |
| 257 throw exception_io_not_found(); | |
| 258 } | |
| 259 fsItemBase::ptr findChild(const char* fileName, abort_callback& aborter) override { | |
| 260 auto sub = subPath(fileName); | |
| 261 auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); | |
| 262 if ( stats.is_folder() ) { | |
| 263 return m_fs->makeItemFileStd(sub->c_str(), stats ); | |
| 264 } else { | |
| 265 return m_fs->makeItemFolderStd(sub->c_str(), stats ); | |
| 266 } | |
| 267 } | |
| 268 fsItemFile::ptr createFile(const char* fileName, unsigned createMode, abort_callback& aborter) override { | |
| 269 for (unsigned add = 0; ; ++add) { | |
| 270 pfc::string8 fn(fileName); uniqueFn(fn, add); | |
| 271 auto sub = subPath(fn); | |
| 272 | |
| 273 t_filestats2 stats; | |
| 274 | |
| 275 bool bDidExist = false; | |
| 276 try { | |
| 277 stats = m_fs->get_stats2_( sub->c_str(), stats2_all, aborter ); | |
| 278 bDidExist = stats.is_file(); | |
| 279 } catch(exception_io_not_found const &) {} | |
| 280 switch (createMode) { | |
| 281 case createMode::allowExisting: | |
| 282 break; // OK | |
| 283 case createMode::failIfExists: | |
| 284 if (bDidExist) throw exception_io_already_exists(); | |
| 285 break; // OK | |
| 286 case createMode::generateUniqueName: | |
| 287 if (bDidExist) { | |
| 288 continue; // the for loop | |
| 289 } | |
| 290 break; | |
| 291 default: | |
| 292 PFC_ASSERT(!"Should not get here"); | |
| 293 break; | |
| 294 } | |
| 295 if (!bDidExist) { | |
| 296 // actually create an empty file if it did not yet exist | |
| 297 // FIX ME this should be atomic with exists() check | |
| 298 file::ptr creator; | |
| 299 m_fs->open(creator, sub->c_str(), filesystem::open_mode_write_new, aborter); | |
| 300 stats = creator->get_stats2_( stats2_all, aborter ); | |
| 301 } | |
| 302 return m_fs->makeItemFileStd(sub->c_str(), stats); | |
| 303 } | |
| 304 } | |
| 305 fsItemFolder::ptr createFolder(const char* fileName, unsigned createMode, abort_callback& aborter) override { | |
| 306 for (unsigned add = 0; ; ++add) { | |
| 307 pfc::string8 fn(fileName); uniqueFn(fn, add); | |
| 308 auto sub = subPath(fn); | |
| 309 bool bDidExist = false; | |
| 310 try { | |
| 311 m_fs->create_directory(sub->c_str(), aborter); | |
| 312 } catch (exception_io_already_exists const &) { | |
| 313 bDidExist = true; | |
| 314 } | |
| 315 switch (createMode) { | |
| 316 case createMode::allowExisting: | |
| 317 break; // OK | |
| 318 case createMode::failIfExists: | |
| 319 if (bDidExist) throw exception_io_already_exists(); | |
| 320 break; | |
| 321 case createMode::generateUniqueName: | |
| 322 if (bDidExist) { | |
| 323 continue; // the for loop | |
| 324 } | |
| 325 break; | |
| 326 default: | |
| 327 PFC_ASSERT(!"Should not get here"); | |
| 328 break; | |
| 329 } | |
| 330 // Inherit opportunist stats | |
| 331 return m_fs->makeItemFolderStd(sub->c_str(), this->m_opportunistStats); | |
| 332 } | |
| 333 } | |
| 334 fsItemPtr moveTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) override { | |
| 335 for (unsigned add = 0; ; ++add) { | |
| 336 pfc::string8 fn(desiredName); uniqueFn(fn, add); | |
| 337 pfc::string8 dst(folder->canonicalPath()->c_str()); | |
| 338 dst.end_with(m_fs->pathSeparator()); | |
| 339 dst += fn; | |
| 340 bool bDidExist = false; | |
| 341 try { | |
| 342 if (createMode == createMode::allowExisting) m_fs->move_overwrite(m_path->c_str(), dst, aborter); | |
| 343 else m_fs->move(m_path->c_str(), dst, aborter); | |
| 344 } catch (exception_io_already_exists const &) { | |
| 345 bDidExist = true; | |
| 346 } | |
| 347 | |
| 348 switch (createMode) { | |
| 349 case createMode::allowExisting: | |
| 350 break; // OK | |
| 351 case createMode::failIfExists: | |
| 352 if (bDidExist) throw exception_io_already_exists(); | |
| 353 break; // OK | |
| 354 case createMode::generateUniqueName: | |
| 355 if (bDidExist) { | |
| 356 continue; // the for loop | |
| 357 } | |
| 358 break; // OK | |
| 359 default: | |
| 360 PFC_ASSERT(!"Should not get here"); | |
| 361 break; | |
| 362 } | |
| 363 | |
| 364 return m_fs->makeItemFolderStd(dst, m_opportunistStats); | |
| 365 | |
| 366 } | |
| 367 } | |
| 368 private: | |
| 369 stringRef subPath(const char* name) { | |
| 370 pfc::string8 temp(m_path->c_str()); | |
| 371 temp.add_filename(name); | |
| 372 return makeString(temp); | |
| 373 } | |
| 374 const filesystem::ptr m_fs; | |
| 375 const stringRef m_path; | |
| 376 t_filestats2 m_opportunistStats; | |
| 377 }; | |
| 378 } | |
| 379 | |
| 380 fsItemFolder::ptr filesystem::makeItemFolderStd(const char* pathCanonical, t_filestats2 const& opportunistStats) { | |
| 381 return new service_impl_t<fsItemFolderStd>(this, makeString(pathCanonical), opportunistStats); | |
| 382 } | |
| 383 | |
| 384 fsItemFile::ptr filesystem::makeItemFileStd(const char* pathCanonical, t_filestats2 const & opportunistStats) { | |
| 385 return new service_impl_t<fsItemFileStd>(this, makeString(pathCanonical), opportunistStats); | |
| 386 } | |
| 387 fsItemBase::ptr filesystem::findItem_(const char* path, abort_callback& p_abort) { | |
| 388 filesystem_v3::ptr v3; | |
| 389 if (v3 &= this) { | |
| 390 return v3->findItem(path, p_abort); | |
| 391 } | |
| 392 auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); | |
| 393 if (stats.is_folder()) return this->makeItemFolderStd(path, stats); | |
| 394 else return this->makeItemFileStd(path, stats); | |
| 395 | |
| 396 } | |
| 397 fsItemFile::ptr filesystem::findItemFile_(const char* path, abort_callback& p_abort) { | |
| 398 filesystem_v3::ptr v3; | |
| 399 if (v3 &= this) return v3->findItemFile(path, p_abort); | |
| 400 | |
| 401 auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); | |
| 402 if (!stats.is_folder()) return this->makeItemFileStd(path, stats); | |
| 403 throw exception_io_not_found(); | |
| 404 } | |
| 405 fsItemFolder::ptr filesystem::findItemFolder_(const char* path, abort_callback& p_abort) { | |
| 406 filesystem_v3::ptr v3; | |
| 407 if (v3 &= this) return v3->findItemFolder(path, p_abort); | |
| 408 | |
| 409 auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); | |
| 410 if (stats.is_folder()) return this->makeItemFolderStd(path, stats); | |
| 411 throw exception_io_not_found(); | |
| 412 } | |
| 413 | |
| 414 | |
| 415 fsItemBase::ptr fsItemBase::fromPath(const char* path, abort_callback& aborter) { | |
| 416 return filesystem::get(path)->findItem_(path, aborter); | |
| 417 } | |
| 418 | |
| 419 fsItemFile::ptr fsItemFile::fromPath(const char* path, abort_callback& aborter) { | |
| 420 return filesystem::get(path)->findItemFile_(path, aborter); | |
| 421 } | |
| 422 | |
| 423 fsItemFolder::ptr fsItemFolder::fromPath(const char* path, abort_callback& aborter) { | |
| 424 return filesystem::get(path)->findItemFolder_(path, aborter); | |
| 425 } | |
| 426 | |
| 427 t_filestats fsItemBase::getStats(abort_callback& a) { | |
| 428 return getStats2(stats2_all, a).to_legacy(); | |
| 429 } |
