1 /*
2 * Copyright (c) 2003-2012 Hypertriton, Inc. <http://hypertriton.com/>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 /*
27 * Basic I/O abstraction routines.
28 */
29
30 #include <agar/core/core.h>
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdarg.h>
35
36 static AG_Object errorMgr;
37
38 void
AG_DataSourceInitSubsystem(void)39 AG_DataSourceInitSubsystem(void)
40 {
41 AG_ObjectInitStatic(&errorMgr, NULL);
42 }
43
44 void
AG_DataSourceDestroySubsystem(void)45 AG_DataSourceDestroySubsystem(void)
46 {
47 AG_ObjectDestroy(&errorMgr);
48 }
49
50 /* Assign an error callback routine to a data source. */
51 void
AG_DataSourceSetErrorFn(AG_DataSource * ds,AG_EventFn fn,const char * fmt,...)52 AG_DataSourceSetErrorFn(AG_DataSource *ds, AG_EventFn fn, const char *fmt, ...)
53 {
54 AG_ObjectLock(&errorMgr);
55 ds->errorFn = AG_SetEvent(&errorMgr, NULL, fn, NULL);
56 AG_EVENT_GET_ARGS(ds->errorFn, fmt);
57 AG_ObjectUnlock(&errorMgr);
58 }
59
60 /* Raise a data source exception. */
61 void
AG_DataSourceError(AG_DataSource * ds,const char * fmt,...)62 AG_DataSourceError(AG_DataSource *ds, const char *fmt, ...)
63 {
64 static char msg[256];
65 va_list args;
66
67 if (fmt != NULL) {
68 va_start(args, fmt);
69 Vsnprintf(msg, sizeof(msg), fmt, args);
70 va_end(args);
71 } else {
72 Strlcpy(msg, AG_GetError(), sizeof(msg));
73 }
74
75 AG_ObjectLock(&errorMgr);
76 AG_PostEventByPtr(NULL, &errorMgr, ds->errorFn, "%s", msg);
77 AG_ObjectUnlock(&errorMgr);
78 }
79
80 /* Enable checking of debugging information. */
81 void
AG_DataSourceSetDebug(AG_DataSource * ds,int flag)82 AG_DataSourceSetDebug(AG_DataSource *ds, int flag)
83 {
84 ds->debug = flag;
85 }
86
87 /* Write type identifier for type safety checks. */
88 void
AG_WriteTypeCode(AG_DataSource * ds,Uint32 type)89 AG_WriteTypeCode(AG_DataSource *ds, Uint32 type)
90 {
91 Uint32 i = (ds->byte_order == AG_BYTEORDER_BE) ? AG_SwapBE32(type) :
92 AG_SwapLE32(type);
93
94 if (AG_Write(ds, &i, sizeof(i)) != 0)
95 AG_DataSourceError(ds, NULL);
96 }
97
98 /* Write type identifier for type safety checks (offset). */
99 void
AG_WriteTypeCodeAt(AG_DataSource * ds,Uint32 type,off_t offs)100 AG_WriteTypeCodeAt(AG_DataSource *ds, Uint32 type, off_t offs)
101 {
102 Uint32 i = (ds->byte_order == AG_BYTEORDER_BE) ? AG_SwapBE32(type) :
103 AG_SwapLE32(type);
104
105 if (AG_WriteAt(ds, &i, sizeof(i), offs) != 0)
106 AG_DataSourceError(ds, NULL);
107 }
108
109 /* Write type identifier for type safety checks (error-check). */
110 int
AG_WriteTypeCodeE(AG_DataSource * ds,Uint32 type)111 AG_WriteTypeCodeE(AG_DataSource *ds, Uint32 type)
112 {
113 Uint32 i;
114
115 i = (ds->byte_order == AG_BYTEORDER_BE) ? AG_SwapBE32(type) :
116 AG_SwapLE32(type);
117
118 return AG_Write(ds, &i, sizeof(i));
119 }
120
121 /* Check type identifier for type safety checks (error-check). */
122 int
AG_CheckTypeCode(AG_DataSource * ds,Uint32 type)123 AG_CheckTypeCode(AG_DataSource *ds, Uint32 type)
124 {
125 Uint32 i;
126
127 if (AG_Read(ds, &i, sizeof(i)) != 0) {
128 AG_SetError("Reading type ID: %s", AG_GetError());
129 return (-1);
130 }
131 i = ((ds->byte_order == AG_BYTEORDER_BE) ? AG_SwapBE32(i) :
132 AG_SwapLE32(i));
133 return (i == type) ? 0 : -1;
134 }
135
136 /*
137 * No-ops
138 */
139 static int
WriteNotSup(AG_DataSource * ds,const void * buf,size_t size,size_t * rv)140 WriteNotSup(AG_DataSource *ds, const void *buf, size_t size, size_t *rv)
141 {
142 AG_SetError(_("Operation not supported"));
143 return (-1);
144 }
145 static int
WriteAtNotSup(AG_DataSource * ds,const void * buf,size_t size,off_t pos,size_t * rv)146 WriteAtNotSup(AG_DataSource *ds, const void *buf, size_t size, off_t pos, size_t *rv)
147 {
148 AG_SetError(_("Operation not supported"));
149 return (-1);
150 }
151
152 #ifdef AG_NETWORK
153 static int
ReadAtNotSup(AG_DataSource * ds,void * buf,size_t size,off_t pos,size_t * rv)154 ReadAtNotSup(AG_DataSource *ds, void *buf, size_t size, off_t pos, size_t *rv)
155 {
156 AG_SetError(_("Operation not supported"));
157 return (-1);
158 }
159 static off_t
TellNotSup(AG_DataSource * ds)160 TellNotSup(AG_DataSource *ds)
161 {
162 return (0);
163 }
164 static int
SeekNotSup(AG_DataSource * ds,off_t offs,enum ag_seek_mode mode)165 SeekNotSup(AG_DataSource *ds, off_t offs, enum ag_seek_mode mode)
166 {
167 AG_SetError(_("Seek not supported by data source"));
168 return (-1);
169 }
170 #endif /* AG_NETWORK */
171
172 /*
173 * File operations.
174 */
175 static int
FileRead(AG_DataSource * ds,void * buf,size_t size,size_t * rv)176 FileRead(AG_DataSource *ds, void *buf, size_t size, size_t *rv)
177 {
178 FILE *f = AG_FILE_SOURCE(ds)->file;
179
180 clearerr(f);
181 *rv = fread(buf, 1, size, f);
182 if (*rv < size && ferror(f)) {
183 AG_SetError(_("Read error"));
184 return (-1);
185 }
186 return (0);
187 }
188 static int
FileReadAt(AG_DataSource * ds,void * buf,size_t size,off_t pos,size_t * rv)189 FileReadAt(AG_DataSource *ds, void *buf, size_t size, off_t pos, size_t *rv)
190 {
191 FILE *f = AG_FILE_SOURCE(ds)->file;
192 long savedPos = ftell(f);
193
194 if (fseek(f, pos, SEEK_SET) == -1) { goto fail_seek; }
195 clearerr(f);
196 *rv = fread(buf, 1, size, f);
197 if (*rv < size && ferror(f)) {
198 if (fseek(f, savedPos, SEEK_SET) == -1) { goto fail_seek; }
199 AG_SetError(_("Read Error"));
200 return (-1);
201 }
202 if (fseek(f, savedPos, SEEK_SET) == -1) { goto fail_seek; }
203 return (0);
204 fail_seek:
205 AG_SetError("fseek failed");
206 return (-1);
207 }
208 static int
FileWrite(AG_DataSource * ds,const void * buf,size_t size,size_t * rv)209 FileWrite(AG_DataSource *ds, const void *buf, size_t size, size_t *rv)
210 {
211 FILE *f = AG_FILE_SOURCE(ds)->file;
212
213 clearerr(f);
214 *rv = fwrite(buf, 1, size, f);
215 if (*rv < size && ferror(f)) {
216 AG_SetError(_("Write error"));
217 return (-1);
218 }
219 return (0);
220 }
221 static int
FileWriteAt(AG_DataSource * ds,const void * buf,size_t size,off_t pos,size_t * rv)222 FileWriteAt(AG_DataSource *ds, const void *buf, size_t size, off_t pos,
223 size_t *rv)
224 {
225 FILE *f = AG_FILE_SOURCE(ds)->file;
226 long savedPos = ftell(f);
227
228 if (fseek(f, pos, SEEK_SET) == -1) { goto fail_seek; }
229 clearerr(f);
230 *rv = fwrite(buf, 1, size, f);
231 if (*rv < size && ferror(f)) {
232 if (fseek(f, savedPos, SEEK_SET) == -1) { goto fail_seek; }
233 AG_SetError(_("Write Error"));
234 return (-1);
235 }
236 if (fseek(f, savedPos, SEEK_SET) == -1) { goto fail_seek; }
237 return (0);
238 fail_seek:
239 AG_SetError("fseek failed");
240 return (-1);
241 }
242 static off_t
FileTell(AG_DataSource * ds)243 FileTell(AG_DataSource *ds)
244 {
245 return ftell(AG_FILE_SOURCE(ds)->file);
246 }
247 static int
FileSeek(AG_DataSource * ds,off_t offs,enum ag_seek_mode mode)248 FileSeek(AG_DataSource *ds, off_t offs, enum ag_seek_mode mode)
249 {
250 FILE *f = AG_FILE_SOURCE(ds)->file;
251
252 if (fseek(f, (long)offs,
253 (mode == AG_SEEK_SET) ? SEEK_SET :
254 (mode == AG_SEEK_CUR) ? SEEK_CUR :
255 SEEK_END) == -1) {
256 AG_SetError("fseek failed");
257 return (-1);
258 }
259 return (0);
260 }
261 void
AG_CloseFile(AG_DataSource * ds)262 AG_CloseFile(AG_DataSource *ds)
263 {
264 AG_FileSource *fs = AG_FILE_SOURCE(ds);
265
266 fclose(fs->file);
267 Free(fs->path);
268 AG_DataSourceDestroy(ds);
269 }
270
271 /*
272 * Memory operations.
273 */
274 static __inline__ int
CoreLimitBounds(AG_CoreSource * cs,off_t pos,size_t sizeReq,size_t * size)275 CoreLimitBounds(AG_CoreSource *cs, off_t pos, size_t sizeReq, size_t *size)
276 {
277 if (pos+sizeReq > cs->size) {
278 *size = cs->size - cs->offs;
279 } else {
280 *size = sizeReq;
281 }
282 return (0);
283 }
284 static int
CoreRead(AG_DataSource * ds,void * buf,size_t sizeReq,size_t * rv)285 CoreRead(AG_DataSource *ds, void *buf, size_t sizeReq, size_t *rv)
286 {
287 AG_CoreSource *cs = AG_CORE_SOURCE(ds);
288 size_t size;
289
290 if (CoreLimitBounds(cs, cs->offs, sizeReq, &size) == -1) {
291 return (-1);
292 }
293 memcpy(buf, &cs->data[cs->offs], size);
294 *rv = size;
295 cs->offs += size;
296 return (0);
297 }
298 static int
CoreReadAt(AG_DataSource * ds,void * buf,size_t sizeReq,off_t pos,size_t * rv)299 CoreReadAt(AG_DataSource *ds, void *buf, size_t sizeReq, off_t pos, size_t *rv)
300 {
301 AG_CoreSource *cs = AG_CORE_SOURCE(ds);
302 size_t size;
303
304 if (CoreLimitBounds(cs, pos, sizeReq, &size) == -1) {
305 return (-1);
306 }
307 memcpy(buf, &cs->data[pos], size);
308 *rv = size;
309 return (0);
310 }
311 static int
CoreWrite(AG_DataSource * ds,const void * buf,size_t sizeReq,size_t * rv)312 CoreWrite(AG_DataSource *ds, const void *buf, size_t sizeReq, size_t *rv)
313 {
314 AG_CoreSource *cs = AG_CORE_SOURCE(ds);
315 size_t size;
316
317 if (CoreLimitBounds(cs, cs->offs, sizeReq, &size) == -1) {
318 return (-1);
319 }
320 memcpy(&cs->data[cs->offs], buf, size);
321 *rv = size;
322 cs->offs += size;
323 return (0);
324 }
325 static int
CoreAutoWrite(AG_DataSource * ds,const void * buf,size_t size,size_t * rv)326 CoreAutoWrite(AG_DataSource *ds, const void *buf, size_t size, size_t *rv)
327 {
328 AG_CoreSource *cs = AG_CORE_SOURCE(ds);
329 Uint8 *dataNew;
330
331 if (cs->offs+size > cs->size) {
332 if ((dataNew = TryRealloc(cs->data, (cs->offs+size))) == NULL) {
333 return (-1);
334 }
335 cs->data = dataNew;
336 }
337 memcpy(&cs->data[cs->offs], buf, size);
338 cs->size += size;
339 cs->offs += size;
340 *rv = size;
341 return (0);
342 }
343 static int
CoreWriteAt(AG_DataSource * ds,const void * buf,size_t sizeReq,off_t pos,size_t * rv)344 CoreWriteAt(AG_DataSource *ds, const void *buf, size_t sizeReq, off_t pos,
345 size_t *rv)
346 {
347 AG_CoreSource *cs = AG_CORE_SOURCE(ds);
348 size_t size;
349
350 if (CoreLimitBounds(cs, pos, sizeReq, &size) == -1) {
351 return (-1);
352 }
353 memcpy(&cs->data[pos], buf, size);
354 *rv = size;
355 return (0);
356 }
357 static int
CoreAutoWriteAt(AG_DataSource * ds,const void * buf,size_t size,off_t pos,size_t * rv)358 CoreAutoWriteAt(AG_DataSource *ds, const void *buf, size_t size, off_t pos,
359 size_t *rv)
360 {
361 AG_CoreSource *cs = AG_CORE_SOURCE(ds);
362 Uint8 *dataNew;
363
364 if (pos < 0) {
365 AG_SetError("Bad offset");
366 return (-1);
367 }
368 if (pos+size > cs->size) {
369 if ((dataNew = TryRealloc(cs->data, (pos+size))) == NULL) {
370 return (-1);
371 }
372 cs->data = dataNew;
373 cs->size = pos+size;
374 }
375 memcpy(&cs->data[pos], buf, size);
376 *rv = size;
377 return (0);
378 }
379 static off_t
CoreTell(AG_DataSource * ds)380 CoreTell(AG_DataSource *ds)
381 {
382 return AG_CORE_SOURCE(ds)->offs;
383 }
384 static int
CoreSeek(AG_DataSource * ds,off_t offs,enum ag_seek_mode mode)385 CoreSeek(AG_DataSource *ds, off_t offs, enum ag_seek_mode mode)
386 {
387 AG_CoreSource *cs = AG_CORE_SOURCE(ds);
388 off_t nOffs;
389
390 switch (mode) {
391 case AG_SEEK_SET:
392 nOffs = offs;
393 break;
394 case AG_SEEK_CUR:
395 nOffs = cs->offs + offs;
396 break;
397 case AG_SEEK_END:
398 default:
399 nOffs = cs->size - offs;
400 break;
401 }
402 if (nOffs < 0 || nOffs >= cs->size) {
403 AG_SetError("Bad offset %ld", (long)nOffs);
404 return (-1);
405 }
406 cs->offs = nOffs;
407 return (0);
408 }
409 void
AG_CloseCore(AG_DataSource * ds)410 AG_CloseCore(AG_DataSource *ds)
411 {
412 AG_DataSourceDestroy(ds);
413 }
414 void
AG_CloseAutoCore(AG_DataSource * ds)415 AG_CloseAutoCore(AG_DataSource *ds)
416 {
417 Free(AG_CORE_SOURCE(ds)->data);
418 AG_DataSourceDestroy(ds);
419 }
420
421 #ifdef AG_NETWORK
422 /*
423 * Network socket operations
424 */
425 static int
NetSocketRead(AG_DataSource * ds,void * buf,size_t size,size_t * rv)426 NetSocketRead(AG_DataSource *ds, void *buf, size_t size, size_t *rv)
427 {
428 AG_NetSocketSource *nss = AG_NET_SOCKET_SOURCE(ds);
429 return AG_NetRead(nss->sock, buf, size, rv);
430 }
431 static int
NetSocketWrite(AG_DataSource * ds,const void * buf,size_t size,size_t * rv)432 NetSocketWrite(AG_DataSource *ds, const void *buf, size_t size, size_t *rv)
433 {
434 AG_NetSocketSource *nss = AG_NET_SOCKET_SOURCE(ds);
435 return AG_NetWrite(nss->sock, buf, size, rv);
436 }
437 void
AG_CloseNetSocket(AG_DataSource * ds)438 AG_CloseNetSocket(AG_DataSource *ds)
439 {
440 AG_DataSourceDestroy(ds);
441 }
442 #endif
443
444 /* Default error handler */
445 static void
ErrorDefault(AG_Event * event)446 ErrorDefault(AG_Event *event)
447 {
448 AG_FatalError("Data source error: %s", AG_GetError());
449 }
450
451 /* Initialize the data source structure. */
452 void
AG_DataSourceInit(AG_DataSource * ds)453 AG_DataSourceInit(AG_DataSource *ds)
454 {
455 ds->debug = 0;
456 ds->byte_order = AG_BYTEORDER_BE;
457 ds->rdLast = 0;
458 ds->wrLast = 0;
459 ds->rdTotal = 0;
460 ds->wrTotal = 0;
461 ds->read = NULL;
462 ds->read_at = NULL;
463 ds->write = NULL;
464 ds->write_at = NULL;
465 ds->tell = NULL;
466 ds->seek = NULL;
467 ds->close = NULL;
468 AG_MutexInitRecursive(&ds->lock);
469 AG_DataSourceSetErrorFn(ds, ErrorDefault, "%p", ds);
470 }
471
472 /* Close a data source of any type. */
473 void
AG_CloseDataSource(AG_DataSource * ds)474 AG_CloseDataSource(AG_DataSource *ds)
475 {
476 ds->close(ds);
477 }
478
479 /* Release the resources allocated by the data source structure. */
480 void
AG_DataSourceDestroy(AG_DataSource * ds)481 AG_DataSourceDestroy(AG_DataSource *ds)
482 {
483 AG_MutexDestroy(&ds->lock);
484 Free(ds);
485 }
486
487 /* Create a data source from a stdio file handle. */
488 AG_DataSource *
AG_OpenFileHandle(FILE * f)489 AG_OpenFileHandle(FILE *f)
490 {
491 AG_FileSource *fs;
492
493 fs = Malloc(sizeof(AG_FileSource));
494 AG_DataSourceInit(&fs->ds);
495 fs->path = NULL;
496 fs->file = f;
497 fs->ds.read = FileRead;
498 fs->ds.read_at = FileReadAt;
499 fs->ds.write = FileWrite;
500 fs->ds.write_at = FileWriteAt;
501 fs->ds.tell = FileTell;
502 fs->ds.seek = FileSeek;
503 fs->ds.close = AG_CloseFile;
504 return (&fs->ds);
505 }
506
507 /* Create a data source from a specified file path. */
508 AG_DataSource *
AG_OpenFile(const char * path,const char * mode)509 AG_OpenFile(const char *path, const char *mode)
510 {
511 FILE *f;
512
513 if ((f = fopen(path, mode)) == NULL) {
514 AG_SetError(_("Unable to open %s"), path);
515 return (NULL);
516 }
517 return AG_OpenFileHandle(f);
518 }
519
520 /* Create a data source from a specified chunk of memory. */
521 AG_DataSource *
AG_OpenCore(void * data,size_t size)522 AG_OpenCore(void *data, size_t size)
523 {
524 AG_CoreSource *cs;
525
526 if ((cs = TryMalloc(sizeof(AG_CoreSource))) == NULL) {
527 return (NULL);
528 }
529 AG_DataSourceInit(&cs->ds);
530 cs->data = (Uint8 *)data;
531 cs->size = size;
532 cs->offs = 0;
533 cs->ds.read = CoreRead;
534 cs->ds.read_at = CoreReadAt;
535 cs->ds.write = CoreWrite;
536 cs->ds.write_at = CoreWriteAt;
537 cs->ds.tell = CoreTell;
538 cs->ds.seek = CoreSeek;
539 cs->ds.close = AG_CloseCore;
540 return (&cs->ds);
541 }
542
543 /* Create a data source from a specified chunk of memory (read-only). */
544 AG_DataSource *
AG_OpenConstCore(const void * data,size_t size)545 AG_OpenConstCore(const void *data, size_t size)
546 {
547 AG_ConstCoreSource *cs;
548
549 if ((cs = TryMalloc(sizeof(AG_ConstCoreSource))) == NULL) {
550 return (NULL);
551 }
552 AG_DataSourceInit(&cs->ds);
553 cs->data = (const Uint8 *)data;
554 cs->size = size;
555 cs->offs = 0;
556 cs->ds.read = CoreRead;
557 cs->ds.read_at = CoreReadAt;
558 cs->ds.write = WriteNotSup;
559 cs->ds.write_at = WriteAtNotSup;
560 cs->ds.tell = CoreTell;
561 cs->ds.seek = CoreSeek;
562 cs->ds.close = AG_CloseCore;
563 return (&cs->ds);
564 }
565
566 /* Create a data source using dynamically-allocated memory. */
567 AG_DataSource *
AG_OpenAutoCore(void)568 AG_OpenAutoCore(void)
569 {
570 AG_CoreSource *cs;
571
572 if ((cs = TryMalloc(sizeof(AG_CoreSource))) == NULL) {
573 return (NULL);
574 }
575 AG_DataSourceInit(&cs->ds);
576 cs->data = NULL;
577 cs->size = 0;
578 cs->offs = 0;
579 cs->ds.read = CoreRead;
580 cs->ds.read_at = CoreReadAt;
581 cs->ds.write = CoreAutoWrite;
582 cs->ds.write_at = CoreAutoWriteAt;
583 cs->ds.tell = CoreTell;
584 cs->ds.seek = CoreSeek;
585 cs->ds.close = AG_CloseAutoCore;
586 return (&cs->ds);
587 }
588
589 #ifdef AG_NETWORK
590 /* Create a data source using a network socket. */
591 AG_DataSource *
AG_OpenNetSocket(AG_NetSocket * ns)592 AG_OpenNetSocket(AG_NetSocket *ns)
593 {
594 AG_NetSocketSource *ss;
595
596 if ((ss = TryMalloc(sizeof(AG_NetSocketSource))) == NULL) {
597 return (NULL);
598 }
599 AG_DataSourceInit(&ss->ds);
600 ss->sock = ns;
601 ss->ds.read = NetSocketRead;
602 ss->ds.read_at = ReadAtNotSup;
603 ss->ds.write = NetSocketWrite;
604 ss->ds.write_at = WriteAtNotSup;
605 ss->ds.tell = TellNotSup;
606 ss->ds.seek = SeekNotSup;
607 ss->ds.close = AG_CloseNetSocket;
608 return (&ss->ds);
609 }
610 #endif /* AG_NETWORK */
611
612 /* Select the byte order of the source. */
613 void
AG_SetByteOrder(AG_DataSource * ds,enum ag_byte_order order)614 AG_SetByteOrder(AG_DataSource *ds, enum ag_byte_order order)
615 {
616 AG_MutexLock(&ds->lock);
617 ds->byte_order = order;
618 AG_MutexUnlock(&ds->lock);
619 }
620
621 /* Toggle encoding/decoding of debugging data. */
622 void
AG_SetSourceDebug(AG_DataSource * ds,int enable)623 AG_SetSourceDebug(AG_DataSource *ds, int enable)
624 {
625 AG_MutexLock(&ds->lock);
626 ds->debug = enable;
627 AG_MutexUnlock(&ds->lock);
628 }
629
630 /* Low-level read operation. */
631 int
AG_Read(AG_DataSource * ds,void * ptr,size_t size)632 AG_Read(AG_DataSource *ds, void *ptr, size_t size)
633 {
634 int rv;
635 AG_MutexLock(&ds->lock);
636 rv = ds->read(ds, ptr, size, &ds->rdLast);
637 ds->rdTotal += ds->rdLast;
638 if (ds->rdLast < size) {
639 AG_SetError("Short read");
640 rv = -1;
641 }
642 AG_MutexUnlock(&ds->lock);
643 return (rv);
644 }
645
646 /* Low-level read operation (partial reads allowed). */
647 int
AG_ReadP(AG_DataSource * ds,void * ptr,size_t size,size_t * nRead)648 AG_ReadP(AG_DataSource *ds, void *ptr, size_t size, size_t *nRead)
649 {
650 int rv;
651 AG_MutexLock(&ds->lock);
652 rv = ds->read(ds, ptr, size, &ds->rdLast);
653 ds->rdTotal += ds->rdLast;
654 if (nRead != NULL) { *nRead = ds->rdLast; }
655 AG_MutexUnlock(&ds->lock);
656 return (rv);
657 }
658
659 /* Low-level read-at-offset operation. */
660 int
AG_ReadAt(AG_DataSource * ds,void * ptr,size_t size,off_t pos)661 AG_ReadAt(AG_DataSource *ds, void *ptr, size_t size, off_t pos)
662 {
663 int rv;
664 AG_MutexLock(&ds->lock);
665 rv = ds->read_at(ds, ptr, size, pos, &ds->rdLast);
666 ds->rdTotal += ds->rdLast;
667 if (ds->rdLast < size) {
668 AG_SetError("Short read");
669 rv = -1;
670 }
671 AG_MutexUnlock(&ds->lock);
672 return (rv);
673 }
674
675 /* Low-level read-at-offset operation (partial reads allowed). */
676 int
AG_ReadAtP(AG_DataSource * ds,void * ptr,size_t size,off_t pos,size_t * nRead)677 AG_ReadAtP(AG_DataSource *ds, void *ptr, size_t size, off_t pos, size_t *nRead)
678 {
679 int rv;
680 AG_MutexLock(&ds->lock);
681 rv = ds->read_at(ds, ptr, size, pos, &ds->rdLast);
682 ds->rdTotal += ds->rdLast;
683 if (nRead != NULL) { *nRead = ds->rdLast; }
684 AG_MutexUnlock(&ds->lock);
685 return (rv);
686 }
687
688 /* Low-level write operation. */
689 int
AG_Write(AG_DataSource * ds,const void * ptr,size_t size)690 AG_Write(AG_DataSource *ds, const void *ptr, size_t size)
691 {
692 int rv;
693 AG_MutexLock(&ds->lock);
694 rv = ds->write(ds, ptr, size, &ds->wrLast);
695 ds->wrTotal += ds->wrLast;
696 if (ds->wrLast < size) {
697 AG_SetError("Short write");
698 rv = -1;
699 }
700 AG_MutexUnlock(&ds->lock);
701 return (rv);
702 }
703
704 /* Low-level write operation (partial writes allowed). */
705 int
AG_WriteP(AG_DataSource * ds,const void * ptr,size_t size,size_t * nWrote)706 AG_WriteP(AG_DataSource *ds, const void *ptr, size_t size, size_t *nWrote)
707 {
708 int rv;
709 AG_MutexLock(&ds->lock);
710 rv = ds->write(ds, ptr, size, &ds->wrLast);
711 ds->wrTotal += ds->wrLast;
712 if (nWrote != NULL) { *nWrote = ds->wrLast; }
713 AG_MutexUnlock(&ds->lock);
714 return (rv);
715 }
716
717 /* Low-level write-at-offset operation. */
718 int
AG_WriteAt(AG_DataSource * ds,const void * ptr,size_t size,off_t pos)719 AG_WriteAt(AG_DataSource *ds, const void *ptr, size_t size, off_t pos)
720 {
721 int rv;
722 AG_MutexLock(&ds->lock);
723 rv = ds->write_at(ds, ptr, size, pos, &ds->wrLast);
724 ds->wrTotal += ds->wrLast;
725 if (ds->wrLast < size) {
726 AG_SetError("Short write");
727 rv = -1;
728 }
729 AG_MutexUnlock(&ds->lock);
730 return (rv);
731 }
732
733 /* Low-level write-at-offset operation (partial writes allowed) */
734 int
AG_WriteAtP(AG_DataSource * ds,const void * ptr,size_t size,off_t pos,size_t * nWrote)735 AG_WriteAtP(AG_DataSource *ds, const void *ptr, size_t size, off_t pos, size_t *nWrote)
736 {
737 int rv;
738 AG_MutexLock(&ds->lock);
739 rv = ds->write_at(ds, ptr, size, pos, &ds->wrLast);
740 ds->wrTotal += ds->wrLast;
741 if (nWrote != NULL) { *nWrote = ds->wrLast; }
742 AG_MutexUnlock(&ds->lock);
743 return (rv);
744 }
745
746