HelenOS sources
This source file includes following definitions.
- riff_wopen
- riff_wclose
- riff_write_uint32
- riff_wchunk_start
- riff_wchunk_end
- riff_write
- riff_ropen
- riff_rclose
- riff_read_uint32
- riff_rchunk_start
- riff_rchunk_match
- riff_rchunk_list_match
- riff_rchunk_seek
- riff_rchunk_size
- riff_rchunk_get_end
- riff_rchunk_get_ndpos
- riff_rchunk_end
- riff_read
#include <assert.h>
#include <byteorder.h>
#include <errno.h>
#include <macros.h>
#include <riff/chunk.h>
#include <stdbool.h>
#include <stdlib.h>
errno_t riff_wopen(const char *fname, riffw_t **rrw)
{
riffw_t *rw;
rw = calloc(1, sizeof(riffw_t));
if (rw == NULL)
return ENOMEM;
rw->f = fopen(fname, "wb");
if (rw->f == NULL) {
free(rw);
return EIO;
}
*rrw = rw;
return EOK;
}
errno_t riff_wclose(riffw_t *rw)
{
int rv;
rv = fclose(rw->f);
free(rw);
return (rv == 0) ? EOK : EIO;
}
errno_t riff_write_uint32(riffw_t *rw, uint32_t v)
{
uint32_t vle;
vle = host2uint32_t_le(v);
if (fwrite(&vle, 1, sizeof(vle), rw->f) < sizeof(vle))
return EIO;
return EOK;
}
errno_t riff_wchunk_start(riffw_t *rw, riff_ckid_t ckid, riff_wchunk_t *wchunk)
{
long pos;
errno_t rc;
pos = ftell(rw->f);
if (pos < 0)
return EIO;
wchunk->ckstart = pos + 2 * sizeof(uint32_t);
rc = riff_write_uint32(rw, ckid);
if (rc != EOK) {
assert(rc == EIO);
return EIO;
}
rc = riff_write_uint32(rw, 0);
if (rc != EOK) {
assert(rc == EIO);
return EIO;
}
return EOK;
}
errno_t riff_wchunk_end(riffw_t *rw, riff_wchunk_t *wchunk)
{
long pos;
long cksize;
uint8_t pad;
size_t nw;
errno_t rc;
pos = ftell(rw->f);
if (pos < 0)
return EIO;
cksize = pos - wchunk->ckstart;
if (pos % 2 != 0) {
++pos;
pad = 0;
nw = fwrite(&pad, 1, sizeof(pad), rw->f);
if (nw != sizeof(pad))
return EIO;
}
if (fseek(rw->f, wchunk->ckstart - 4, SEEK_SET) < 0)
return EIO;
rc = riff_write_uint32(rw, cksize);
if (rc != EOK) {
assert(rc == EIO);
return EIO;
}
if (fseek(rw->f, pos, SEEK_SET) < 0)
return EIO;
return EOK;
}
errno_t riff_write(riffw_t *rw, void *data, size_t bytes)
{
size_t nw;
nw = fwrite(data, 1, bytes, rw->f);
if (nw != bytes)
return EIO;
return EOK;
}
errno_t riff_ropen(const char *fname, riff_rchunk_t *riffck, riffr_t **rrr)
{
riffr_t *rr;
riff_rchunk_t fchunk;
long fsize;
errno_t rc;
int rv;
rr = calloc(1, sizeof(riffr_t));
if (rr == NULL) {
rc = ENOMEM;
goto error;
}
rr->pos = 0;
rr->f = fopen(fname, "rb");
if (rr->f == NULL) {
rc = EIO;
goto error;
}
rv = fseek(rr->f, 0, SEEK_END);
if (rv < 0) {
rc = EIO;
goto error;
}
fsize = ftell(rr->f);
if (fsize < 0) {
rc = EIO;
goto error;
}
rv = fseek(rr->f, 0, SEEK_SET);
if (rv < 0) {
rc = EIO;
goto error;
}
fchunk.riffr = rr;
fchunk.ckstart = 0;
fchunk.cksize = fsize;
rc = riff_rchunk_start(&fchunk, riffck);
if (rc != EOK)
goto error;
*rrr = rr;
return EOK;
error:
if (rr != NULL && rr->f != NULL)
fclose(rr->f);
free(rr);
return rc;
}
errno_t riff_rclose(riffr_t *rr)
{
errno_t rc;
rc = fclose(rr->f);
free(rr);
return rc == 0 ? EOK : EIO;
}
errno_t riff_read_uint32(riff_rchunk_t *rchunk, uint32_t *v)
{
uint32_t vle;
errno_t rc;
size_t nread;
rc = riff_read(rchunk, &vle, sizeof(vle), &nread);
if (rc != EOK)
return rc;
if (nread != sizeof(vle))
return ELIMIT;
*v = uint32_t_le2host(vle);
return EOK;
}
errno_t riff_rchunk_start(riff_rchunk_t *parent, riff_rchunk_t *rchunk)
{
errno_t rc;
rchunk->riffr = parent->riffr;
rchunk->ckstart = parent->riffr->pos + 8;
rc = riff_read_uint32(parent, &rchunk->ckid);
if (rc != EOK)
goto error;
rc = riff_read_uint32(parent, &rchunk->cksize);
if (rc != EOK)
goto error;
return EOK;
error:
return rc;
}
errno_t riff_rchunk_match(riff_rchunk_t *parent, riff_ckid_t ckid,
riff_rchunk_t *rchunk)
{
errno_t rc;
while (true) {
rc = riff_rchunk_start(parent, rchunk);
if (rc == ELIMIT)
return ENOENT;
if (rc != EOK)
return rc;
if (rchunk->ckid == ckid)
break;
rc = riff_rchunk_end(rchunk);
if (rc != EOK)
return rc;
}
return EOK;
}
errno_t riff_rchunk_list_match(riff_rchunk_t *parent, riff_ltype_t ltype,
riff_rchunk_t *rchunk)
{
errno_t rc;
riff_ltype_t rltype;
while (true) {
rc = riff_rchunk_match(parent, CKID_LIST, rchunk);
if (rc == ELIMIT)
return ENOENT;
if (rc != EOK)
return rc;
rc = riff_read_uint32(parent, &rltype);
if (rc != EOK)
return rc;
if (rltype == ltype)
break;
rc = riff_rchunk_end(rchunk);
if (rc != EOK)
return rc;
}
return EOK;
}
errno_t riff_rchunk_seek(riff_rchunk_t *rchunk, long offset, int whence)
{
long dest;
int rv;
switch (whence) {
case SEEK_SET:
dest = rchunk->ckstart + offset;
break;
case SEEK_END:
dest = rchunk->ckstart + rchunk->cksize + offset;
break;
case SEEK_CUR:
dest = rchunk->riffr->pos + offset;
break;
default:
return EINVAL;
}
if (dest < rchunk->ckstart || (unsigned long) dest >
(unsigned long) rchunk->ckstart + rchunk->cksize) {
return ELIMIT;
}
rv = fseek(rchunk->riffr->f, dest, SEEK_SET);
if (rv < 0)
return EIO;
rchunk->riffr->pos = dest;
return EOK;
}
uint32_t riff_rchunk_size(riff_rchunk_t *rchunk)
{
return rchunk->cksize;
}
static long riff_rchunk_get_end(riff_rchunk_t *rchunk)
{
return rchunk->ckstart + rchunk->cksize;
}
static long riff_rchunk_get_ndpos(riff_rchunk_t *rchunk)
{
long ckend;
ckend = riff_rchunk_get_end(rchunk);
if ((ckend % 2) != 0)
return ckend + 1;
else
return ckend;
}
errno_t riff_rchunk_end(riff_rchunk_t *rchunk)
{
long ckend;
uint8_t byte;
size_t nread;
ckend = riff_rchunk_get_ndpos(rchunk);
if (rchunk->riffr->pos < ckend &&
ckend <= rchunk->riffr->pos + 512) {
while (rchunk->riffr->pos < ckend) {
nread = fread(&byte, 1, sizeof(byte), rchunk->riffr->f);
if (nread != sizeof(byte))
return EIO;
rchunk->riffr->pos += sizeof(byte);
}
} else if (rchunk->riffr->pos != ckend) {
if (fseek(rchunk->riffr->f, ckend, SEEK_SET) < 0)
return EIO;
rchunk->riffr->pos = ckend;
}
return EOK;
}
errno_t riff_read(riff_rchunk_t *rchunk, void *buf, size_t bytes,
size_t *nread)
{
long pos;
long ckend;
long toread;
pos = rchunk->riffr->pos;
ckend = riff_rchunk_get_end(rchunk);
if (pos < rchunk->ckstart || pos > ckend)
return ELIMIT;
toread = min(bytes, (size_t)(ckend - pos));
if (toread == 0) {
*nread = 0;
return EOK;
}
*nread = fread(buf, 1, toread, rchunk->riffr->f);
if (*nread == 0)
return EIO;
rchunk->riffr->pos += *nread;
return EOK;
}
HelenOS homepage, sources at GitHub