#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
#include <ogg/ogg.h>
#include <vorbis/codec.h>
+#include <assert.h>
#include "vcedit.h"
#define CHUNKSIZE 4096
+static int vcedit_open (vcedit_state *state);
+
struct vcedit_state_St {
int refcount;
vorbis_comment *vc;
vorbis_info *vi;
- vcedit_read_func read;
- vcedit_write_func write;
+ char filename[PATH_MAX];
- void *in;
+ FILE *in;
long serial;
unsigned char *mainbuf;
unsigned char *bookbuf;
};
vcedit_state *
-vcedit_state_new (void)
+vcedit_state_new (const char *filename)
{
vcedit_state *state;
state->refcount = 1;
+ snprintf (state->filename, sizeof (state->filename),
+ "%s", filename);
+
+ state->in = fopen (state->filename, "rb");
+
+ if (vcedit_open (state) < 0) {
+ free (state);
+ return NULL;
+ }
+
return state;
}
static void
vcedit_clear_internals (vcedit_state *state)
{
- const char *tmp;
-
if (state->vc) {
vorbis_comment_clear (state->vc);
free (state->vc);
+ state->vc = NULL;
}
if (state->os) {
ogg_stream_clear (state->os);
free (state->os);
+ state->os = NULL;
}
if (state->oy) {
ogg_sync_clear (state->oy);
free (state->oy);
+ state->oy = NULL;
}
free (state->vendor);
+ state->vendor = NULL;
+
free (state->mainbuf);
+ state->mainbuf = NULL;
+ state->mainlen = 0;
+
free (state->bookbuf);
+ state->bookbuf = NULL;
+ state->booklen = 0;
- if (state->vi) {
+ if (state->vi) {
vorbis_info_clear (state->vi);
- free (state->vi);
- }
+ free (state->vi);
+ state->vi = NULL;
+ }
- tmp = state->lasterror;
- memset (state, 0, sizeof (vcedit_state));
- state->lasterror = tmp;
+ state->serial = 0;
+ state->prevW = state->extrapage = state->eosin = 0;
}
void
state->refcount--;
if (!state->refcount) {
+ fclose (state->in);
vcedit_clear_internals (state);
free (state);
}
while (ogg_sync_pageout (s->oy, page) <= 0) {
buffer = ogg_sync_buffer (s->oy, CHUNKSIZE);
- bytes = s->read (buffer, 1, CHUNKSIZE, s->in);
+ bytes = fread (buffer, 1, CHUNKSIZE, s->in);
ogg_sync_wrote (s->oy, bytes);
if (!bytes)
return _fetch_next_packet (s, p, page);
}
-int
-vcedit_open_callbacks (vcedit_state *state, void *in,
- vcedit_read_func read_func,
- vcedit_write_func write_func)
+static int
+vcedit_open (vcedit_state *state)
{
char *buffer;
int bytes, i;
ogg_packet header_main, header_comments, header_codebooks;
ogg_page og;
- state->in = in;
- state->read = read_func;
- state->write = write_func;
-
state->oy = malloc (sizeof (ogg_sync_state));
ogg_sync_init (state->oy);
while (1) {
buffer = ogg_sync_buffer (state->oy, CHUNKSIZE);
- bytes = state->read (buffer, 1, CHUNKSIZE, state->in);
+ bytes = fread (buffer, 1, CHUNKSIZE, state->in);
ogg_sync_wrote (state->oy, bytes);
}
buffer = ogg_sync_buffer (state->oy, CHUNKSIZE);
- bytes = state->read (buffer, 1, CHUNKSIZE, state->in);
+ bytes = fread (buffer, 1, CHUNKSIZE, state->in);
if (bytes == 0 && i < 2) {
state->lasterror = "EOF before end of vorbis headers.";
}
int
-vcedit_write (vcedit_state *state, void *out)
+vcedit_write (vcedit_state *state)
{
ogg_stream_state streamout;
ogg_packet header_main, header_comments, header_codebooks, op;
ogg_page ogout, ogin;
ogg_int64_t granpos = 0;
- int result, bytes, needflush = 0, needout = 0;
- char *buffer;
+ FILE *out;
+ char *buffer, tmpfile[PATH_MAX];
+ int s, result, bytes, needflush = 0, needout = 0;
size_t tmp;
+ strcpy (tmpfile, state->filename);
+ strcat (tmpfile, ".XXXXXX");
+
+ s = mkstemp (tmpfile);
+ if (s == -1) {
+ state->lasterror = "Error writing stream to output. "
+ "Cannot open temporary file.";
+ return -1;
+ }
+
+ out = fdopen (s, "wb");
+ if (!out) {
+ unlink (tmpfile);
+ close (s);
+ state->lasterror = "Error writing stream to output. "
+ "Cannot open temporary file.";
+ return -1;
+ }
+
state->eosin = 0;
state->extrapage = 0;
ogg_stream_packetin (&streamout, &header_codebooks);
while ((result = ogg_stream_flush (&streamout, &ogout))) {
- tmp = state->write (ogout.header, 1, ogout.header_len, out);
+ tmp = fwrite (ogout.header, 1, ogout.header_len, out);
if (tmp != (size_t) ogout.header_len)
goto cleanup;
- tmp = state->write (ogout.body, 1, ogout.body_len, out);
+ tmp = fwrite (ogout.body, 1, ogout.body_len, out);
if (tmp != (size_t) ogout.body_len)
goto cleanup;
}
if (needflush) {
if (ogg_stream_flush (&streamout, &ogout)) {
- tmp = state->write (ogout.header, 1, ogout.header_len, out);
+ tmp = fwrite (ogout.header, 1, ogout.header_len, out);
if (tmp != (size_t) ogout.header_len)
goto cleanup;
- tmp = state->write (ogout.body, 1, ogout.body_len, out);
+ tmp = fwrite (ogout.body, 1, ogout.body_len, out);
if (tmp != (size_t) ogout.body_len)
goto cleanup;
}
} else if (needout) {
if (ogg_stream_pageout (&streamout, &ogout)) {
- tmp = state->write (ogout.header, 1, ogout.header_len, out);
+ tmp = fwrite (ogout.header, 1, ogout.header_len, out);
if (tmp != (size_t) ogout.header_len)
goto cleanup;
- tmp = state->write (ogout.body, 1, ogout.body_len, out);
+ tmp = fwrite (ogout.body, 1, ogout.body_len, out);
if (tmp != (size_t) ogout.body_len)
goto cleanup;
}
streamout.e_o_s = 1;
while (ogg_stream_flush (&streamout, &ogout)) {
- tmp = state->write (ogout.header, 1, ogout.header_len, out);
+ tmp = fwrite (ogout.header, 1, ogout.header_len, out);
if (tmp != (size_t) ogout.header_len)
goto cleanup;
- tmp = state->write (ogout.body, 1, ogout.body_len, out);
+ tmp = fwrite (ogout.body, 1, ogout.body_len, out);
if (tmp != (size_t) ogout.body_len)
goto cleanup;
}
if (state->extrapage) {
- tmp = state->write (ogin.header, 1, ogin.header_len, out);
+ tmp = fwrite (ogin.header, 1, ogin.header_len, out);
if (tmp != (size_t) ogin.header_len)
goto cleanup;
- tmp = state->write (ogin.body, 1, ogin.body_len, out);
+ tmp = fwrite (ogin.body, 1, ogin.body_len, out);
if (tmp != (size_t) ogin.body_len)
goto cleanup;
}
/* Don't bother going through the rest, we can just
* write the page out now
*/
- tmp = state->write (ogout.header,1,ogout.header_len, out);
+ tmp = fwrite (ogout.header, 1, ogout.header_len, out);
if (tmp != (size_t) ogout.header_len)
goto cleanup;
- tmp = state->write (ogout.body,1,ogout.body_len, out);
+ tmp = fwrite (ogout.body, 1, ogout.body_len, out);
if (tmp != (size_t) ogout.body_len)
goto cleanup;
}
}
buffer = ogg_sync_buffer (state->oy, CHUNKSIZE);
- bytes = state->read (buffer, 1, CHUNKSIZE, state->in);
+ bytes = fread (buffer, 1, CHUNKSIZE, state->in);
ogg_sync_wrote (state->oy, bytes);
if (!bytes) {
}
}
+ fclose (out);
+ fclose (state->in);
+
+ unlink (state->filename);
+ rename (tmpfile, state->filename);
+
cleanup:
ogg_stream_clear (&streamout);
return -1;
}
+ vcedit_clear_internals (state);
+
+ state->in = fopen (state->filename, "rb");
+ vcedit_open (state);
+
return 0;
}