A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/*****************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
5 * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 Alexander Papst
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "plugin.h"
23#include "lib/pluginlib_bmp.h"
24#include "ppm_decoder.h"
25#include "../imageviewer.h"
26
27static int ppm_read_magic_number(int fd)
28{
29 unsigned char i1, i2;
30 if(rb->read(fd, &i1, 1) < 1 || rb->read(fd, &i2, 1) < 1)
31 {
32 ppm_error( "Error reading magic number from ppm image stream. "\
33 "Most often, this means your input file is empty." );
34 return PLUGIN_ERROR;
35 }
36 return i1 * 256 + i2;
37}
38
39static int ppm_getc(int fd)
40{
41 unsigned char ch;
42
43 if (rb->read(fd, &ch, 1) < 1) {
44 ppm_error("EOF. Read error reading a byte");
45 return PLUGIN_ERROR;
46 }
47
48 if (ch == '#') {
49 do {
50 if (rb->read(fd, &ch, 1) < 1) {
51 ppm_error("EOF. Read error reading a byte");
52 return PLUGIN_ERROR;
53 }
54 } while (ch != '\n' && ch != '\r');
55 }
56 return (int)ch;
57}
58
59static int ppm_getuint(int fd)
60{
61 int ch;
62 int i;
63 int digitVal;
64
65 do {
66 ch = ppm_getc(fd);
67 } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
68
69 if (ch == PLUGIN_ERROR) return PLUGIN_ERROR;
70 if (ch < '0' || ch > '9') {
71 ppm_error("Junk (%c) in file where an integer should be.", ch);
72 return PLUGIN_ERROR;
73 }
74
75 i = 0;
76
77 do {
78 digitVal = ch - '0';
79
80 if (i > INT_MAX/10 - digitVal) {
81 ppm_error("ASCII decimal integer in file is "\
82 "too large to be processed.");
83 return PLUGIN_ERROR;
84 }
85
86 i = i * 10 + digitVal;
87 ch = ppm_getc(fd);
88
89 } while (ch >= '0' && ch <= '9');
90 if (ch == PLUGIN_ERROR) return PLUGIN_ERROR;
91
92 return i;
93}
94
95static int ppm_getrawbyte(int fd)
96{
97 unsigned char by;
98
99 if (rb->read(fd, &by, 1) < 1) {
100 ppm_error("EOF. Read error while reading a one-byte sample.");
101 return PLUGIN_ERROR;
102 }
103
104 return (int)by;
105}
106
107static int ppm_getrawsample(int fd, int const maxval)
108{
109 if (maxval < 256) {
110 /* The sample is just one byte. Read it. */
111 return(ppm_getrawbyte(fd));
112 } else {
113 /* The sample is two bytes. Read both. */
114 unsigned char byte_pair[2];
115
116 if (rb->read(fd, byte_pair, 2) < 2) {
117 ppm_error("EOF. Read error while reading a long sample.");
118 return PLUGIN_ERROR;
119 }
120 return((byte_pair[0]<<8) | byte_pair[1]);
121 }
122}
123
124/* Read from the file header dimensions as well as max
125 * int value used
126 */
127static int read_ppm_init_rest(int fd, struct ppm_info *ppm)
128{
129 /* Read size. */
130 ppm->x = ppm_getuint(fd);
131 ppm->y = ppm_getuint(fd);
132
133#ifdef HAVE_LCD_COLOR
134 ppm->native_img_size = ppm->x * ppm->y * FB_DATA_SZ;
135#endif
136
137 if (ppm->native_img_size > ppm->buf_size) {
138 return PLUGIN_OUTOFMEM;
139 }
140
141 /* Read maxval. */
142 ppm->maxval = ppm_getuint(fd);
143
144 if (ppm->maxval > PPM_OVERALLMAXVAL) {
145 ppm_error("maxval of input image (%u) is too large. "\
146 "The maximum allowed by the PPM is %u.",
147 ppm->maxval, PPM_OVERALLMAXVAL);
148 return PLUGIN_ERROR;
149 }
150 if (ppm->maxval == 0) {
151 ppm_error("maxval of input image is zero.");
152 return PLUGIN_ERROR;
153 }
154 return PLUGIN_OK;
155}
156
157static int read_ppm_init(int fd, struct ppm_info *ppm)
158{
159 /* Check magic number. */
160 ppm->format = ppm_read_magic_number( fd );
161
162 if (ppm->format == PLUGIN_ERROR) return PLUGIN_ERROR;
163 switch (ppm->format) {
164 case PPM_FORMAT:
165 case RPPM_FORMAT:
166 return read_ppm_init_rest(fd, ppm);
167
168 default:
169 ppm_error( "Bad magic number - not a ppm or rppm file." );
170 return PLUGIN_ERROR;
171 }
172 return PLUGIN_OK;
173}
174
175static int read_ppm_row(int fd, struct ppm_info *ppm, int row)
176{
177 int col;
178 int r, g, b;
179#ifdef HAVE_LCD_COLOR
180#if LCD_STRIDEFORMAT == VERTICAL_STRIDE
181 fb_data *dst = (fb_data *) ppm->buf + row;
182 const int stride = ppm->x;
183#else
184 fb_data *dst = (fb_data *) ppm->buf + ppm->x*row;
185 const int stride = 1;
186#endif
187#endif /* HAVE_LCD_COLOR */
188 switch (ppm->format) {
189 case PPM_FORMAT:
190 for (col = 0; col < ppm->x; ++col) {
191 r = ppm_getuint(fd);
192 g = ppm_getuint(fd);
193 b = ppm_getuint(fd);
194
195 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
196 b == PLUGIN_ERROR)
197 {
198 return PLUGIN_ERROR;
199 }
200 *dst = FB_RGBPACK(
201 (255 * r)/ppm->maxval,
202 (255 * g)/ppm->maxval,
203 (255 * b)/ppm->maxval);
204 dst += stride;
205 }
206 break;
207
208 case RPPM_FORMAT:
209 for (col = 0; col < ppm->x; ++col) {
210 r = ppm_getrawsample(fd, ppm->maxval);
211 g = ppm_getrawsample(fd, ppm->maxval);
212 b = ppm_getrawsample(fd, ppm->maxval);
213
214 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
215 b == PLUGIN_ERROR)
216 {
217 return PLUGIN_ERROR;
218 }
219 *dst = FB_RGBPACK(
220 (255 * r)/ppm->maxval,
221 (255 * g)/ppm->maxval,
222 (255 * b)/ppm->maxval);
223 dst += stride;
224 }
225 break;
226
227 default:
228 ppm_error("What?!");
229 return PLUGIN_ERROR;
230 }
231 return PLUGIN_OK;
232}
233
234/* public */
235int read_ppm(int fd, struct ppm_info *ppm)
236{
237 int row, ret;
238
239 ret = read_ppm_init(fd, ppm);
240 if(ret != PLUGIN_OK) {
241 return ret;
242 }
243
244 for (row = 0; row < ppm->y; ++row) {
245 ret = read_ppm_row(fd, ppm, row);
246 if(ret != PLUGIN_OK) {
247 return ret;
248 }
249 iv->cb_progress(row, ppm->y);
250 }
251 return PLUGIN_OK;
252}