1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#ifndef LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H
22#define LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H
23
24#include <cstdint>
25#include <cstdio>
26#include <string>
27
28#include "libraries/physfs/physfs.h"
29
30namespace love
31{
32namespace filesystem
33{
34namespace physfs
35{
36
37template <typename Derived>
38struct PhysfsIo : PHYSFS_Io
39{
40protected:
41
42 PhysfsIo()
43 : PHYSFS_Io()
44 {
45 // Direct initialization of PHYSFS_Io members in the initializer list
46 // doesn't work in VS2013.
47 this->version = Derived::version;
48 this->opaque = this;
49 this->read = staticRead; // May be null.
50 this->write = staticWrite; // May be null.
51 this->seek = staticSeek;
52 this->tell = staticTell;
53 this->length = staticLength;
54 this->duplicate = staticDuplicate;
55 this->flush = staticFlush; // May be null.
56 this->destroy = staticDestroy;
57 }
58
59 virtual ~PhysfsIo() {}
60
61private:
62
63 // Returns: number of bytes read, 0 on EOF, -1 on failure
64 static PHYSFS_sint64 staticRead(struct PHYSFS_Io* io, void* buf, PHYSFS_uint64 len)
65 {
66 return derived(io)->read(buf, len);
67 }
68
69 // Returns: number of bytes written, -1 on failure
70 static PHYSFS_sint64 staticWrite(struct PHYSFS_Io* io, const void* buf, PHYSFS_uint64 len)
71 {
72 return derived(io)->write(buf, len);
73 }
74
75 // Returns: non-zero on success, zero on error
76 static int staticSeek(struct PHYSFS_Io* io, PHYSFS_uint64 offset)
77 {
78 return derived(io)->seek(offset);
79 }
80
81 // Returns: current offset from start, -1 on error
82 static PHYSFS_sint64 staticTell(struct PHYSFS_Io* io)
83 {
84 return derived(io)->tell();
85 }
86
87 // Returns: total size in bytes, -1 on error
88 static PHYSFS_sint64 staticLength(struct PHYSFS_Io* io)
89 {
90 return derived(io)->length();
91 }
92
93 static struct PHYSFS_Io* staticDuplicate(struct PHYSFS_Io* io)
94 {
95 // Just use copy constructor
96 return new Derived(*derived(io));
97 }
98
99 // Returns: non-zero on success, zero on error
100 static int staticFlush(struct PHYSFS_Io* io)
101 {
102 return derived(io)->flush();
103 }
104
105 static void staticDestroy(struct PHYSFS_Io* io)
106 {
107 // Just use destructor
108 delete derived(io);
109 }
110
111 static Derived* derived(PHYSFS_Io* io)
112 {
113 return static_cast<Derived*>(reinterpret_cast<PhysfsIo*>(io->opaque));
114 }
115};
116
117struct StripSuffixIo : public PhysfsIo<StripSuffixIo>
118{
119 static const uint32_t version = 0;
120
121 std::string filename;
122 FILE* file = nullptr;
123
124 // The constructor is private in favor of this function to prevent stack allocation
125 // because Physfs will take ownership of this object and call destroy on it later.
126 static StripSuffixIo* create(std::string f) { return new StripSuffixIo(f); }
127
128 virtual ~StripSuffixIo()
129 {
130 if (file)
131 {
132 std::fclose(file);
133 }
134 }
135
136 StripSuffixIo(const StripSuffixIo& other)
137 : StripSuffixIo(other.filename)
138 {
139 }
140
141 bool determineStrippedLength();
142
143 int64_t read(void* buf, uint64_t len);
144 int64_t write(const void* buf, uint64_t len);
145 int64_t seek(uint64_t offset);
146 int64_t tell();
147 int64_t length();
148 int64_t flush();
149
150private:
151
152 StripSuffixIo(std::string f)
153 : filename(std::move(f))
154 , file(std::fopen(filename.c_str(), "rb"))
155 {
156 }
157
158 int64_t fullLength();
159
160 int64_t strippedLength_ = -1;
161};
162
163} // physfs
164} // filesystem
165} // love
166
167#endif
168