Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | /* |
| 2 | * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>. |
||
| 3 | * It is copyright by its individual contributors, as recorded in the |
||
| 4 | * project's Git history. See COPYING.txt at the top level for license |
||
| 5 | * terms and a link to the Git history. |
||
| 6 | */ |
||
| 7 | |||
| 8 | /* |
||
| 9 | * |
||
| 10 | * Some simple physfs extensions |
||
| 11 | * |
||
| 12 | */ |
||
| 13 | |||
| 14 | #pragma once |
||
| 15 | |||
| 16 | #include <cstddef> |
||
| 17 | #include <memory> |
||
| 18 | #include <string.h> |
||
| 19 | #include <stdarg.h> |
||
| 20 | #include <type_traits> |
||
| 21 | |||
| 22 | // When PhysicsFS can *easily* be built as a framework on Mac OS X, |
||
| 23 | // the framework form will be supported again -kreatordxx |
||
| 24 | #if 1 //!(defined(__APPLE__) && defined(__MACH__)) |
||
| 25 | #include <physfs.h> |
||
| 26 | #else |
||
| 27 | #include <physfs/physfs.h> |
||
| 28 | #endif |
||
| 29 | |||
| 30 | #include "fmtcheck.h" |
||
| 31 | #include "dxxsconf.h" |
||
| 32 | #include "dsx-ns.h" |
||
| 33 | #include "dxxerror.h" |
||
| 34 | #include "vecmat.h" |
||
| 35 | #include "byteutil.h" |
||
| 36 | |||
| 37 | #ifdef __cplusplus |
||
| 38 | #include <stdexcept> |
||
| 39 | #include "u_mem.h" |
||
| 40 | #include "pack.h" |
||
| 41 | #include "ntstring.h" |
||
| 42 | #include "fwd-partial_range.h" |
||
| 43 | #include <array> |
||
| 44 | #include <memory> |
||
| 45 | |||
| 46 | #ifdef DXX_CONSTANT_TRUE |
||
| 47 | #define _DXX_PHYSFS_CHECK_SIZE_CONSTANT(S,v) DXX_CONSTANT_TRUE((S) > (v)) |
||
| 48 | #define _DXX_PHYSFS_CHECK_SIZE(S,C,v) _DXX_PHYSFS_CHECK_SIZE_CONSTANT(static_cast<size_t>(S) * static_cast<size_t>(C), v) |
||
| 49 | #define DXX_PHYSFS_CHECK_READ_SIZE_OBJECT_SIZE(S,C,v) \ |
||
| 50 | (void)(__builtin_object_size(v, 1) != static_cast<size_t>(-1) && _DXX_PHYSFS_CHECK_SIZE(S,C,__builtin_object_size(v, 1)) && (DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_overwrite, "read size exceeds element size"), 0)) |
||
| 51 | #define DXX_PHYSFS_CHECK_READ_SIZE_ARRAY_SIZE(S,C) \ |
||
| 52 | (void)(_DXX_PHYSFS_CHECK_SIZE(S,C,sizeof(v)) && (DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_overwrite, "read size exceeds array size"), 0)) |
||
| 53 | #define DXX_PHYSFS_CHECK_WRITE_SIZE_OBJECT_SIZE(S,C,v) \ |
||
| 54 | (void)(__builtin_object_size(v, 1) != static_cast<size_t>(-1) && _DXX_PHYSFS_CHECK_SIZE(S,C,__builtin_object_size(v, 1)) && (DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_overwrite, "write size exceeds element size"), 0)) |
||
| 55 | #define DXX_PHYSFS_CHECK_WRITE_ELEMENT_SIZE_CONSTANT(S,C) \ |
||
| 56 | ((void)(dxx_builtin_constant_p(S) || dxx_builtin_constant_p(C) || \ |
||
| 57 | (DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_nonconstant_size, "array element size is not constant"), 0))) |
||
| 58 | #define DXX_PHYSFS_CHECK_WRITE_SIZE_ARRAY_SIZE(S,C) \ |
||
| 59 | ((void)(_DXX_PHYSFS_CHECK_SIZE(S,C,sizeof(v)) && \ |
||
| 60 | (DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_overread, "write size exceeds array size"), 0))) |
||
| 61 | #else |
||
| 62 | #define DXX_PHYSFS_CHECK_READ_SIZE_OBJECT_SIZE(S,C,v) ((void)0) |
||
| 63 | #define DXX_PHYSFS_CHECK_READ_SIZE_ARRAY_SIZE(S,C) ((void)0) |
||
| 64 | #define DXX_PHYSFS_CHECK_WRITE_SIZE_OBJECT_SIZE(S,C,v) ((void)0) |
||
| 65 | #define DXX_PHYSFS_CHECK_WRITE_ELEMENT_SIZE_CONSTANT(S,C) ((void)0) |
||
| 66 | #define DXX_PHYSFS_CHECK_WRITE_SIZE_ARRAY_SIZE(S,C) ((void)0) |
||
| 67 | #endif |
||
| 68 | |||
| 69 | #define DXX_PHYSFS_CHECK_WRITE_CONSTANTS(S,C) \ |
||
| 70 | ((void)(DXX_PHYSFS_CHECK_WRITE_ELEMENT_SIZE_CONSTANT(S,C), \ |
||
| 71 | DXX_PHYSFS_CHECK_WRITE_SIZE_ARRAY_SIZE(S,C), 0)) \ |
||
| 72 | |||
| 73 | namespace dcx { |
||
| 74 | |||
| 75 | template <typename V> |
||
| 76 | __attribute_always_inline() |
||
| 77 | static inline PHYSFS_sint64 PHYSFSX_check_read(PHYSFS_File *file, V *v, const PHYSFS_uint32 S, const PHYSFS_uint32 C) |
||
| 78 | { |
||
| 79 | if constexpr (std::is_integral<V>::value) |
||
| 80 | static_assert(std::is_pod<V>::value, "non-POD integral value read"); |
||
| 81 | else |
||
| 82 | static_assert(std::is_pod<V>::value, "non-POD non-integral value read"); |
||
| 83 | DXX_PHYSFS_CHECK_READ_SIZE_OBJECT_SIZE(S, C, v); |
||
| 84 | return (S == 0 ? 0 : PHYSFS_readBytes(file, v, S * C) / S); // Pierre-Marie Baty -- work around PHYSFS_read() deprecation |
||
| 85 | } |
||
| 86 | |||
| 87 | template <typename V, std::size_t N> |
||
| 88 | __attribute_always_inline() |
||
| 89 | static inline PHYSFS_sint64 PHYSFSX_check_read(PHYSFS_File *file, std::array<V, N> &v, PHYSFS_uint32 S, PHYSFS_uint32 C) |
||
| 90 | { |
||
| 91 | static_assert(std::is_pod<V>::value, "C++ array of non-POD elements read"); |
||
| 92 | DXX_PHYSFS_CHECK_READ_SIZE_ARRAY_SIZE(S, C); |
||
| 93 | return PHYSFSX_check_read(file, &v[0], S, C); |
||
| 94 | } |
||
| 95 | |||
| 96 | template <typename V, typename D> |
||
| 97 | __attribute_always_inline() |
||
| 98 | static inline PHYSFS_sint64 PHYSFSX_check_read(PHYSFS_File *file, const std::unique_ptr<V, D> &v, PHYSFS_uint32 S, PHYSFS_uint32 C) |
||
| 99 | { |
||
| 100 | return PHYSFSX_check_read(file, v.get(), S, C); |
||
| 101 | } |
||
| 102 | |||
| 103 | template <typename V> |
||
| 104 | __attribute_always_inline() |
||
| 105 | static inline PHYSFS_sint64 PHYSFSX_check_write(PHYSFS_File *file, const V *v, const PHYSFS_uint32 S, const PHYSFS_uint32 C) |
||
| 106 | { |
||
| 107 | if constexpr (std::is_integral<V>::value) |
||
| 108 | { |
||
| 109 | static_assert(std::is_pod<V>::value, "non-POD integral value written"); |
||
| 110 | DXX_PHYSFS_CHECK_WRITE_ELEMENT_SIZE_CONSTANT(S,C); |
||
| 111 | } |
||
| 112 | else |
||
| 113 | static_assert(std::is_pod<V>::value, "non-POD non-integral value written"); |
||
| 114 | DXX_PHYSFS_CHECK_WRITE_SIZE_OBJECT_SIZE(S, C, v); |
||
| 115 | return (S == 0 ? 0 : PHYSFS_writeBytes(file, v, S * C) / S); // Pierre-Marie Baty -- work around PHYSFS_write() deprecation |
||
| 116 | } |
||
| 117 | |||
| 118 | template <typename V, std::size_t N> |
||
| 119 | __attribute_always_inline() |
||
| 120 | static inline PHYSFS_sint64 PHYSFSX_check_write(PHYSFS_File *file, const std::array<V, N> &v, PHYSFS_uint32 S, PHYSFS_uint32 C) |
||
| 121 | { |
||
| 122 | static_assert(std::is_pod<V>::value, "C++ array of non-POD elements written"); |
||
| 123 | DXX_PHYSFS_CHECK_WRITE_CONSTANTS(S,C); |
||
| 124 | return PHYSFSX_check_write(file, &v[0], S, C); |
||
| 125 | } |
||
| 126 | |||
| 127 | template <typename T, typename D> |
||
| 128 | __attribute_always_inline() |
||
| 129 | static inline PHYSFS_sint64 PHYSFSX_check_write(PHYSFS_File *file, const std::unique_ptr<T, D> &p, PHYSFS_uint32 S, PHYSFS_uint32 C) |
||
| 130 | { |
||
| 131 | return PHYSFSX_check_write(file, p.get(), S, C); |
||
| 132 | } |
||
| 133 | |||
| 134 | template <typename V> |
||
| 135 | PHYSFS_sint64 PHYSFSX_check_read(PHYSFS_File *file, exact_type<V> v, PHYSFS_uint32 S, PHYSFS_uint32 C) = delete; |
||
| 136 | template <typename V> |
||
| 137 | PHYSFS_sint64 PHYSFSX_check_write(PHYSFS_File *file, exact_type<V> v, PHYSFS_uint32 S, PHYSFS_uint32 C) = delete; |
||
| 138 | |||
| 139 | template <typename V> |
||
| 140 | PHYSFS_sint64 PHYSFSX_check_read(PHYSFS_File *file, V **v, PHYSFS_uint32 S, PHYSFS_uint32 C) = delete; |
||
| 141 | template <typename V> |
||
| 142 | PHYSFS_sint64 PHYSFSX_check_write(PHYSFS_File *file, V **v, PHYSFS_uint32 S, PHYSFS_uint32 C) = delete; |
||
| 143 | #define PHYSFS_read(F,V,S,C) PHYSFSX_check_read(F,V,S,C) |
||
| 144 | #define PHYSFS_write(F,V,S,C) PHYSFSX_check_write(F,V,S,C) |
||
| 145 | |||
| 146 | static inline PHYSFS_sint16 PHYSFSX_readSXE16(PHYSFS_File *file, int swap) |
||
| 147 | { |
||
| 148 | PHYSFS_sint16 val; |
||
| 149 | |||
| 150 | PHYSFS_read(file, &val, sizeof(val), 1); |
||
| 151 | |||
| 152 | return swap ? SWAPSHORT(val) : val; |
||
| 153 | } |
||
| 154 | |||
| 155 | static inline PHYSFS_sint32 PHYSFSX_readSXE32(PHYSFS_File *file, int swap) |
||
| 156 | { |
||
| 157 | PHYSFS_sint32 val; |
||
| 158 | |||
| 159 | PHYSFS_read(file, &val, sizeof(val), 1); |
||
| 160 | |||
| 161 | return swap ? SWAPINT(val) : val; |
||
| 162 | } |
||
| 163 | |||
| 164 | static inline int PHYSFSX_writeU8(PHYSFS_File *file, PHYSFS_uint8 val) |
||
| 165 | { |
||
| 166 | return PHYSFS_write(file, &val, 1, 1); |
||
| 167 | } |
||
| 168 | |||
| 169 | static inline int PHYSFSX_writeString(PHYSFS_File *file, const char *s) |
||
| 170 | { |
||
| 171 | return PHYSFS_write(file, s, 1, strlen(s) + 1); |
||
| 172 | } |
||
| 173 | |||
| 174 | static inline int PHYSFSX_puts(PHYSFS_File *file, const char *s, size_t len) __attribute_nonnull(); |
||
| 175 | static inline int PHYSFSX_puts(PHYSFS_File *file, const char *s, size_t len) |
||
| 176 | { |
||
| 177 | return PHYSFS_write(file, s, 1, len); |
||
| 178 | } |
||
| 179 | |||
| 180 | template <size_t len> |
||
| 181 | static inline int PHYSFSX_puts_literal(PHYSFS_File *file, const char (&s)[len]) __attribute_nonnull(); |
||
| 182 | template <size_t len> |
||
| 183 | static inline int PHYSFSX_puts_literal(PHYSFS_File *file, const char (&s)[len]) |
||
| 184 | { |
||
| 185 | return PHYSFSX_puts(file, s, len - 1); |
||
| 186 | } |
||
| 187 | #define PHYSFSX_puts(A1,S,...) (PHYSFSX_puts(A1,S, _dxx_call_puts_parameter2(1, ## __VA_ARGS__, strlen(S)))) |
||
| 188 | |||
| 189 | static inline int PHYSFSX_fgetc(PHYSFS_File *const fp) |
||
| 190 | { |
||
| 191 | unsigned char c; |
||
| 192 | |||
| 193 | if (PHYSFS_read(fp, &c, 1, 1) != 1) |
||
| 194 | return EOF; |
||
| 195 | |||
| 196 | return c; |
||
| 197 | } |
||
| 198 | |||
| 199 | static inline int PHYSFSX_fseek(PHYSFS_File *fp, long int offset, int where) |
||
| 200 | { |
||
| 201 | int c, goal_position; |
||
| 202 | |||
| 203 | switch(where) |
||
| 204 | { |
||
| 205 | case SEEK_SET: |
||
| 206 | goal_position = offset; |
||
| 207 | break; |
||
| 208 | case SEEK_CUR: |
||
| 209 | goal_position = PHYSFS_tell(fp) + offset; |
||
| 210 | break; |
||
| 211 | case SEEK_END: |
||
| 212 | goal_position = PHYSFS_fileLength(fp) + offset; |
||
| 213 | break; |
||
| 214 | default: |
||
| 215 | return 1; |
||
| 216 | } |
||
| 217 | c = PHYSFS_seek(fp, goal_position); |
||
| 218 | return !c; |
||
| 219 | } |
||
| 220 | |||
| 221 | template <std::size_t N> |
||
| 222 | struct PHYSFSX_gets_line_t |
||
| 223 | { |
||
| 224 | PHYSFSX_gets_line_t() = default; |
||
| 225 | PHYSFSX_gets_line_t(const PHYSFSX_gets_line_t &) = delete; |
||
| 226 | PHYSFSX_gets_line_t &operator=(const PHYSFSX_gets_line_t &) = delete; |
||
| 227 | PHYSFSX_gets_line_t(PHYSFSX_gets_line_t &&) = default; |
||
| 228 | PHYSFSX_gets_line_t &operator=(PHYSFSX_gets_line_t &&) = default; |
||
| 229 | using line_t = std::array<char, N>; |
||
| 230 | #if DXX_HAVE_POISON |
||
| 231 | /* Force onto heap to improve checker accuracy */ |
||
| 232 | std::unique_ptr<line_t> m_line; |
||
| 233 | const line_t &line() const { return *m_line.get(); } |
||
| 234 | line_t &line() { return *m_line.get(); } |
||
| 235 | line_t &next() |
||
| 236 | { |
||
| 237 | m_line = std::make_unique<line_t>(); |
||
| 238 | return *m_line.get(); |
||
| 239 | } |
||
| 240 | #else |
||
| 241 | line_t m_line; |
||
| 242 | const line_t &line() const { return m_line; } |
||
| 243 | line_t &line() { return m_line; } |
||
| 244 | line_t &next() { return m_line; } |
||
| 245 | #endif |
||
| 246 | operator line_t &() { return line(); } |
||
| 247 | operator const line_t &() const { return line(); } |
||
| 248 | operator char *() { return line().data(); } |
||
| 249 | operator const char *() const { return line().data(); } |
||
| 250 | typename line_t::reference operator[](typename line_t::size_type i) { return line()[i]; } |
||
| 251 | typename line_t::reference operator[](int i) { return operator[](static_cast<typename line_t::size_type>(i)); } |
||
| 252 | typename line_t::const_reference operator[](typename line_t::size_type i) const { return line()[i]; } |
||
| 253 | typename line_t::const_reference operator[](int i) const { return operator[](static_cast<typename line_t::size_type>(i)); } |
||
| 254 | constexpr std::size_t size() const { return N; } |
||
| 255 | typename line_t::const_iterator begin() const { return line().begin(); } |
||
| 256 | typename line_t::const_iterator end() const { return line().end(); } |
||
| 257 | }; |
||
| 258 | |||
| 259 | template <> |
||
| 260 | struct PHYSFSX_gets_line_t<0> |
||
| 261 | { |
||
| 262 | #define DXX_ALLOCATE_PHYSFS_LINE(n) std::make_unique<char[]>(n) |
||
| 263 | std::unique_ptr<char[]> m_line; |
||
| 264 | std::size_t m_length; |
||
| 265 | PHYSFSX_gets_line_t(std::size_t n) : |
||
| 266 | #if !DXX_HAVE_POISON |
||
| 267 | m_line(DXX_ALLOCATE_PHYSFS_LINE(n)), |
||
| 268 | #endif |
||
| 269 | m_length(n) |
||
| 270 | { |
||
| 271 | } |
||
| 272 | char *line() { return m_line.get(); } |
||
| 273 | const char *line() const { return m_line.get(); } |
||
| 274 | char *next() |
||
| 275 | { |
||
| 276 | #if DXX_HAVE_POISON |
||
| 277 | /* Reallocate to tell checker to undefine the buffer */ |
||
| 278 | m_line = DXX_ALLOCATE_PHYSFS_LINE(m_length); |
||
| 279 | #endif |
||
| 280 | return m_line.get(); |
||
| 281 | } |
||
| 282 | std::size_t size() const { return m_length; } |
||
| 283 | operator const char *() const { return m_line.get(); } |
||
| 284 | const char *begin() const { return *this; } |
||
| 285 | const char *end() const { return begin() + m_length; } |
||
| 286 | operator const void *() const = delete; |
||
| 287 | #undef DXX_ALLOCATE_PHYSFS_LINE |
||
| 288 | }; |
||
| 289 | |||
| 290 | class PHYSFSX_fgets_t |
||
| 291 | { |
||
| 292 | static char *get(char *buf, std::size_t n, PHYSFS_File *const fp); |
||
| 293 | static char *get(char *buf, std::size_t offset, std::size_t n, PHYSFS_File *const fp) |
||
| 294 | { |
||
| 295 | if (offset > n) |
||
| 296 | throw std::invalid_argument("offset too large"); |
||
| 297 | return get(&buf[offset], n - offset, fp); |
||
| 298 | } |
||
| 299 | public: |
||
| 300 | template <std::size_t n> |
||
| 301 | __attribute_nonnull() |
||
| 302 | char *operator()(PHYSFSX_gets_line_t<n> &buf, PHYSFS_File *const fp, std::size_t offset = 0) const |
||
| 303 | { |
||
| 304 | return get(&buf.next()[0], offset, buf.size(), fp); |
||
| 305 | } |
||
| 306 | template <std::size_t n> |
||
| 307 | __attribute_nonnull() |
||
| 308 | char *operator()(ntstring<n> &buf, PHYSFS_File *const fp, std::size_t offset = 0) const |
||
| 309 | { |
||
| 310 | auto r = get(&buf.data()[0], offset, buf.size(), fp); |
||
| 311 | buf.back() = 0; |
||
| 312 | return r; |
||
| 313 | } |
||
| 314 | }; |
||
| 315 | |||
| 316 | constexpr PHYSFSX_fgets_t PHYSFSX_fgets{}; |
||
| 317 | |||
| 318 | static inline int PHYSFSX_printf(PHYSFS_File *file, const char *format, ...) __attribute_format_printf(2, 3); |
||
| 319 | static inline int PHYSFSX_printf(PHYSFS_File *file, const char *format, ...) |
||
| 320 | #define PHYSFSX_printf(A1,F,...) dxx_call_printf_checked(PHYSFSX_printf,PHYSFSX_puts_literal,(A1),(F),##__VA_ARGS__) |
||
| 321 | { |
||
| 322 | char buffer[1024]; |
||
| 323 | va_list args; |
||
| 324 | |||
| 325 | va_start(args, format); |
||
| 326 | size_t len = vsnprintf(buffer, sizeof(buffer), format, args); |
||
| 327 | va_end(args); |
||
| 328 | |||
| 329 | return PHYSFSX_puts(file, buffer, len); |
||
| 330 | } |
||
| 331 | |||
| 332 | #define PHYSFSX_writeFix PHYSFS_writeSLE32 |
||
| 333 | #define PHYSFSX_writeFixAng PHYSFS_writeSLE16 |
||
| 334 | |||
| 335 | static inline int PHYSFSX_writeVector(PHYSFS_File *file, const vms_vector &v) |
||
| 336 | { |
||
| 337 | if (PHYSFSX_writeFix(file, v.x) < 1 || |
||
| 338 | PHYSFSX_writeFix(file, v.y) < 1 || |
||
| 339 | PHYSFSX_writeFix(file, v.z) < 1) |
||
| 340 | return 0; |
||
| 341 | |||
| 342 | return 1; |
||
| 343 | } |
||
| 344 | |||
| 345 | __attribute_cold |
||
| 346 | __attribute_noreturn |
||
| 347 | void PHYSFSX_read_helper_report_error(const char *const filename, const unsigned line, const char *const func, PHYSFS_File *const file); |
||
| 348 | |||
| 349 | template <typename T, int (*F)(PHYSFS_File *, T *)> |
||
| 350 | static T PHYSFSX_read_helper(const char *const filename, const unsigned line, const char *const func, PHYSFS_File *const file) |
||
| 351 | { |
||
| 352 | T i; |
||
| 353 | if (!F(file, &i)) |
||
| 354 | PHYSFSX_read_helper_report_error(filename, line, func, file); |
||
| 355 | return i; |
||
| 356 | } |
||
| 357 | |||
| 358 | template <typename T1, int (*F)(PHYSFS_File *, T1 *), typename T2, T1 T2::*m1, T1 T2::*m2, T1 T2::*m3> |
||
| 359 | static void PHYSFSX_read_sequence_helper(const char *const filename, const unsigned line, const char *const func, PHYSFS_File *const file, T2 *const i) |
||
| 360 | { |
||
| 361 | if (unlikely(!F(file, &(i->*m1)) || |
||
| 362 | !F(file, &(i->*m2)) || |
||
| 363 | !F(file, &(i->*m3)))) |
||
| 364 | PHYSFSX_read_helper_report_error(filename, line, func, file); |
||
| 365 | } |
||
| 366 | |||
| 367 | static inline int PHYSFSX_readS8(PHYSFS_File *const file, int8_t *const b) |
||
| 368 | { |
||
| 369 | return (PHYSFS_read(file, b, sizeof(*b), 1) == 1); |
||
| 370 | } |
||
| 371 | |||
| 372 | #define PHYSFSX_readByte(F) (PHYSFSX_read_helper<int8_t, PHYSFSX_readS8>(__FILE__, __LINE__, __func__, (F))) |
||
| 373 | #define PHYSFSX_readShort(F) (PHYSFSX_read_helper<int16_t, PHYSFS_readSLE16>(__FILE__, __LINE__, __func__, (F))) |
||
| 374 | #define PHYSFSX_readInt(F) (PHYSFSX_read_helper<int32_t, PHYSFS_readSLE32>(__FILE__, __LINE__, __func__, (F))) |
||
| 375 | #define PHYSFSX_readFix(F) (PHYSFSX_read_helper<fix, PHYSFS_readSLE32>(__FILE__, __LINE__, __func__, (F))) |
||
| 376 | #define PHYSFSX_readFixAng(F) (PHYSFSX_read_helper<fixang, PHYSFS_readSLE16>(__FILE__, __LINE__, __func__, (F))) |
||
| 377 | #define PHYSFSX_readVector(F,V) (PHYSFSX_read_sequence_helper<fix, PHYSFS_readSLE32, vms_vector, &vms_vector::x, &vms_vector::y, &vms_vector::z>(__FILE__, __LINE__, __func__, (F), &(V))) |
||
| 378 | #define PHYSFSX_readAngleVec(V,F) (PHYSFSX_read_sequence_helper<fixang, PHYSFS_readSLE16, vms_angvec, &vms_angvec::p, &vms_angvec::b, &vms_angvec::h>(__FILE__, __LINE__, __func__, (F), (V))) |
||
| 379 | |||
| 380 | static inline void PHYSFSX_readMatrix(const char *const filename, const unsigned line, const char *const func, vms_matrix *const m, PHYSFS_File *const file) |
||
| 381 | { |
||
| 382 | auto &PHYSFSX_readVector = PHYSFSX_read_sequence_helper<fix, PHYSFS_readSLE32, vms_vector, &vms_vector::x, &vms_vector::y, &vms_vector::z>; |
||
| 383 | (PHYSFSX_readVector)(filename, line, func, file, &m->rvec); |
||
| 384 | (PHYSFSX_readVector)(filename, line, func, file, &m->uvec); |
||
| 385 | (PHYSFSX_readVector)(filename, line, func, file, &m->fvec); |
||
| 386 | } |
||
| 387 | |||
| 388 | #define PHYSFSX_readMatrix(M,F) ((PHYSFSX_readMatrix)(__FILE__, __LINE__, __func__, (M), (F))) |
||
| 389 | |||
| 390 | #define PHYSFSX_contfile_init PHYSFSX_addRelToSearchPath |
||
| 391 | #define PHYSFSX_contfile_close PHYSFSX_removeRelFromSearchPath |
||
| 392 | |||
| 393 | class PHYSFS_File_deleter |
||
| 394 | { |
||
| 395 | public: |
||
| 396 | int operator()(PHYSFS_File *fp) const |
||
| 397 | { |
||
| 398 | return PHYSFS_close(fp); |
||
| 399 | } |
||
| 400 | }; |
||
| 401 | |||
| 402 | class RAIIPHYSFS_File : public std::unique_ptr<PHYSFS_File, PHYSFS_File_deleter> |
||
| 403 | { |
||
| 404 | typedef std::unique_ptr<PHYSFS_File, PHYSFS_File_deleter> base_t; |
||
| 405 | public: |
||
| 406 | DXX_INHERIT_CONSTRUCTORS(RAIIPHYSFS_File, base_t); |
||
| 407 | using base_t::operator bool; |
||
| 408 | operator PHYSFS_File *() const && = delete; |
||
| 409 | operator PHYSFS_File *() const & |
||
| 410 | { |
||
| 411 | return get(); |
||
| 412 | } |
||
| 413 | int close() |
||
| 414 | { |
||
| 415 | /* Like reset(), but returns result */ |
||
| 416 | int r = get_deleter()(get()); |
||
| 417 | if (r) |
||
| 418 | release(); |
||
| 419 | return r; |
||
| 420 | } |
||
| 421 | template <typename T> |
||
| 422 | bool operator==(T) const = delete; |
||
| 423 | template <typename T> |
||
| 424 | bool operator!=(T) const = delete; |
||
| 425 | }; |
||
| 426 | |||
| 427 | typedef char file_extension_t[5]; |
||
| 428 | __attribute_nonnull() |
||
| 429 | __attribute_warn_unused_result |
||
| 430 | int PHYSFSX_checkMatchingExtension(const char *filename, const partial_range_t<const file_extension_t *>); |
||
| 431 | |||
| 432 | template <std::size_t count> |
||
| 433 | __attribute_nonnull() |
||
| 434 | __attribute_warn_unused_result |
||
| 435 | static inline int PHYSFSX_checkMatchingExtension(const std::array<file_extension_t, count> &exts, const char *filename) |
||
| 436 | { |
||
| 437 | return PHYSFSX_checkMatchingExtension(filename, exts); |
||
| 438 | } |
||
| 439 | |||
| 440 | extern int PHYSFSX_addRelToSearchPath(const char *relname, int add_to_end); |
||
| 441 | extern int PHYSFSX_removeRelFromSearchPath(const char *relname); |
||
| 442 | extern int PHYSFSX_fsize(const char *hogname); |
||
| 443 | extern void PHYSFSX_listSearchPathContent(); |
||
| 444 | int PHYSFSX_getRealPath(const char *stdPath, char *realPath, std::size_t); |
||
| 445 | |||
| 446 | template <std::size_t N> |
||
| 447 | static inline int PHYSFSX_getRealPath(const char *stdPath, std::array<char, N> &realPath) |
||
| 448 | { |
||
| 449 | return PHYSFSX_getRealPath(stdPath, realPath.data(), N); |
||
| 450 | } |
||
| 451 | |||
| 452 | extern int PHYSFSX_isNewPath(const char *path); |
||
| 453 | extern int PHYSFSX_rename(const char *oldpath, const char *newpath); |
||
| 454 | |||
| 455 | #define PHYSFSX_exists(F,I) ((I) ? PHYSFSX_exists_ignorecase(F) : PHYSFS_exists(F)) |
||
| 456 | int PHYSFSX_exists_ignorecase(const char *filename); |
||
| 457 | RAIIPHYSFS_File PHYSFSX_openReadBuffered(const char *filename); |
||
| 458 | RAIIPHYSFS_File PHYSFSX_openWriteBuffered(const char *filename); |
||
| 459 | extern void PHYSFSX_addArchiveContent(); |
||
| 460 | extern void PHYSFSX_removeArchiveContent(); |
||
| 461 | } |
||
| 462 | |||
| 463 | #ifdef dsx |
||
| 464 | namespace dsx { |
||
| 465 | |||
| 466 | bool PHYSFSX_init(int argc, char *argv[]); |
||
| 467 | int PHYSFSX_checkSupportedArchiveTypes(); |
||
| 468 | |||
| 469 | } |
||
| 470 | #endif |
||
| 471 | |||
| 472 | #endif |