• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * PNM image parser
3  * Copyright (c) 2002, 2003 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "libavutil/avassert.h"
23 #include "libavutil/imgutils.h"
24 
25 #include "parser.h" //for ParseContext
26 #include "pnm.h"
27 
28 typedef struct PNMParseContext {
29     ParseContext pc;
30     int remaining_bytes;
31     int ascii_scan;
32 }PNMParseContext;
33 
pnm_parse(AVCodecParserContext * s,AVCodecContext * avctx,const uint8_t ** poutbuf,int * poutbuf_size,const uint8_t * buf,int buf_size)34 static int pnm_parse(AVCodecParserContext *s, AVCodecContext *avctx,
35                      const uint8_t **poutbuf, int *poutbuf_size,
36                      const uint8_t *buf, int buf_size)
37 {
38     PNMParseContext *pnmpc = s->priv_data;
39     ParseContext *pc = &pnmpc->pc;
40     PNMContext pnmctx;
41     int next = END_NOT_FOUND;
42     int skip = 0;
43 
44     if (pc->overread > 0) {
45         memmove(pc->buffer + pc->index, pc->buffer + pc->overread_index, pc->overread);
46         pc->index          += pc->overread;
47         pc->overread_index += pc->overread;
48         pc->overread = 0;
49     }
50 
51     if (pnmpc->remaining_bytes) {
52         int inc = FFMIN(pnmpc->remaining_bytes, buf_size);
53         skip += inc;
54         pnmpc->remaining_bytes -= inc;
55 
56         if (!pnmpc->remaining_bytes)
57             next = skip;
58         goto end;
59     }
60 
61 retry:
62     if (pc->index) {
63         pnmctx.bytestream_start =
64         pnmctx.bytestream       = pc->buffer;
65         pnmctx.bytestream_end   = pc->buffer + pc->index;
66     } else {
67         pnmctx.bytestream_start =
68         pnmctx.bytestream       = (uint8_t *) buf + skip; /* casts avoid warnings */
69         pnmctx.bytestream_end   = (uint8_t *) buf + buf_size - skip;
70     }
71     if (ff_pnm_decode_header(avctx, &pnmctx) < 0) {
72         if (pnmctx.bytestream < pnmctx.bytestream_end) {
73             if (pc->index) {
74                 pc->index = 0;
75                 pnmpc->ascii_scan = 0;
76             } else {
77                 unsigned step = FFMAX(1, pnmctx.bytestream - pnmctx.bytestream_start);
78 
79                 skip += step;
80             }
81             goto retry;
82         }
83     } else if (pnmctx.type < 4) {
84               uint8_t *bs  = pnmctx.bytestream;
85         const uint8_t *end = pnmctx.bytestream_end;
86         uint8_t *sync      = bs;
87 
88         if (pc->index) {
89             av_assert0(pnmpc->ascii_scan <= end - bs);
90             bs += pnmpc->ascii_scan;
91         }
92 
93         while (bs < end) {
94             int c;
95             sync = bs;
96             c = *bs++;
97             if (c == '#')  {
98                 uint8_t *match = memchr(bs, '\n', end-bs);
99                 if (match)
100                     bs = match + 1;
101                 else
102                     break;
103             } else if (c == 'P') {
104                 next = bs - pnmctx.bytestream_start + skip - 1;
105                 pnmpc->ascii_scan = 0;
106                 break;
107             }
108         }
109         if (next == END_NOT_FOUND)
110             pnmpc->ascii_scan = sync - pnmctx.bytestream + skip;
111     } else {
112         int ret = av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1);
113         next = pnmctx.bytestream - pnmctx.bytestream_start + skip;
114         if (ret >= 0 && next + (uint64_t)ret <= INT_MAX)
115             next += ret;
116     }
117     if (next != END_NOT_FOUND && pnmctx.bytestream_start != buf + skip)
118         next -= pc->index;
119     if (next > buf_size) {
120         pnmpc->remaining_bytes = next - buf_size;
121         next = END_NOT_FOUND;
122     }
123 end:
124     if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
125         *poutbuf      = NULL;
126         *poutbuf_size = 0;
127         return buf_size;
128     }
129     *poutbuf      = buf;
130     *poutbuf_size = buf_size;
131     return next;
132 }
133 
134 AVCodecParser ff_pnm_parser = {
135     .codec_ids      = { AV_CODEC_ID_PGM, AV_CODEC_ID_PGMYUV, AV_CODEC_ID_PPM,
136                         AV_CODEC_ID_PBM, AV_CODEC_ID_PAM },
137     .priv_data_size = sizeof(PNMParseContext),
138     .parser_parse   = pnm_parse,
139     .parser_close   = ff_parse_close,
140 };
141