git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / file / nbio / nbio_orbis.c
1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (nbio_orbis.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #include <file/nbio.h>
24
25 #if defined(ORBIS)
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <orbisFile.h>
29 #include <unistd.h>
30 #include <sys/fcntl.h>
31
32 struct nbio_orbis_t
33 {
34    void* data;
35    size_t progress;
36    size_t len;
37    int fd;
38    unsigned int mode;
39    /*
40     * possible values:
41     * NBIO_READ, NBIO_WRITE - obvious
42     * -1 - currently doing nothing
43     * -2 - the pointer was reallocated since the last operation
44     */
45    signed char op;
46 };
47
48 static void *nbio_orbis_open(const char * filename, unsigned int mode)
49 {
50    static const int o_flags[]  =   { O_RDONLY, O_RDWR | O_CREAT | O_TRUNC,
51       O_RDWR, O_RDONLY, O_RDWR | O_CREAT | O_TRUNC };
52    void *buf                   = NULL;
53    struct nbio_orbis_t* handle = NULL;
54    size_t len                  = 0;
55    int fd                      = orbisOpen(filename, o_flags[mode], 0644);
56
57    if (fd < 0)
58       return NULL;
59    handle                = (struct nbio_orbis_t*)malloc(sizeof(struct nbio_orbis_t));
60
61    if (!handle)
62       goto error;
63
64    handle->fd             = fd;
65
66    switch (mode)
67    {
68       case NBIO_WRITE:
69       case BIO_WRITE:
70          break;
71       default:
72          len=orbisLseek(handle->fd, 0, SEEK_END);
73          orbisLseek(handle->fd, 0, SEEK_SET);
74          break;
75    }
76
77    handle->mode          = mode;
78
79    if (len)
80       buf                = malloc(len);
81
82    if (len && !buf)
83       goto error;
84
85    handle->data          = buf;
86    handle->len           = len;
87    handle->progress      = handle->len;
88    handle->op            = -2;
89
90    return handle;
91
92 error:
93    if (handle)
94       free(handle);
95    orbisClose(fd);
96    return NULL;
97 }
98
99 static void nbio_orbis_begin_read(void *data)
100 {
101
102    struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
103    if (!handle)
104       return;
105
106    if (handle->op >= 0)
107       return;
108
109    orbisLseek(handle->fd, 0, SEEK_SET);
110
111    handle->op       = NBIO_READ;
112    handle->progress = 0;
113 }
114
115 static void nbio_orbis_begin_write(void *data)
116 {
117    struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
118    if (!handle)
119       return;
120
121    if (handle->op >= 0)
122       return;
123
124    orbisLseek(handle->fd, 0, SEEK_SET);
125    handle->op = NBIO_WRITE;
126    handle->progress = 0;
127 }
128
129 static bool nbio_orbis_iterate(void *data)
130 {
131    size_t amount               = 65536;
132    struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
133
134    if (!handle)
135       return false;
136
137    if (amount > handle->len - handle->progress)
138       amount = handle->len - handle->progress;
139
140    switch (handle->op)
141    {
142       case NBIO_READ:
143          if (handle->mode == BIO_READ)
144             amount = handle->len;
145          break;
146       case NBIO_WRITE:
147          if (handle->mode == BIO_WRITE)
148          {
149             size_t written = 0;
150             amount = handle->len;
151             written = orbisWrite(handle->fd, (char*)handle->data, amount);
152
153             if (written != amount)
154                return false;
155          }
156          break;
157    }
158
159    handle->progress += amount;
160
161    if (handle->progress == handle->len)
162       handle->op = -1;
163    return (handle->op < 0);
164 }
165
166 static void nbio_orbis_resize(void *data, size_t len)
167 {
168    struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
169    if (!handle)
170       return;
171
172    if (handle->op >= 0)
173       return;
174    if (len < handle->len)
175       return;
176
177    handle->len      = len;
178    handle->data     = realloc(handle->data, handle->len);
179    handle->op       = -1;
180    handle->progress = handle->len;
181 }
182
183 static void *nbio_orbis_get_ptr(void *data, size_t* len)
184 {
185    struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
186    if (!handle)
187       return NULL;
188    if (len)
189       *len = handle->len;
190    if (handle->op == -1)
191       return handle->data;
192    return NULL;
193 }
194
195 static void nbio_orbis_cancel(void *data)
196 {
197    struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
198    if (!handle)
199       return;
200    handle->op = -1;
201    handle->progress = handle->len;
202 }
203
204 static void nbio_orbis_free(void *data)
205 {
206    struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
207    if (!handle)
208       return;
209
210    if (handle->op >= 0)
211       return;
212
213    orbisClose(handle->fd);
214    free(handle->data);
215
216    handle->data = NULL;
217    free(handle);
218 }
219
220 nbio_intf_t nbio_orbis = {
221    nbio_orbis_open,
222    nbio_orbis_begin_read,
223    nbio_orbis_begin_write,
224    nbio_orbis_iterate,
225    nbio_orbis_resize,
226    nbio_orbis_get_ptr,
227    nbio_orbis_cancel,
228    nbio_orbis_free,
229    "nbio_orbis",
230 };
231 #endif