X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=ext%2Fvcedit.c;h=70eae0591af0e91ac5dee35e9858fb3aaa7e80cf;hb=e71087631ea69d4785be8da4a962d540bd25bcab;hp=10746706f71c97fbd0c620b4ca2d95f4d8d8be9b;hpb=bf1f7624bee5a466b402825083190d3afbd9c28b;p=ruby-vorbistagger.git diff --git a/ext/vcedit.c b/ext/vcedit.c index 1074670..70eae05 100644 --- a/ext/vcedit.c +++ b/ext/vcedit.c @@ -34,34 +34,30 @@ struct vcedit_state_St { int refcount; - ogg_sync_state *oy; - ogg_stream_state *os; + ogg_sync_state oy; + ogg_stream_state os; - vorbis_comment *vc; - vorbis_info *vi; - - char filename[PATH_MAX]; + vorbis_comment vc; + vorbis_info vi; FILE *in; + bool opened; long serial; unsigned char *mainbuf; unsigned char *bookbuf; int mainlen; int booklen; - const char *lasterror; char *vendor; int prevW; int extrapage; int eosin; + + char filename[0]; }; static void vcedit_state_free (vcedit_state *state) { - free (state->oy); - free (state->os); - free (state->vc); - free (state->vi); free (state->mainbuf); free (state->bookbuf); free (state->vendor); @@ -75,25 +71,11 @@ vcedit_state_free (vcedit_state *state) } static bool -vcedit_state_init (vcedit_state *state) +vcedit_state_init (vcedit_state *state, const char *filename) { state->refcount = 1; - state->oy = malloc (sizeof (ogg_sync_state)); - if (!state->oy) - return false; - - state->os = malloc (sizeof (ogg_stream_state)); - if (!state->os) - return false; - - state->vc = malloc (sizeof (vorbis_comment)); - if (!state->vc) - return false; - - state->vi = malloc (sizeof (vorbis_info)); - if (!state->vi) - return false; + strcpy (state->filename, filename); return true; } @@ -102,44 +84,40 @@ vcedit_state * vcedit_state_new (const char *filename) { vcedit_state *state; + size_t len; + + len = strlen (filename); + if (len > PATH_MAX) + return NULL; - state = malloc (sizeof (vcedit_state)); + state = malloc (sizeof (vcedit_state) + len + 1); if (!state) return NULL; memset (state, 0, sizeof (vcedit_state)); - if (!vcedit_state_init (state)) { + if (!vcedit_state_init (state, filename)) { vcedit_state_free (state); return NULL; } - snprintf (state->filename, sizeof (state->filename), - "%s", filename); - return state; } -const char * -vcedit_error (vcedit_state *state) -{ - return state->lasterror; -} - vorbis_comment * vcedit_comments (vcedit_state *state) { - return state->vc; + return state->opened ? &state->vc : NULL; } static void vcedit_clear_internals (vcedit_state *state) { - ogg_stream_clear (state->os); - ogg_sync_clear (state->oy); + ogg_stream_clear (&state->os); + ogg_sync_clear (&state->oy); - vorbis_info_clear (state->vi); - vorbis_comment_clear (state->vc); + vorbis_info_clear (&state->vi); + vorbis_comment_clear (&state->vc); free (state->vendor); state->vendor = NULL; @@ -153,6 +131,7 @@ vcedit_clear_internals (vcedit_state *state) state->booklen = 0; state->serial = 0; + state->opened = false; } void @@ -167,7 +146,9 @@ vcedit_state_unref (vcedit_state *state) if (--state->refcount) return; - vcedit_clear_internals (state); + if (state->opened) + vcedit_clear_internals (state); + vcedit_state_free (state); } @@ -177,9 +158,8 @@ vcedit_state_unref (vcedit_state *state) static void _v_writestring (oggpack_buffer *o, char *s, int len) { - while (len--) { + while (len--) oggpack_write (o, *s++, 8); - } } static int @@ -232,7 +212,7 @@ _blocksize (vcedit_state *s, ogg_packet *p) { int this, ret = 0; - this = vorbis_packet_blocksize (s->vi, p); + this = vorbis_packet_blocksize (&s->vi, p); if (s->prevW) ret = (this + s->prevW) / 4; @@ -248,20 +228,19 @@ _fetch_next_packet (vcedit_state *s, ogg_packet *p, ogg_page *page) char *buffer; int result, bytes; - result = ogg_stream_packetout (s->os, p); - - if (result > 0) + result = ogg_stream_packetout (&s->os, p); + if (result == 1) return 1; if (s->eosin) return 0; - while (ogg_sync_pageout (s->oy, page) <= 0) { - buffer = ogg_sync_buffer (s->oy, CHUNKSIZE); + while (ogg_sync_pageout (&s->oy, page) != 1) { + buffer = ogg_sync_buffer (&s->oy, CHUNKSIZE); bytes = fread (buffer, 1, CHUNKSIZE, s->in); - ogg_sync_wrote (s->oy, bytes); + ogg_sync_wrote (&s->oy, bytes); - if (!bytes) + if (!bytes && feof (s->in)) return 0; } @@ -273,67 +252,62 @@ _fetch_next_packet (vcedit_state *s, ogg_packet *p, ogg_page *page) return 0; } - ogg_stream_pagein (s->os, page); + ogg_stream_pagein (&s->os, page); return _fetch_next_packet (s, p, page); } -int +vcedit_error vcedit_open (vcedit_state *state) { - char *buffer; - int bytes, i; - int chunks = 0; + vcedit_error ret; ogg_packet *header; ogg_packet header_main, header_comments, header_codebooks; ogg_page og; + char *buffer; + size_t bytes, total = 0; + int i = 0; state->in = fopen (state->filename, "rb"); - if (!state->in) { - state->lasterror = "Cannot open file."; - return -1; - } + if (!state->in) + return VCEDIT_ERR_OPEN; - ogg_sync_init (state->oy); + ogg_sync_init (&state->oy); - while (1) { - buffer = ogg_sync_buffer (state->oy, CHUNKSIZE); - bytes = fread (buffer, 1, CHUNKSIZE, state->in); + do { + /* Bail if we don't find data in the first 40 kB */ + if (feof (state->in) || total >= (CHUNKSIZE * 10)) { + ogg_sync_clear (&state->oy); - ogg_sync_wrote (state->oy, bytes); + return VCEDIT_ERR_INVAL; + } - if (ogg_sync_pageout (state->oy, &og) == 1) - break; + buffer = ogg_sync_buffer (&state->oy, CHUNKSIZE); - /* Bail if we don't find data in the first 40 kB */ - if (chunks++ >= 10) { - if (bytes < CHUNKSIZE) - state->lasterror = "Input truncated or empty."; - else - state->lasterror = "Input is not an Ogg bitstream."; + bytes = fread (buffer, 1, CHUNKSIZE, state->in); + total += bytes; - goto err; - } - } + ogg_sync_wrote (&state->oy, bytes); + } while (ogg_sync_pageout (&state->oy, &og) != 1); state->serial = ogg_page_serialno (&og); - ogg_stream_init (state->os, state->serial); - vorbis_info_init (state->vi); - vorbis_comment_init (state->vc); + ogg_stream_init (&state->os, state->serial); + vorbis_info_init (&state->vi); + vorbis_comment_init (&state->vc); - if (ogg_stream_pagein (state->os, &og) < 0) { - state->lasterror = "Error reading first page of Ogg bitstream."; + if (ogg_stream_pagein (&state->os, &og) < 0) { + ret = VCEDIT_ERR_INVAL; goto err; } - if (ogg_stream_packetout (state->os, &header_main) != 1) { - state->lasterror = "Error reading initial header packet."; + if (ogg_stream_packetout (&state->os, &header_main) != 1) { + ret = VCEDIT_ERR_INVAL; goto err; } - if (vorbis_synthesis_headerin (state->vi, state->vc, &header_main) < 0) { - state->lasterror = "Ogg bitstream does not contain vorbis data."; + if (vorbis_synthesis_headerin (&state->vi, &state->vc, &header_main) < 0) { + ret = VCEDIT_ERR_INVAL; goto err; } @@ -341,68 +315,69 @@ vcedit_open (vcedit_state *state) state->mainbuf = malloc (state->mainlen); memcpy (state->mainbuf, header_main.packet, header_main.bytes); - i = 0; header = &header_comments; while (i < 2) { while (i < 2) { - int result = ogg_sync_pageout (state->oy, &og); + int result; + result = ogg_sync_pageout (&state->oy, &og); if (!result) break; /* Too little data so far */ - if (result == 1) { - ogg_stream_pagein (state->os, &og); - - while (i < 2) { - result = ogg_stream_packetout (state->os, header); + if (result != 1) + continue; - if (!result) - break; + ogg_stream_pagein (&state->os, &og); - if (result == -1) { - state->lasterror = "Corrupt secondary header."; - goto err; - } + while (i < 2) { + result = ogg_stream_packetout (&state->os, header); + if (!result) + break; - vorbis_synthesis_headerin (state->vi, state->vc, header); + if (result != 1) { + ret = VCEDIT_ERR_INVAL; + goto err; + } - if (i == 1) { - state->booklen = header->bytes; - state->bookbuf = malloc (state->booklen); - memcpy (state->bookbuf, header->packet, header->bytes); - } + vorbis_synthesis_headerin (&state->vi, &state->vc, header); - i++; - header = &header_codebooks; + if (i++ == 1) { + state->booklen = header->bytes; + state->bookbuf = malloc (state->booklen); + memcpy (state->bookbuf, header->packet, header->bytes); } + + header = &header_codebooks; } } - buffer = ogg_sync_buffer (state->oy, CHUNKSIZE); + buffer = ogg_sync_buffer (&state->oy, CHUNKSIZE); bytes = fread (buffer, 1, CHUNKSIZE, state->in); - if (bytes == 0 && i < 2) { - state->lasterror = "EOF before end of vorbis headers."; + if (!bytes && feof (state->in) && i < 2) { + ret = VCEDIT_ERR_INVAL; goto err; } - ogg_sync_wrote (state->oy, bytes); + ogg_sync_wrote (&state->oy, bytes); } /* Copy the vendor tag */ - state->vendor = strdup (state->vc->vendor); + state->vendor = strdup (state->vc.vendor); /* Headers are done! */ - return 0; + state->opened = true; + + return VCEDIT_ERR_SUCCESS; err: vcedit_clear_internals (state); - return -1; + return ret; } -int +vcedit_error vcedit_write (vcedit_state *state) { ogg_stream_state streamout; @@ -414,23 +389,22 @@ vcedit_write (vcedit_state *state) int s, result, bytes, needflush = 0, needout = 0; size_t tmp; + if (!state->opened) + return VCEDIT_ERR_INVAL; + 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; - } + if (s == -1) + return VCEDIT_ERR_TMPFILE; out = fdopen (s, "wb"); if (!out) { unlink (tmpfile); close (s); - state->lasterror = "Error writing stream to output. " - "Cannot open temporary file."; - return -1; + + return VCEDIT_ERR_TMPFILE; } state->prevW = state->extrapage = state->eosin = 0; @@ -449,7 +423,7 @@ vcedit_write (vcedit_state *state) ogg_stream_init (&streamout, state->serial); - _commentheader_out (state->vc, state->vendor, &header_comments); + _commentheader_out (&state->vc, state->vendor, &header_comments); ogg_stream_packetin (&streamout, &header_main); ogg_stream_packetin (&streamout, &header_comments); @@ -542,36 +516,27 @@ vcedit_write (vcedit_state *state) /* We copy the rest of the stream (other logical streams) * through, a page at a time. */ - while (1) { - result = ogg_sync_pageout (state->oy, &ogout); + while ((result = ogg_sync_pageout (&state->oy, &ogout))) { + if (result != 1) + continue; - if (!result) - break; - - if (result < 0) - state->lasterror = "Corrupt or missing data, continuing..."; - else { - /* Don't bother going through the rest, we can just - * write the page out now - */ - tmp = fwrite (ogout.header, 1, ogout.header_len, out); - if (tmp != (size_t) ogout.header_len) - goto cleanup; + /* Don't bother going through the rest, we can just + * write the page out now + */ + tmp = fwrite (ogout.header, 1, ogout.header_len, out); + if (tmp != (size_t) ogout.header_len) + goto cleanup; - tmp = fwrite (ogout.body, 1, ogout.body_len, out); - if (tmp != (size_t) ogout.body_len) - goto cleanup; - } + 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); + buffer = ogg_sync_buffer (&state->oy, CHUNKSIZE); bytes = fread (buffer, 1, CHUNKSIZE, state->in); - ogg_sync_wrote (state->oy, bytes); + ogg_sync_wrote (&state->oy, bytes); - if (!bytes) { - state->eosin = 1; - break; - } + state->eosin = !bytes && feof (state->in); } fclose (out); @@ -593,14 +558,11 @@ cleanup: state->mainbuf = state->bookbuf = NULL; - if (!state->eosin) { - state->lasterror = "Error writing stream to output. " - "Output stream may be corrupted or truncated."; - return -1; - } + if (!state->eosin) + return VCEDIT_ERR_INVAL; vcedit_clear_internals (state); - vcedit_open (state); - return 0; + return (vcedit_open (state) == VCEDIT_ERR_SUCCESS) ? + VCEDIT_ERR_SUCCESS : VCEDIT_ERR_REOPEN; }