From d9c71be69a0391cfe05f91c63c76f5134b121818 Mon Sep 17 00:00:00 2001 From: Tilman Sauerbeck Date: Thu, 17 Aug 2006 17:24:13 +0200 Subject: [PATCH] Reworked error handling. vcedit functions now return an error code instead of setting lasterror. Ogg::Vorbis::Tagger turns these error codes into their own exception classes. --- ext/ext.c | 51 +++++++++++++++++++++++++----------- ext/vcedit.c | 73 +++++++++++++++++++++------------------------------- ext/vcedit.h | 13 +++++++--- 3 files changed, 76 insertions(+), 61 deletions(-) diff --git a/ext/ext.c b/ext/ext.c index 9c433f2..67fa6b1 100644 --- a/ext/ext.c +++ b/ext/ext.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "vcedit.h" #include "comments.h" @@ -31,7 +32,8 @@ typedef struct { static VALUE c_close (VALUE self); -static VALUE cComments, eVTError; +static VALUE cComments, eVT, eOpen, eInvalidData, eInvalidComment, + eTempFile, eReopen; static ID id_length; static void @@ -100,17 +102,23 @@ c_init (VALUE self, VALUE filename) o->state = vcedit_state_new (StringValuePtr (filename)); if (!o->state) - rb_raise (eVTError, "vcedit_new_state() failed - %s", - vcedit_error (o->state)); - - if (vcedit_open (o->state) < 0) - rb_raise (eVTError, "vcedit_open() failed - %s", - vcedit_error (o->state)); + rb_raise (rb_eNoMemError, "Out of Memory"); + + switch (vcedit_open (o->state)) { + case VCEDIT_ERR_OPEN: + rb_raise (eOpen, "Cannot open file"); + case VCEDIT_ERR_INVAL: + rb_raise (eInvalidData, "Invalid data"); + default: + break; + } vc = vcedit_comments (o->state); - if (!vc) - rb_raise (eVTError, "vcedit_comments() failed - %s", - vcedit_error (o->state)); + + /* vcedit_open() succeeded, so vcedit_comments() cannot + * return NULL. + */ + assert (vc); /* check whether all comments are well-formed */ for (i = 0; i < vc->comments; i++) { @@ -118,7 +126,7 @@ c_init (VALUE self, VALUE filename) ptr = strchr (content, '='); if (!ptr || ptr == content) - rb_raise (eVTError, "malformed comment - %s", content); + rb_raise (eInvalidComment, "invalid comment - %s", content); } o->comments = rb_class_new_instance (0, NULL, cComments); @@ -163,9 +171,16 @@ c_write (VALUE self) comments_sync (o->comments, o->state); - if (vcedit_write (o->state) < 0) - rb_raise (rb_eIOError, "write failed - %s", - vcedit_error (o->state)); + switch (vcedit_write (o->state)) { + case VCEDIT_ERR_INVAL: + rb_raise (eInvalidData, "Invalid data"); + case VCEDIT_ERR_TMPFILE: + rb_raise (eTempFile, "Cannot create temporary file"); + case VCEDIT_ERR_REOPEN: + rb_raise (eReopen, "Cannot reopen file"); + default: + break; + } return rb_funcall (o->comments, id_length, 0); } @@ -209,7 +224,13 @@ Init_vorbistagger_ext (void) rb_define_method (cVT, "write", c_write, 0); rb_define_method (cVT, "comments", c_comments, 0); - eVTError = rb_define_class_under (cVT, "TaggerError", eVorbis); + eVT = rb_define_class_under (cVT, "TaggerError", eVorbis); + eOpen = rb_define_class_under (cVT, "OpenError", eVT); + eInvalidData = rb_define_class_under (cVT, "InvalidDataError", eVT); + eInvalidComment = rb_define_class_under (cVT, "InvalidCommentError", + eInvalidData); + eTempFile = rb_define_class_under (cVT, "TempFileError", eVT); + eReopen = rb_define_class_under (cVT, "ReopenError", eVT); id_length = rb_intern ("length"); diff --git a/ext/vcedit.c b/ext/vcedit.c index 1074670..22a8271 100644 --- a/ext/vcedit.c +++ b/ext/vcedit.c @@ -43,12 +43,12 @@ struct vcedit_state_St { char filename[PATH_MAX]; 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; @@ -120,16 +120,10 @@ vcedit_state_new (const char *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 @@ -153,6 +147,7 @@ vcedit_clear_internals (vcedit_state *state) state->booklen = 0; state->serial = 0; + state->opened = false; } void @@ -278,9 +273,10 @@ _fetch_next_packet (vcedit_state *s, ogg_packet *p, ogg_page *page) return _fetch_next_packet (s, p, page); } -int +vcedit_error vcedit_open (vcedit_state *state) { + vcedit_error ret; char *buffer; int bytes, i; int chunks = 0; @@ -289,10 +285,8 @@ vcedit_open (vcedit_state *state) ogg_page og; 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); @@ -307,10 +301,7 @@ vcedit_open (vcedit_state *state) /* 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."; + ret = VCEDIT_ERR_INVAL; goto err; } @@ -323,17 +314,17 @@ vcedit_open (vcedit_state *state) vorbis_comment_init (state->vc); if (ogg_stream_pagein (state->os, &og) < 0) { - state->lasterror = "Error reading first page of Ogg bitstream."; + ret = VCEDIT_ERR_INVAL; goto err; } if (ogg_stream_packetout (state->os, &header_main) != 1) { - state->lasterror = "Error reading initial header packet."; + 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."; + ret = VCEDIT_ERR_INVAL; goto err; } @@ -361,7 +352,7 @@ vcedit_open (vcedit_state *state) break; if (result == -1) { - state->lasterror = "Corrupt secondary header."; + ret = VCEDIT_ERR_INVAL; goto err; } @@ -383,7 +374,7 @@ vcedit_open (vcedit_state *state) bytes = fread (buffer, 1, CHUNKSIZE, state->in); if (bytes == 0 && i < 2) { - state->lasterror = "EOF before end of vorbis headers."; + ret = VCEDIT_ERR_INVAL; goto err; } @@ -394,15 +385,17 @@ vcedit_open (vcedit_state *state) 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 +407,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; @@ -548,9 +540,7 @@ vcedit_write (vcedit_state *state) if (!result) break; - if (result < 0) - state->lasterror = "Corrupt or missing data, continuing..."; - else { + if (result >= 0) { /* Don't bother going through the rest, we can just * write the page out now */ @@ -593,14 +583,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; } diff --git a/ext/vcedit.h b/ext/vcedit.h index cdd7be5..c0f15dc 100644 --- a/ext/vcedit.h +++ b/ext/vcedit.h @@ -27,15 +27,22 @@ extern "C" { #include #include +typedef enum { + VCEDIT_ERR_SUCCESS = 0, + VCEDIT_ERR_OPEN, + VCEDIT_ERR_INVAL, + VCEDIT_ERR_TMPFILE, + VCEDIT_ERR_REOPEN +} vcedit_error; + typedef struct vcedit_state_St vcedit_state; vcedit_state *vcedit_state_new (const char *filename); void vcedit_state_ref (vcedit_state *state); void vcedit_state_unref (vcedit_state *state); vorbis_comment *vcedit_comments (vcedit_state *state); -int vcedit_open (vcedit_state *state); -int vcedit_write (vcedit_state *state); -const char *vcedit_error (vcedit_state *state); +vcedit_error vcedit_open (vcedit_state *state); +vcedit_error vcedit_write (vcedit_state *state); #ifdef __cplusplus } -- 2.30.2