filesystem.h (18654B)
1 // This file is part of Blend2D project <https://blend2d.com> 2 // 3 // See blend2d.h or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #ifndef BLEND2D_FILESYSTEM_H_INCLUDED 7 #define BLEND2D_FILESYSTEM_H_INCLUDED 8 9 #include "array.h" 10 11 //! \addtogroup bl_filesystem 12 //! \{ 13 14 //! \name BLFile API Constants 15 //! \{ 16 17 //! File information flags, used by \ref BLFileInfo. 18 BL_DEFINE_ENUM(BLFileInfoFlags) { 19 //! File owner has read permission (compatible with 0400 octal notation). 20 BL_FILE_INFO_OWNER_R = 0x00000100u, 21 //! File owner has write permission (compatible with 0200 octal notation). 22 BL_FILE_INFO_OWNER_W = 0x00000080u, 23 //! File owner has execute permission (compatible with 0100 octal notation). 24 BL_FILE_INFO_OWNER_X = 0x00000040u, 25 //! A combination of \ref BL_FILE_INFO_OWNER_R, \ref BL_FILE_INFO_OWNER_W, and \ref BL_FILE_INFO_OWNER_X. 26 BL_FILE_INFO_OWNER_MASK = 0x000001C0u, 27 28 //! File group owner has read permission (compatible with 040 octal notation). 29 BL_FILE_INFO_GROUP_R = 0x00000020u, 30 //! File group owner has write permission (compatible with 020 octal notation). 31 BL_FILE_INFO_GROUP_W = 0x00000010u, 32 //! File group owner has execute permission (compatible with 010 octal notation). 33 BL_FILE_INFO_GROUP_X = 0x00000008u, 34 //! A combination of \ref BL_FILE_INFO_GROUP_R, \ref BL_FILE_INFO_GROUP_W, and \ref BL_FILE_INFO_GROUP_X. 35 BL_FILE_INFO_GROUP_MASK = 0x00000038u, 36 37 //! Other users have read permission (compatible with 04 octal notation). 38 BL_FILE_INFO_OTHER_R = 0x00000004u, 39 //! Other users have write permission (compatible with 02 octal notation). 40 BL_FILE_INFO_OTHER_W = 0x00000002u, 41 //! Other users have execute permission (compatible with 01 octal notation). 42 BL_FILE_INFO_OTHER_X = 0x00000001u, 43 //! A combination of \ref BL_FILE_INFO_OTHER_R, \ref BL_FILE_INFO_OTHER_W, and \ref BL_FILE_INFO_OTHER_X. 44 BL_FILE_INFO_OTHER_MASK = 0x00000007u, 45 46 //! Set user ID to file owner user ID on execution (compatible with 04000 octal notation). 47 BL_FILE_INFO_SUID = 0x00000800u, 48 //! Set group ID to file's user group ID on execution (compatible with 02000 octal notation). 49 BL_FILE_INFO_SGID = 0x00000400u, 50 51 //! A combination of all file permission bits. 52 BL_FILE_INFO_PERMISSIONS_MASK = 0x00000FFFu, 53 54 //! A flag specifying that this is a regular file. 55 BL_FILE_INFO_REGULAR = 0x00010000u, 56 //! A flag specifying that this is a directory. 57 BL_FILE_INFO_DIRECTORY = 0x00020000u, 58 //! A flag specifying that this is a symbolic link. 59 BL_FILE_INFO_SYMLINK = 0x00040000u, 60 61 //! A flag describing a character device. 62 BL_FILE_INFO_CHAR_DEVICE = 0x00100000u, 63 //! A flag describing a block device. 64 BL_FILE_INFO_BLOCK_DEVICE = 0x00200000u, 65 //! A flag describing a FIFO (named pipe). 66 BL_FILE_INFO_FIFO = 0x00400000u, 67 //! A flag describing a socket. 68 BL_FILE_INFO_SOCKET = 0x00800000u, 69 70 //! A flag describing a hidden file (Windows only). 71 BL_FILE_INFO_HIDDEN = 0x01000000u, 72 //! A flag describing a hidden file (Windows only). 73 BL_FILE_INFO_EXECUTABLE = 0x02000000u, 74 //! A flag describing an archive (Windows only). 75 BL_FILE_INFO_ARCHIVE = 0x04000000u, 76 //! A flag describing a system file (Windows only). 77 BL_FILE_INFO_SYSTEM = 0x08000000u, 78 79 //! File information is valid (the request succeeded). 80 BL_FILE_INFO_VALID = 0x80000000u 81 82 BL_FORCE_ENUM_UINT32(BL_FILE_INFO) 83 }; 84 85 //! File open flags, see \ref BLFile::open(). 86 BL_DEFINE_ENUM(BLFileOpenFlags) { 87 //! No flags. 88 BL_FILE_OPEN_NO_FLAGS = 0u, 89 90 //! Opens the file for reading. 91 //! 92 //! The following system flags are used when opening the file: 93 //! - `O_RDONLY` (Posix) 94 //! - `GENERIC_READ` (Windows) 95 BL_FILE_OPEN_READ = 0x00000001u, 96 97 //! Opens the file for writing: 98 //! 99 //! The following system flags are used when opening the file: 100 //! - `O_WRONLY` (Posix) 101 //! - `GENERIC_WRITE` (Windows) 102 BL_FILE_OPEN_WRITE = 0x00000002u, 103 104 //! Opens the file for reading & writing. 105 //! 106 //! The following system flags are used when opening the file: 107 //! - `O_RDWR` (Posix) 108 //! - `GENERIC_READ | GENERIC_WRITE` (Windows) 109 BL_FILE_OPEN_RW = 0x00000003u, 110 111 //! Creates the file if it doesn't exist or opens it if it does. 112 //! 113 //! The following system flags are used when opening the file: 114 //! - `O_CREAT` (Posix) 115 //! - `CREATE_ALWAYS` or `OPEN_ALWAYS` depending on other flags (Windows) 116 BL_FILE_OPEN_CREATE = 0x00000004u, 117 118 //! Opens the file for deleting or renaming (Windows). 119 //! 120 //! Adds `DELETE` flag when opening the file to `ACCESS_MASK`. 121 BL_FILE_OPEN_DELETE = 0x00000008u, 122 123 //! Truncates the file. 124 //! 125 //! The following system flags are used when opening the file: 126 //! - `O_TRUNC` (Posix) 127 //! - `TRUNCATE_EXISTING` (Windows) 128 BL_FILE_OPEN_TRUNCATE = 0x00000010u, 129 130 //! Opens the file for reading in exclusive mode (Windows). 131 //! 132 //! Exclusive mode means to not specify the `FILE_SHARE_READ` option. 133 BL_FILE_OPEN_READ_EXCLUSIVE = 0x10000000u, 134 135 //! Opens the file for writing in exclusive mode (Windows). 136 //! 137 //! Exclusive mode means to not specify the `FILE_SHARE_WRITE` option. 138 BL_FILE_OPEN_WRITE_EXCLUSIVE = 0x20000000u, 139 140 //! Opens the file for both reading and writing (Windows). 141 //! 142 //! This is a combination of both `BL_FILE_OPEN_READ_EXCLUSIVE` and `BL_FILE_OPEN_WRITE_EXCLUSIVE`. 143 BL_FILE_OPEN_RW_EXCLUSIVE = 0x30000000u, 144 145 //! Creates the file in exclusive mode - fails if the file already exists. 146 //! 147 //! The following system flags are used when opening the file: 148 //! - `O_EXCL` (Posix) 149 //! - `CREATE_NEW` (Windows) 150 BL_FILE_OPEN_CREATE_EXCLUSIVE = 0x40000000u, 151 152 //! Opens the file for deleting or renaming in exclusive mode (Windows). 153 //! 154 //! Exclusive mode means to not specify the `FILE_SHARE_DELETE` option. 155 BL_FILE_OPEN_DELETE_EXCLUSIVE = 0x80000000u 156 157 BL_FORCE_ENUM_UINT32(BL_FILE_OPEN) 158 }; 159 160 //! File seek mode, see \ref BLFile::seek(). 161 //! 162 //! \note Seek constants should be compatible with constants used by both POSIX 163 //! and Windows API. 164 BL_DEFINE_ENUM(BLFileSeekType) { 165 //! Seek from the beginning of the file (SEEK_SET). 166 BL_FILE_SEEK_SET = 0, 167 //! Seek from the current position (SEEK_CUR). 168 BL_FILE_SEEK_CUR = 1, 169 //! Seek from the end of the file (SEEK_END). 170 BL_FILE_SEEK_END = 2, 171 172 //! Maximum value of `BLFileSeekType`. 173 BL_FILE_SEEK_MAX_VALUE = 3 174 175 BL_FORCE_ENUM_UINT32(BL_FILE_SEEK) 176 }; 177 178 //! File read flags used by \ref BLFileSystem::read_file(). 179 BL_DEFINE_ENUM(BLFileReadFlags) { 180 //! No flags. 181 BL_FILE_READ_NO_FLAGS = 0u, 182 183 //! Use memory mapping to read the content of the file. 184 //! 185 //! The destination buffer `BLArray<>` would be configured to use the memory mapped buffer instead of allocating its 186 //! own. 187 BL_FILE_READ_MMAP_ENABLED = 0x00000001u, 188 189 //! Avoid memory mapping of small files. 190 //! 191 //! The size of small file is determined by Blend2D, however, you should expect it to be 16kB or 64kB depending on 192 //! host operating system. 193 BL_FILE_READ_MMAP_AVOID_SMALL = 0x00000002u, 194 195 //! Do not fallback to regular read if memory mapping fails. It's worth noting that memory mapping would fail for 196 //! files stored on filesystem that is not local (like a mounted network filesystem, etc...). 197 BL_FILE_READ_MMAP_NO_FALLBACK = 0x00000008u 198 199 BL_FORCE_ENUM_UINT32(BL_FILE_READ) 200 }; 201 202 //! \} 203 204 //! \name BLFile C API Structs 205 //! 206 //! \{ 207 208 //! A thin abstraction over a native OS file IO [C API]. 209 struct BLFileCore { 210 //! A file handle - either a file descriptor used by POSIX or file handle used by Windows. On both platforms the 211 //! handle is always `intptr_t` to make FFI easier (it's basically the size of a pointer / machine register). 212 //! 213 //! \note A handle of value `-1` is considered invalid and/or uninitialized. This value also matches Windows API 214 //! `INVALID_HANDLE_VALUE`, which is also defined to be -1. 215 intptr_t handle; 216 }; 217 218 //! \} 219 220 //! \name BLFileInfo Structs 221 //! 222 //! \{ 223 224 //! File information. 225 struct BLFileInfo { 226 //! \name Members 227 //! \{ 228 229 uint64_t size; 230 int64_t modified_time; 231 BLFileInfoFlags flags; 232 uint32_t uid; 233 uint32_t gid; 234 uint32_t reserved[5]; 235 236 //! \} 237 238 #if defined(__cplusplus) 239 240 //! \name Accessors 241 //! \{ 242 243 //! Tests whether the file information has the given `flag` set in `flags`. 244 BL_INLINE_NODEBUG bool has_flag(BLFileInfoFlags flag) const noexcept { return (flags & flag) != 0; } 245 246 BL_INLINE_NODEBUG bool has_owner_r() const noexcept { return has_flag(BL_FILE_INFO_OWNER_R); } 247 BL_INLINE_NODEBUG bool has_owner_w() const noexcept { return has_flag(BL_FILE_INFO_OWNER_W); } 248 BL_INLINE_NODEBUG bool has_owner_x() const noexcept { return has_flag(BL_FILE_INFO_OWNER_X); } 249 250 BL_INLINE_NODEBUG bool has_group_r() const noexcept { return has_flag(BL_FILE_INFO_GROUP_R); } 251 BL_INLINE_NODEBUG bool has_group_w() const noexcept { return has_flag(BL_FILE_INFO_GROUP_W); } 252 BL_INLINE_NODEBUG bool has_group_x() const noexcept { return has_flag(BL_FILE_INFO_GROUP_X); } 253 254 BL_INLINE_NODEBUG bool has_other_r() const noexcept { return has_flag(BL_FILE_INFO_OTHER_R); } 255 BL_INLINE_NODEBUG bool has_other_w() const noexcept { return has_flag(BL_FILE_INFO_OTHER_W); } 256 BL_INLINE_NODEBUG bool has_other_x() const noexcept { return has_flag(BL_FILE_INFO_OTHER_X); } 257 258 BL_INLINE_NODEBUG bool has_suid() const noexcept { return has_flag(BL_FILE_INFO_SUID); } 259 BL_INLINE_NODEBUG bool has_sgid() const noexcept { return has_flag(BL_FILE_INFO_SGID); } 260 261 BL_INLINE_NODEBUG bool is_regular() const noexcept { return has_flag(BL_FILE_INFO_REGULAR); } 262 BL_INLINE_NODEBUG bool is_directory() const noexcept { return has_flag(BL_FILE_INFO_DIRECTORY); } 263 BL_INLINE_NODEBUG bool is_symlink() const noexcept { return has_flag(BL_FILE_INFO_SYMLINK); } 264 265 BL_INLINE_NODEBUG bool is_char_device() const noexcept { return has_flag(BL_FILE_INFO_CHAR_DEVICE); } 266 BL_INLINE_NODEBUG bool is_block_device() const noexcept { return has_flag(BL_FILE_INFO_BLOCK_DEVICE); } 267 BL_INLINE_NODEBUG bool is_fifo() const noexcept { return has_flag(BL_FILE_INFO_FIFO); } 268 BL_INLINE_NODEBUG bool is_socket() const noexcept { return has_flag(BL_FILE_INFO_SOCKET); } 269 270 BL_INLINE_NODEBUG bool is_hidden() const noexcept { return has_flag(BL_FILE_INFO_HIDDEN); } 271 BL_INLINE_NODEBUG bool is_executable() const noexcept { return has_flag(BL_FILE_INFO_EXECUTABLE); } 272 BL_INLINE_NODEBUG bool is_archive() const noexcept { return has_flag(BL_FILE_INFO_ARCHIVE); } 273 BL_INLINE_NODEBUG bool is_system() const noexcept { return has_flag(BL_FILE_INFO_SYSTEM); } 274 275 BL_INLINE_NODEBUG bool is_valid() const noexcept { return has_flag(BL_FILE_INFO_VALID); } 276 277 //! \} 278 279 #endif 280 }; 281 282 //! \} 283 284 //! \} 285 286 //! \addtogroup bl_c_api 287 //! \{ 288 289 BL_BEGIN_C_DECLS 290 291 //! \name BLFile C API Functions 292 //! 293 //! File read/write functionality is provided by \ref BLFileCore in C API and wrapped by \ref BLFile in C++ API. 294 //! 295 //! \{ 296 297 BL_API BLResult BL_CDECL bl_file_init(BLFileCore* self) BL_NOEXCEPT_C; 298 BL_API BLResult BL_CDECL bl_file_reset(BLFileCore* self) BL_NOEXCEPT_C; 299 BL_API BLResult BL_CDECL bl_file_open(BLFileCore* self, const char* file_name, BLFileOpenFlags open_flags) BL_NOEXCEPT_C; 300 BL_API BLResult BL_CDECL bl_file_close(BLFileCore* self) BL_NOEXCEPT_C; 301 BL_API BLResult BL_CDECL bl_file_seek(BLFileCore* self, int64_t offset, BLFileSeekType seek_type, int64_t* position_out) BL_NOEXCEPT_C; 302 BL_API BLResult BL_CDECL bl_file_read(BLFileCore* self, void* buffer, size_t n, size_t* bytes_read_out) BL_NOEXCEPT_C; 303 BL_API BLResult BL_CDECL bl_file_write(BLFileCore* self, const void* buffer, size_t n, size_t* bytes_written_out) BL_NOEXCEPT_C; 304 BL_API BLResult BL_CDECL bl_file_truncate(BLFileCore* self, int64_t max_size) BL_NOEXCEPT_C; 305 BL_API BLResult BL_CDECL bl_file_get_info(BLFileCore* self, BLFileInfo* info_out) BL_NOEXCEPT_C; 306 BL_API BLResult BL_CDECL bl_file_get_size(BLFileCore* self, uint64_t* file_size_out) BL_NOEXCEPT_C; 307 308 //! \} 309 310 //! \name BLFileSystem C API Functions 311 //! 312 //! \{ 313 314 BL_API BLResult BL_CDECL bl_file_system_get_info(const char* file_name, BLFileInfo* info_out) BL_NOEXCEPT_C; 315 BL_API BLResult BL_CDECL bl_file_system_read_file(const char* file_name, BLArrayCore* dst, size_t max_size, BLFileReadFlags read_flags) BL_NOEXCEPT_C; 316 BL_API BLResult BL_CDECL bl_file_system_write_file(const char* file_name, const void* data, size_t size, size_t* bytes_written_out) BL_NOEXCEPT_C; 317 318 //! \} 319 320 BL_END_C_DECLS 321 322 //! \} 323 324 //! \addtogroup bl_filesystem 325 //! \{ 326 327 #ifdef __cplusplus 328 //! \name BLFile C++ API 329 //! \{ 330 331 //! A thin abstraction over a native OS file IO [C++ API]. 332 //! 333 //! A thin wrapper around a native OS file support. The file handle is always `intptr_t` and it refers to either 334 //! a file descriptor on POSIX targets and file handle on Windows targets. 335 class BLFile final : public BLFileCore { 336 public: 337 // Prevent copy-constructor and copy-assignment. 338 BL_INLINE_NODEBUG BLFile(const BLFile& other) noexcept = delete; 339 BL_INLINE_NODEBUG BLFile& operator=(const BLFile& other) noexcept = delete; 340 341 //! \name Construction & Destruction 342 //! \{ 343 344 //! Creates an empty file instance, which doesn't represent any open file. 345 //! 346 //! \note The internal file handle of non-opened files is set to -1. 347 BL_INLINE_NODEBUG BLFile() noexcept 348 : BLFileCore { -1 } {} 349 350 //! Move constructor - copies file descriptor from `other` to this instance and resets `other` to a default 351 //! constructed state. 352 BL_INLINE_NODEBUG BLFile(BLFile&& other) noexcept { 353 intptr_t h = other.handle; 354 other.handle = -1; 355 handle = h; 356 } 357 358 //! Creates a file instance from an existing file `handle`, which either represents a file descriptor or Windows 359 //! `HANDLE` (if compiled for Windows platform). 360 BL_INLINE_NODEBUG explicit BLFile(intptr_t handle) noexcept 361 : BLFileCore { handle } {} 362 363 BL_INLINE_NODEBUG BLFile& operator=(BLFile&& other) noexcept { 364 intptr_t h = other.handle; 365 other.handle = -1; 366 367 this->close(); 368 this->handle = h; 369 370 return *this; 371 } 372 373 //! Destroys this file instance - closes the file descriptor or handle when it's referencing an open file. 374 BL_INLINE_NODEBUG ~BLFile() noexcept { bl_file_reset(this); } 375 376 //! \} 377 378 //! \name Common Functionality 379 //! \{ 380 381 BL_INLINE_NODEBUG void swap(BLFile& other) noexcept { BLInternal::swap(this->handle, other.handle); } 382 383 //! \} 384 385 //! \name Interface 386 //! \{ 387 388 //! Tests whether the file is open. 389 BL_INLINE_NODEBUG bool is_open() const noexcept { return handle != -1; } 390 391 //! Attempts to open a file specified by `file_name` with the given `open_flags`. 392 BL_INLINE_NODEBUG BLResult open(const char* file_name, BLFileOpenFlags open_flags) noexcept { 393 return bl_file_open(this, file_name, open_flags); 394 } 395 396 //! Closes the file (if open) and sets the file handle to -1. 397 BL_INLINE_NODEBUG BLResult close() noexcept { 398 return bl_file_close(this); 399 } 400 401 //! Sets the file position of the file to the given `offset` by using the specified `seek_type`. 402 BL_INLINE_NODEBUG BLResult seek(int64_t offset, BLFileSeekType seek_type) noexcept { 403 int64_t position_out; 404 return bl_file_seek(this, offset, seek_type, &position_out); 405 } 406 407 //! Sets the file position of the file to the given `offset` by using the specified `seek_type` and writes the new 408 //! position into `position_out` output parameter. 409 BL_INLINE_NODEBUG BLResult seek(int64_t offset, BLFileSeekType seek_type, int64_t* position_out) noexcept { 410 return bl_file_seek(this, offset, seek_type, position_out); 411 } 412 413 //! Reads `n` bytes from the file into the given `buffer` and stores the number of bytes actually read into 414 //! the `bytes_read_out` output parameter. 415 BL_INLINE_NODEBUG BLResult read(void* buffer, size_t n, size_t* bytes_read_out) noexcept { 416 return bl_file_read(this, buffer, n, bytes_read_out); 417 } 418 419 //! Writes `n` bytes to the file from the given `buffer` and stores the number of bytes actually written into 420 //! the `bytes_read_out` output parameter. 421 BL_INLINE_NODEBUG BLResult write(const void* buffer, size_t n, size_t* bytes_written_out) noexcept { 422 return bl_file_write(this, buffer, n, bytes_written_out); 423 } 424 425 //! Truncates the file to the given maximum size `max_size`. 426 BL_INLINE_NODEBUG BLResult truncate(int64_t max_size) noexcept { 427 return bl_file_truncate(this, max_size); 428 } 429 430 //! Queries an information of the file and stores it to `info_out`. 431 BL_INLINE_NODEBUG BLResult get_info(BLFileInfo* info_out) noexcept { 432 return bl_file_get_info(this, info_out); 433 } 434 435 //! Queries a size of the file and stores it to `size_out`. 436 BL_INLINE_NODEBUG BLResult get_size(uint64_t* size_out) noexcept { 437 return bl_file_get_size(this, size_out); 438 } 439 440 //! \} 441 }; 442 443 //! File-system utilities. 444 namespace BLFileSystem { 445 446 static BL_INLINE_NODEBUG BLResult file_info(const char* file_name, BLFileInfo* info_out) noexcept { 447 return bl_file_system_get_info(file_name, info_out); 448 } 449 450 //! Reads a file into the `dst` buffer. 451 //! 452 //! Optionally you can set `max_size` to non-zero value that would restrict the maximum bytes to read to such value. 453 //! In addition, `read_flags` can be used to enable file mapping. See \ref BLFileReadFlags for more details. 454 static BL_INLINE_NODEBUG BLResult read_file(const char* file_name, BLArray<uint8_t>& dst, size_t max_size = 0, BLFileReadFlags read_flags = BL_FILE_READ_NO_FLAGS) noexcept { 455 return bl_file_system_read_file(file_name, &dst, max_size, read_flags); 456 } 457 458 static BL_INLINE_NODEBUG BLResult write_file(const char* file_name, const void* data, size_t size) noexcept { 459 size_t bytes_written_out; 460 return bl_file_system_write_file(file_name, data, size, &bytes_written_out); 461 } 462 463 static BL_INLINE_NODEBUG BLResult write_file(const char* file_name, const void* data, size_t size, size_t* bytes_written_out) noexcept { 464 return bl_file_system_write_file(file_name, data, size, bytes_written_out); 465 } 466 467 static BL_INLINE_NODEBUG BLResult write_file(const char* file_name, const BLArrayView<uint8_t>& view) noexcept { 468 return write_file(file_name, view.data, view.size); 469 } 470 471 static BL_INLINE_NODEBUG BLResult write_file(const char* file_name, const BLArrayView<uint8_t>& view, size_t* bytes_written_out) noexcept { 472 return write_file(file_name, view.data, view.size, bytes_written_out); 473 } 474 475 static BL_INLINE_NODEBUG BLResult write_file(const char* file_name, const BLArray<uint8_t>& array) noexcept { 476 return write_file(file_name, array.view()); 477 } 478 479 static BL_INLINE_NODEBUG BLResult write_file(const char* file_name, const BLArray<uint8_t>& array, size_t* bytes_written_out) noexcept { 480 return write_file(file_name, array.view(), bytes_written_out); 481 } 482 483 } // {BLFileSystem} 484 485 //! \} 486 #endif 487 488 //! \} 489 490 #endif // BLEND2D_FILESYSTEM_H_INCLUDED