libretro: adjust psxclock description
[pcsx_rearmed.git] / deps / libretro-common / file / nbio / nbio_stdio.c
CommitLineData
3719602c
PC
1/* Copyright (C) 2010-2020 The RetroArch team
2 *
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (nbio_stdio.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 <stdio.h>
24#include <stdlib.h>
25#if defined(WIIU)
26#include <malloc.h>
27#endif
28
29#include <file/nbio.h>
30#include <encodings/utf.h>
31
32/* Assume W-functions do not work below Win2K and Xbox platforms */
33#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
34
35#ifndef LEGACY_WIN32
36#define LEGACY_WIN32
37#endif
38
39#endif
40
41#if defined(_WIN32)
42#if defined(_MSC_VER) && _MSC_VER >= 1400
43#define ATLEAST_VC2005
44#endif
45#endif
46
47#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
48#ifndef HAVE_64BIT_OFFSETS
49#define HAVE_64BIT_OFFSETS
50#endif
51#endif
52
53struct nbio_stdio_t
54{
55 FILE* f;
56 void* data;
57 size_t progress;
58 size_t len;
59 /*
60 * possible values:
61 * NBIO_READ, NBIO_WRITE - obvious
62 * -1 - currently doing nothing
63 * -2 - the pointer was reallocated since the last operation
64 */
65 signed char op;
66 signed char mode;
67};
68
69#if !defined(_WIN32) || defined(LEGACY_WIN32)
70static const char *stdio_modes[] = { "rb", "wb", "r+b", "rb", "wb", "r+b" };
71#else
72static const wchar_t *stdio_modes[] = { L"rb", L"wb", L"r+b", L"rb", L"wb", L"r+b" };
73#endif
74
75static int64_t fseek_wrap(FILE *f, int64_t offset, int origin)
76{
77#ifdef ATLEAST_VC2005
78 /* VC2005 and up have a special 64-bit fseek */
79 return _fseeki64(f, offset, origin);
80#elif defined(HAVE_64BIT_OFFSETS)
81 return fseeko(f, (off_t)offset, origin);
82#else
83 return fseek(f, (long)offset, origin);
84#endif
85}
86
87static int64_t ftell_wrap(FILE *f)
88{
89#ifdef ATLEAST_VC2005
90 /* VC2005 and up have a special 64-bit ftell */
91 return _ftelli64(f);
92#elif defined(HAVE_64BIT_OFFSETS)
93 return ftello(f);
94#else
95 return ftell(f);
96#endif
97}
98
99static void *nbio_stdio_open(const char * filename, unsigned mode)
100{
101 void *buf = NULL;
102 struct nbio_stdio_t* handle = NULL;
103 int64_t len = 0;
104#if !defined(_WIN32) || defined(LEGACY_WIN32)
105 FILE* f = fopen(filename, stdio_modes[mode]);
106#else
107 wchar_t *filename_wide = utf8_to_utf16_string_alloc(filename);
108 FILE* f = _wfopen(filename_wide, stdio_modes[mode]);
109
110 if (filename_wide)
111 free(filename_wide);
112#endif
113 if (!f)
114 return NULL;
115
116 handle = (struct nbio_stdio_t*)malloc(sizeof(struct nbio_stdio_t));
117
118 if (!handle)
119 goto error;
120
121 handle->f = f;
122
123 switch (mode)
124 {
125 case NBIO_WRITE:
126 case BIO_WRITE:
127 break;
128 default:
129 fseek_wrap(handle->f, 0, SEEK_END);
130 len = ftell_wrap(handle->f);
131 break;
132 }
133
134 handle->mode = mode;
135
136#if defined(WIIU)
137 /* hit the aligned-buffer fast path on Wii U */
138 if (len)
139 buf = memalign(0x40, (size_t)len);
140#else
141 if (len)
142 buf = malloc((size_t)len);
143#endif
144
145 if (len && !buf)
146 goto error;
147
148 handle->data = buf;
149 handle->len = len;
150 handle->progress = handle->len;
151 handle->op = -2;
152
153 return handle;
154
155error:
156 if (handle)
157 free(handle);
158 fclose(f);
159 return NULL;
160}
161
162static void nbio_stdio_begin_read(void *data)
163{
164 struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
165 if (!handle)
166 return;
167
168 if (handle->op >= 0)
169 abort();
170
171 fseek_wrap(handle->f, 0, SEEK_SET);
172
173 handle->op = NBIO_READ;
174 handle->progress = 0;
175}
176
177static void nbio_stdio_begin_write(void *data)
178{
179 struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
180 if (!handle)
181 return;
182
183 if (handle->op >= 0)
184 abort();
185
186 fseek_wrap(handle->f, 0, SEEK_SET);
187 handle->op = NBIO_WRITE;
188 handle->progress = 0;
189}
190
191static bool nbio_stdio_iterate(void *data)
192{
193 size_t amount = 65536;
194 struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
195
196 if (!handle)
197 return false;
198
199 if (amount > handle->len - handle->progress)
200 amount = handle->len - handle->progress;
201
202 switch (handle->op)
203 {
204 case NBIO_READ:
205 if (handle->mode == BIO_READ)
206 {
207 amount = handle->len;
208 fread((char*)handle->data, 1, amount, handle->f);
209 }
210 else
211 fread((char*)handle->data + handle->progress, 1, amount, handle->f);
212 break;
213 case NBIO_WRITE:
214 if (handle->mode == BIO_WRITE)
215 {
216 size_t written = 0;
217 amount = handle->len;
218 written = fwrite((char*)handle->data, 1, amount, handle->f);
219 if (written != amount)
220 return false;
221 }
222 else
223 fwrite((char*)handle->data + handle->progress, 1, amount, handle->f);
224 break;
225 }
226
227 handle->progress += amount;
228
229 if (handle->progress == handle->len)
230 handle->op = -1;
231 return (handle->op < 0);
232}
233
234static void nbio_stdio_resize(void *data, size_t len)
235{
236 void *new_data = NULL;
237 struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
238 if (!handle)
239 return;
240
241 if (handle->op >= 0)
242 abort();
243 if (len < handle->len)
244 abort();
245
246 handle->len = len;
247 handle->progress = len;
248 handle->op = -1;
249
250 new_data = realloc(handle->data, handle->len);
251
252 if (new_data)
253 handle->data = new_data;
254}
255
256static void *nbio_stdio_get_ptr(void *data, size_t* len)
257{
258 struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
259 if (!handle)
260 return NULL;
261 if (len)
262 *len = handle->len;
263 if (handle->op == -1)
264 return handle->data;
265 return NULL;
266}
267
268static void nbio_stdio_cancel(void *data)
269{
270 struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
271 if (!handle)
272 return;
273
274 handle->op = -1;
275 handle->progress = handle->len;
276}
277
278static void nbio_stdio_free(void *data)
279{
280 struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
281 if (!handle)
282 return;
283 if (handle->op >= 0)
284 abort();
285 fclose(handle->f);
286 free(handle->data);
287
288 handle->f = NULL;
289 handle->data = NULL;
290 free(handle);
291}
292
293nbio_intf_t nbio_stdio = {
294 nbio_stdio_open,
295 nbio_stdio_begin_read,
296 nbio_stdio_begin_write,
297 nbio_stdio_iterate,
298 nbio_stdio_resize,
299 nbio_stdio_get_ptr,
300 nbio_stdio_cancel,
301 nbio_stdio_free,
302 "nbio_stdio",
303};