From a744f8136b12a879fec4cd554d67f9b4d9cf4069 Mon Sep 17 00:00:00 2001 From: Lutz Mueller Date: Tue, 22 Sep 2009 08:11:36 +0200 Subject: [PATCH] pnm: Handle ASCII encoded PNM data that is split over multiple buffers Also: - unref buffers after gst_buffer_span - fix scanning of header if header data is split over several buffers Fixes bug #595700. --- gst/pnm/gstpnmdec.c | 59 ++++++++++++++++++++++++++++++++++--------- gst/pnm/gstpnmdec.h | 2 +- gst/pnm/gstpnmutils.c | 6 ++--- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/gst/pnm/gstpnmdec.c b/gst/pnm/gstpnmdec.c index 0d7cc3c1fc..73a27345d7 100644 --- a/gst/pnm/gstpnmdec.c +++ b/gst/pnm/gstpnmdec.c @@ -95,6 +95,7 @@ static GstFlowReturn gst_pnmdec_chain_raw (GstPnmdec * s, GstPad * src, GstBuffer * buf) { GstFlowReturn r = GST_FLOW_OK; + GstBuffer *out; /* If we got the whole image, just push the buffer. */ if (GST_BUFFER_SIZE (buf) == s->size) { @@ -108,10 +109,11 @@ gst_pnmdec_chain_raw (GstPnmdec * s, GstPad * src, GstBuffer * buf) if (!s->buf) { s->buf = buf; } else { - buf = gst_buffer_span (s->buf, 0, buf, + out = gst_buffer_span (s->buf, 0, buf, GST_BUFFER_SIZE (s->buf) + GST_BUFFER_SIZE (buf)); + gst_buffer_unref (buf); gst_buffer_unref (s->buf); - s->buf = buf; + s->buf = out; } if (!s->buf) return GST_FLOW_ERROR; @@ -132,16 +134,46 @@ static GstFlowReturn gst_pnmdec_chain_ascii (GstPnmdec * s, GstPad * src, GstBuffer * buf) { GScanner *scanner; - GstBuffer *out = gst_buffer_new_and_alloc (s->size); + GstBuffer *out; guint i = 0; + gchar *b = (gchar *) GST_BUFFER_DATA (buf); + guint bs = GST_BUFFER_SIZE (buf); + guint target = s->size - (s->buf ? GST_BUFFER_SIZE (s->buf) : 0); + + if (!bs) { + gst_buffer_unref (buf); + return GST_FLOW_OK; + } + + if (s->last_byte) { + while (*b >= '0' && *b <= '9') { + s->last_byte = 10 * s->last_byte + *b - '0'; + b++; + if (!--bs) { + gst_buffer_unref (buf); + return GST_FLOW_OK; + } + } + if (s->last_byte > 255) { + gst_buffer_unref (buf); + GST_DEBUG_OBJECT (s, "Corrupt ASCII encoded PNM file."); + return GST_FLOW_ERROR; + } + } + + out = gst_buffer_new_and_alloc (target); + + if (s->last_byte) { + GST_BUFFER_DATA (out)[i++] = s->last_byte; + s->last_byte = 0; + } scanner = g_scanner_new (NULL); - g_scanner_input_text (scanner, (gchar *) GST_BUFFER_DATA (buf), - GST_BUFFER_SIZE (buf)); + g_scanner_input_text (scanner, b, bs); while (!g_scanner_eof (scanner)) { switch (g_scanner_get_next_token (scanner)) { case G_TOKEN_INT: - if (i == s->size) { + if (i == target) { GST_DEBUG_OBJECT (s, "PNM file contains too much data."); gst_buffer_unref (buf); gst_buffer_unref (out); @@ -154,15 +186,18 @@ gst_pnmdec_chain_ascii (GstPnmdec * s, GstPad * src, GstBuffer * buf) } } g_scanner_destroy (scanner); - gst_buffer_unref (buf); - if (i < s->size) { - GST_DEBUG_OBJECT (s, "FIXME: Decoding of ASCII encoded files split " - "over several buffers is not implemented!"); + /* If we didn't get the whole image, handle the last byte with care. */ + if (i < target && b[bs - 1] > '0' && b[bs - 1] <= '9') + s->last_byte = GST_BUFFER_DATA (out)[--i]; + + gst_buffer_unref (buf); + if (!i) { gst_buffer_unref (out); - return GST_FLOW_ERROR; + return GST_FLOW_OK; } + GST_BUFFER_SIZE (out) = i; return gst_pnmdec_chain_raw (s, src, out); } @@ -175,7 +210,7 @@ gst_pnmdec_chain (GstPad * pad, GstBuffer * data) GstFlowReturn r = GST_FLOW_OK; guint offset = 0; - if (!(s->mngr.info.fields & GST_PNM_INFO_FIELDS_ALL)) { + if (s->mngr.info.fields != GST_PNM_INFO_FIELDS_ALL) { switch (gst_pnm_info_mngr_scan (&s->mngr, GST_BUFFER_DATA (data), GST_BUFFER_SIZE (data))) { case GST_PNM_INFO_MNGR_RESULT_FAILED: diff --git a/gst/pnm/gstpnmdec.h b/gst/pnm/gstpnmdec.h index 318ba25889..12a845381b 100644 --- a/gst/pnm/gstpnmdec.h +++ b/gst/pnm/gstpnmdec.h @@ -39,7 +39,7 @@ struct _GstPnmdec GstElement element; GstPnmInfoMngr mngr; - guint size; + guint size, last_byte; GstBuffer *buf; }; diff --git a/gst/pnm/gstpnmutils.c b/gst/pnm/gstpnmutils.c index 2773430a99..f87136d88b 100644 --- a/gst/pnm/gstpnmutils.c +++ b/gst/pnm/gstpnmutils.c @@ -134,6 +134,7 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf, case '\n': case '\t': case ' ': + mngr->info.fields |= GST_PNM_INFO_FIELDS_WIDTH; mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE; mngr->data_offset += i; return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); @@ -143,7 +144,6 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf, } mngr->info.width *= 10; mngr->info.width += buf[i++] - 0x030; - mngr->info.fields |= GST_PNM_INFO_FIELDS_WIDTH; mngr->data_offset += i; return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); case GST_PNM_INFO_MNGR_STATE_DATA_HEIGHT: @@ -152,6 +152,7 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf, case '\n': case '\t': case ' ': + mngr->info.fields |= GST_PNM_INFO_FIELDS_HEIGHT; mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE; mngr->data_offset += i; return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); @@ -161,7 +162,6 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf, } mngr->info.height *= 10; mngr->info.height += buf[i++] - 0x030; - mngr->info.fields |= GST_PNM_INFO_FIELDS_HEIGHT; mngr->data_offset += i; return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); case GST_PNM_INFO_MNGR_STATE_DATA_MAX: @@ -170,6 +170,7 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf, case '\n': case '\t': case ' ': + mngr->info.fields |= GST_PNM_INFO_FIELDS_MAX; mngr->data_offset += i + 1; return GST_PNM_INFO_MNGR_RESULT_FINISHED; default: @@ -178,7 +179,6 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf, } mngr->info.max *= 10; mngr->info.max += buf[i++] - 0x030; - mngr->info.fields |= GST_PNM_INFO_FIELDS_MAX; mngr->data_offset += i; return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); }