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 * load image decoder.
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 "imageviewer.h"
24#include "image_decoder.h"
25
26static const char *decoder_names[MAX_IMAGE_TYPES] = {
27 "bmp",
28 "jpeg", // Default decoder for jpeg: Use jpeg for old decoder, jpegp for new
29 "png",
30#ifdef HAVE_LCD_COLOR
31 "ppm",
32#endif
33 "gif",
34 "jpegp",
35};
36
37/* Check file type by magic number or file extension
38 *
39 * If the file contains magic number, use it to determine image type.
40 * Otherwise use file extension to determine image type.
41 * If the file contains magic number and file extension is not correct,
42 * informs user that something is wrong.
43 */
44enum image_type get_image_type(const char *name, bool quiet)
45{
46 static const struct {
47 char *ext;
48 enum image_type type;
49 } ext_list[] = {
50 { ".bmp", IMAGE_BMP },
51 { ".jpg", IMAGE_JPEG },
52 { ".jpe", IMAGE_JPEG },
53 { ".jpeg", IMAGE_JPEG },
54 { ".png", IMAGE_PNG },
55#ifdef HAVE_LCD_COLOR
56 { ".ppm", IMAGE_PPM },
57#endif
58 { ".gif", IMAGE_GIF },
59 };
60 static const struct {
61 char *magic; /* magic number */
62 int length; /* length of the magic number */
63 enum image_type type;
64 } magic_list[] = {
65 { "BM", 2, IMAGE_BMP },
66 { "\xff\xd8\xff\xe0", 4, IMAGE_JPEG },
67 { "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8, IMAGE_PNG },
68#ifdef HAVE_LCD_COLOR
69 { "P3", 2, IMAGE_PPM },
70 { "P6", 2, IMAGE_PPM },
71#endif
72 { "GIF87a", 6, IMAGE_GIF },
73 { "GIF89a", 6, IMAGE_GIF },
74 };
75
76 enum image_type type = IMAGE_UNKNOWN;
77 const char *ext = rb->strrchr(name, '.');
78 int i, fd;
79 char buf[12];
80
81 /* check file extention */
82 if (ext)
83 {
84 for (i = 0; i < (int)ARRAYLEN(ext_list); i++)
85 {
86 if (!rb->strcasecmp(ext, ext_list[i].ext))
87 {
88 type = ext_list[i].type;
89 break;
90 }
91 }
92 }
93
94 /* check magic value in the file */
95 fd = rb->open(name, O_RDONLY);
96 if (fd >= 0)
97 {
98 rb->memset(buf, 0, sizeof buf);
99 rb->read(fd, buf, sizeof buf);
100 rb->close(fd);
101 for (i = 0; i < (int)ARRAYLEN(magic_list); i++)
102 {
103 if (!rb->memcmp(buf, magic_list[i].magic, magic_list[i].length))
104 {
105 if (!quiet && type != magic_list[i].type)
106 {
107 /* file extension is wrong. */
108 rb->splashf(HZ*1, "Note: File extension is not correct");
109 }
110 type = magic_list[i].type;
111 break;
112 }
113 }
114 }
115 return type;
116}
117
118static void *decoder_handle = NULL;
119const struct image_decoder *load_decoder(struct loader_info *loader_info)
120{
121 const char *name;
122 char filename[MAX_PATH];
123 struct imgdec_header *hdr;
124 struct lc_header *lc_hdr;
125
126 if (loader_info->type < 0 || loader_info->type >= MAX_IMAGE_TYPES)
127 {
128 rb->splashf(2*HZ, "Unknown type: %d", loader_info->type);
129 goto error;
130 }
131
132 release_decoder();
133
134 name = decoder_names[loader_info->type];
135 rb->snprintf(filename, MAX_PATH, VIEWERS_DIR "/%s.ovl", name);
136
137 /* load decoder to the buffer. */
138 decoder_handle = rb->lc_open(filename, loader_info->buffer, loader_info->size);
139 if (!decoder_handle)
140 {
141 rb->splashf(2*HZ, "Can't open %s", filename);
142 goto error;
143 }
144
145 hdr = rb->lc_get_header(decoder_handle);
146 if (!hdr)
147 {
148 rb->splash(2*HZ, "Can't get header");
149 goto error_close;
150 }
151 lc_hdr = &hdr->lc_hdr;
152
153 if (lc_hdr->magic != PLUGIN_MAGIC || lc_hdr->target_id != TARGET_ID)
154 {
155 rb->splashf(2*HZ, "%s decoder: Incompatible model.", name);
156 goto error_close;
157 }
158
159 if (lc_hdr->api_version != IMGDEC_API_VERSION ||
160 hdr->img_api_size > sizeof(struct imgdec_api) ||
161 hdr->plugin_api_version != PLUGIN_API_VERSION ||
162 hdr->plugin_api_size > sizeof(struct plugin_api))
163 {
164 rb->splashf(2*HZ, "%s decoder: Incompatible version.", name);
165 goto error_close;
166 }
167
168 *(hdr->api) = rb;
169 *(hdr->img_api) = loader_info->iv;
170
171 /* set remaining buffer size to loader_info. decoder will
172 * be loaded to the end of the buffer, so fix size only. */
173#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
174 loader_info->size = lc_hdr->load_addr - loader_info->buffer;
175#endif
176
177 return hdr->decoder;
178
179error_close:
180 release_decoder();
181error:
182 return NULL;
183}
184
185void release_decoder(void)
186{
187 if (decoder_handle != NULL)
188 {
189 rb->lc_close(decoder_handle);
190 decoder_handle = NULL;
191 }
192}