169 lines
4.8 KiB
C
169 lines
4.8 KiB
C
/* ****************************************************************************
|
|
* stream/builtin/memory.c -- built-in memory stream.
|
|
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
|
*
|
|
* This file is part of libcasio.
|
|
* libcasio is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 3.0 of the License,
|
|
* or (at your option) any later version.
|
|
*
|
|
* libcasio is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with libcasio; if not, see <http://www.gnu.org/licenses/>.
|
|
* ************************************************************************* */
|
|
#include "../../internals.h"
|
|
|
|
/* cookie structure */
|
|
typedef struct {
|
|
unsigned char *_memory;
|
|
casio_off_t _size, _offset;
|
|
} memory_cookie_t;
|
|
/* ************************************************************************* */
|
|
/* Callbacks */
|
|
/* ************************************************************************* */
|
|
/**
|
|
* casio_memory_read:
|
|
* Read from a memory area.
|
|
*
|
|
* @arg vcookie the cookie (uncasted)
|
|
* @arg data the data pointer.
|
|
* @arg size the data size.
|
|
* @return the error code (0 if ok).
|
|
*/
|
|
|
|
CASIO_LOCAL int casio_memory_read(void *vcookie, unsigned char *dest, size_t size)
|
|
{
|
|
memory_cookie_t *cookie = (void*)vcookie;
|
|
|
|
if (((size_t)-1 - cookie->_offset) < size) /* overflow */
|
|
return (casio_error_read);
|
|
if (cookie->_offset + (casio_off_t)size > cookie->_size) {
|
|
cookie->_offset = cookie->_size - 1;
|
|
return (casio_error_eof);
|
|
}
|
|
|
|
memcpy(dest, &cookie->_memory[cookie->_offset], size);
|
|
cookie->_offset += size;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/**
|
|
* casio_memory_write:
|
|
* Write on a memory area.
|
|
*
|
|
* @arg vcookie the cookie (uncasted).
|
|
* @arg data the data pointer.
|
|
* @arg size the data size.
|
|
* @return the error code (0 if ok).
|
|
*/
|
|
|
|
CASIO_LOCAL int casio_memory_write(void *vcookie, const unsigned char *data,
|
|
size_t size)
|
|
{
|
|
memory_cookie_t *cookie = (void*)vcookie;
|
|
|
|
if (((size_t)-1 - cookie->_offset) < size) /* overflow */
|
|
return (casio_error_write);
|
|
if (cookie->_offset + (casio_off_t)size > cookie->_size) {
|
|
cookie->_offset = cookie->_size - 1;
|
|
return (casio_error_eof);
|
|
}
|
|
|
|
memcpy(&cookie->_memory[cookie->_offset], data, size);
|
|
cookie->_offset += size;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/**
|
|
* casio_memory_seek:
|
|
* Move within a memory area.
|
|
*
|
|
* @arg vcookie the cookie (uncasted).
|
|
* @arg offset the offset.
|
|
* @arg whence the whence.
|
|
* @return the error code (0 if ok).
|
|
*/
|
|
|
|
CASIO_LOCAL int casio_memory_seek(void *vcookie, casio_off_t *offset,
|
|
casio_whence_t whence)
|
|
{
|
|
memory_cookie_t *cookie = (void*)vcookie;
|
|
casio_off_t off;
|
|
|
|
/* get the offset */
|
|
switch (whence) {
|
|
case CASIO_SEEK_CUR: off = cookie->_offset + *offset; break;
|
|
case CASIO_SEEK_END: off = cookie->_size - *offset; break;
|
|
default /* CASIO_SEEK_SET */: off = *offset; break; }
|
|
|
|
/* check the bounds */
|
|
if (off < 0) off = 0;
|
|
else if (off >= cookie->_size) off = cookie->_size - 1;
|
|
|
|
/* set the offset, return */
|
|
*offset = off;
|
|
cookie->_offset = off;
|
|
return (0);
|
|
}
|
|
|
|
/**
|
|
* casio_memory_close:
|
|
* Close a FILE cookie.
|
|
*
|
|
* @arg vcookie the cookie (uncasted)
|
|
* @return the error code (0 if ok)
|
|
*/
|
|
|
|
CASIO_LOCAL int casio_memory_close(void *vcookie)
|
|
{
|
|
casio_free(vcookie);
|
|
return (0);
|
|
}
|
|
|
|
/* Callbacks. */
|
|
CASIO_LOCAL const casio_streamfuncs_t casio_memory_callbacks =
|
|
casio_stream_callbacks_for_virtual(casio_memory_close,
|
|
casio_memory_read, casio_memory_write, casio_memory_seek);
|
|
/* ************************************************************************* */
|
|
/* Opening functions */
|
|
/* ************************************************************************* */
|
|
/**
|
|
* casio_open_memory:
|
|
* Open a FILE stream.
|
|
*
|
|
* @arg stream the stream to make.
|
|
* @arg rstream the FILE stream to read from.
|
|
* @arg wstream the FILe stream to write to.
|
|
* @return the error (0 if ok).
|
|
*/
|
|
|
|
int CASIO_EXPORT casio_open_memory(casio_stream_t **stream,
|
|
const void *memory, size_t size)
|
|
{
|
|
memory_cookie_t *cookie = NULL;
|
|
|
|
/* check things */
|
|
if (!memory || !size)
|
|
return (casio_error_nostream);
|
|
|
|
/* allocate the cookie */
|
|
cookie = casio_alloc(1, sizeof(memory_cookie_t));
|
|
if (!cookie) return (casio_error_alloc);
|
|
|
|
/* fill the cookie */
|
|
cookie->_memory = (void*)memory;
|
|
cookie->_size = size;
|
|
cookie->_offset = 0;
|
|
|
|
/* initialize da stream */
|
|
return (casio_open(stream, CASIO_OPENMODE_READ, 0, cookie,
|
|
&casio_memory_callbacks));
|
|
}
|