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 by Maurus Cuelenaere
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 <stdio.h>
23#include <stdbool.h>
24#include <stdlib.h>
25#include <string.h>
26#include "creative.h"
27#include "hmac-sha1.h"
28/*
29 ---------------------------------------------------------------------------
30 Shamelessly taken from elf.h (for compatibility reasons included)
31 ---------------------------------------------------------------------------
32
33 This file defines standard ELF types, structures, and macros.
34 Copyright (C) 1995-2003,2004,2005,2006,2007 Free Software Foundation, Inc.
35 This file is part of the GNU C Library.
36
37 The GNU C Library is free software; you can redistribute it and/or
38 modify it under the terms of the GNU Lesser General Public
39 License as published by the Free Software Foundation; either
40 version 2.1 of the License, or (at your option) any later version.
41
42 The GNU C Library is distributed in the hope that it will be useful,
43 but WITHOUT ANY WARRANTY; without even the implied warranty of
44 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45 Lesser General Public License for more details.
46
47 You should have received a copy of the GNU Lesser General Public
48 License along with the GNU C Library; if not, write to the Free
49 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
50 02111-1307 USA.
51*/
52
53#include <stdint.h>
54
55/* Type for a 16-bit quantity. */
56typedef uint16_t Elf32_Half;
57
58/* Types for signed and unsigned 32-bit quantities. */
59typedef uint32_t Elf32_Word;
60typedef int32_t Elf32_Sword;
61
62/* Types for signed and unsigned 64-bit quantities. */
63typedef uint64_t Elf32_Xword;
64typedef int64_t Elf32_Sxword;
65
66/* Type of addresses. */
67typedef uint32_t Elf32_Addr;
68
69/* Type of file offsets. */
70typedef uint32_t Elf32_Off;
71
72/* Type for section indices, which are 16-bit quantities. */
73typedef uint16_t Elf32_Section;
74
75#define EI_NIDENT (16)
76
77typedef struct
78{
79 unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
80 Elf32_Half e_type; /* Object file type */
81 Elf32_Half e_machine; /* Architecture */
82 Elf32_Word e_version; /* Object file version */
83 Elf32_Addr e_entry; /* Entry point virtual address */
84 Elf32_Off e_phoff; /* Program header table file offset */
85 Elf32_Off e_shoff; /* Section header table file offset */
86 Elf32_Word e_flags; /* Processor-specific flags */
87 Elf32_Half e_ehsize; /* ELF header size in bytes */
88 Elf32_Half e_phentsize; /* Program header table entry size */
89 Elf32_Half e_phnum; /* Program header table entry count */
90 Elf32_Half e_shentsize; /* Section header table entry size */
91 Elf32_Half e_shnum; /* Section header table entry count */
92 Elf32_Half e_shstrndx; /* Section header string table index */
93} Elf32_Ehdr;
94
95typedef struct
96{
97 Elf32_Word sh_name; /* Section name (string tbl index) */
98 Elf32_Word sh_type; /* Section type */
99 Elf32_Word sh_flags; /* Section flags */
100 Elf32_Addr sh_addr; /* Section virtual addr at execution */
101 Elf32_Off sh_offset; /* Section file offset */
102 Elf32_Word sh_size; /* Section size in bytes */
103 Elf32_Word sh_link; /* Link to another section */
104 Elf32_Word sh_info; /* Additional section information */
105 Elf32_Word sh_addralign; /* Section alignment */
106 Elf32_Word sh_entsize; /* Entry size if section holds table */
107} Elf32_Shdr;
108
109#define ELFMAG0 0x7f /* Magic number byte 0 */
110#define ELFMAG1 'E' /* Magic number byte 1 */
111#define ELFMAG2 'L' /* Magic number byte 2 */
112#define ELFMAG3 'F' /* Magic number byte 3 */
113
114#define SHF_WRITE (1 << 0) /* Writable */
115#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
116#define SHF_EXECINSTR (1 << 2) /* Executable */
117
118#define SHT_NOBITS 8 /* Program space with no data (bss) */
119
120/*
121 ---------------------------------------------------------------------------
122 End of elf.h
123 ---------------------------------------------------------------------------
124*/
125
126static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP.";
127static const char null_key_v3[] = "CTL:Z3N07|PDE0.DPMP.";
128static const char null_key_v4[] = "CTL:N0MAD|PDE0.DPFP.";
129
130static const struct device_info devices[] =
131{
132 /* Creative Zen Vision:M */
133 {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M", 42, null_key_v2},
134 /* Creative Zen Vision:M Go! */
135 {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M\0 \0G\0o\0!", 50, null_key_v2},
136 /* Creative Zen Vision © TL */
137 /* The "©" should be ANSI encoded or the device won't accept the firmware package. */
138 {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0 \0\xA9\0T\0L", 46, null_key_v2},
139 /* Creative ZEN V */
140 {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0V", 42, null_key_v4},
141 /* Creative ZEN */
142 {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N", 48, null_key_v3},
143 /* Creative ZEN X-Fi */
144 {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0X\0-\0F\0i\0", 34, null_key_v4},
145 /* Creative ZEN Mozaic */
146 {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0M\0o\0z\0a\0i\0c\0", 38, null_key_v4}
147};
148
149/*
150Create a Zen Vision:M FRESCUE structure file
151*/
152extern void int2le(unsigned int val, unsigned char* addr);
153extern unsigned int le2int(unsigned char* buf);
154
155
156static int make_ciff_file(const unsigned char *inbuf, unsigned int length,
157 unsigned char *outbuf, int device)
158{
159 unsigned char key[20];
160 memcpy(outbuf, "FFIC", 4);
161 int2le(length+90, &outbuf[4]);
162 memcpy(&outbuf[8], "FNIC", 4);
163 int2le(96, &outbuf[0xC]);
164 memcpy(&outbuf[0x10], devices[device].cinf, devices[device].cinf_size);
165 memset(&outbuf[0x10+devices[device].cinf_size], 0,
166 96 - devices[device].cinf_size);
167 memcpy(&outbuf[0x70], "ATAD", 4);
168 int2le(length+32, &outbuf[0x74]);
169 memcpy(&outbuf[0x78], "H\0j\0u\0k\0e\0b\0o\0x\0\x32\0.\0j\0r\0m",
170 25); /*Unicode encoded*/
171 memset(&outbuf[0x78+25], 0, 32);
172 memcpy(&outbuf[0x98], inbuf, length);
173 memcpy(&outbuf[0x98+length], "LLUN", 4);
174 int2le(20, &outbuf[0x98+length+4]);
175 /* Do checksum */
176 hmac_sha1((unsigned char *)devices[device].null, strlen(devices[device].null),
177 outbuf, 0x98+length, key);
178 memcpy(&outbuf[0x98+length+8], key, 20);
179 return length+0x90+0x1C+8;
180}
181
182static int elf_convert(const unsigned char *inbuf, unsigned char *outbuf)
183{
184 Elf32_Ehdr *main_header;
185 Elf32_Shdr *section_header;
186 unsigned int i, j, sum;
187 intptr_t startaddr;
188
189 main_header = (Elf32_Ehdr*)inbuf;
190 if( !( main_header->e_ident[0] == ELFMAG0 && main_header->e_ident[1] == ELFMAG1
191 && main_header->e_ident[2] == ELFMAG2 && main_header->e_ident[3] == ELFMAG3 ) )
192 {
193 printf("Invalid ELF header!\n");
194 return -1;
195 }
196
197 startaddr = (intptr_t)outbuf;
198
199 for(i = 0; i < main_header->e_shnum; i++)
200 {
201 section_header = (Elf32_Shdr*)(inbuf+main_header->e_shoff+i*sizeof(Elf32_Shdr));
202
203 if( (section_header->sh_flags & SHF_WRITE || section_header->sh_flags & SHF_ALLOC
204 || section_header->sh_flags & SHF_EXECINSTR) && section_header->sh_size > 0
205 && section_header->sh_type != SHT_NOBITS )
206 {
207 /* Address */
208 int2le(section_header->sh_addr, outbuf);
209 outbuf += 4;
210 /* Size */
211 int2le(section_header->sh_size, outbuf);
212 outbuf += 4;
213 /* Checksum */
214 sum = 0;
215 for(j=0; j<section_header->sh_size; j+= 4)
216 sum += le2int((unsigned char*)(inbuf+section_header->sh_offset+j)) + (le2int((unsigned char*)(inbuf+section_header->sh_offset+j))>>16);
217 int2le(sum, outbuf);
218 outbuf += 2;
219 memset(outbuf, 0, 2);
220 outbuf += 2;
221 /* Data */
222 memcpy(outbuf, inbuf+section_header->sh_offset, section_header->sh_size);
223 outbuf += section_header->sh_size;
224 }
225 }
226 return (int)((intptr_t)outbuf - startaddr);
227}
228
229static int make_jrm_file(const unsigned char *inbuf, unsigned char *outbuf)
230{
231 int length;
232
233 /* Clear the header area to zero */
234 memset(outbuf, 0, 0x18);
235
236 /* Header (EDOC) */
237 memcpy(outbuf, "EDOC", 4);
238 /* Total Size: temporarily set to 0 */
239 memset(&outbuf[0x4], 0, 4);
240 /* 4 bytes of zero */
241 memset(&outbuf[0x8], 0, 4);
242
243 length = elf_convert(inbuf, &outbuf[0xC]);
244 if(length < 0)
245 return -1;
246 /* Now set the actual Total Size */
247 int2le(4+length, &outbuf[0x4]);
248
249 return 0xC+length;
250}
251
252int zvm_encode(const char *iname, const char *oname, int device, bool enable_ciff)
253{
254 size_t len;
255 int length;
256 FILE *file;
257 unsigned char *outbuf;
258 unsigned char *buf;
259
260 file = fopen(iname, "rb");
261 if (!file)
262 {
263 perror(iname);
264 return -1;
265 }
266 fseek(file, 0, SEEK_END);
267 length = ftell(file);
268
269 fseek(file, 0, SEEK_SET);
270
271 buf = (unsigned char*)malloc(length);
272 if ( !buf )
273 {
274 printf("Out of memory!\n");
275 return -1;
276 }
277
278 len = fread(buf, 1, length, file);
279 if(len < (size_t)length)
280 {
281 perror(iname);
282 return -2;
283 }
284 fclose(file);
285
286 outbuf = (unsigned char*)malloc(length+0x300);
287 if ( !outbuf )
288 {
289 free(buf);
290 printf("Out of memory!\n");
291 return -1;
292 }
293 length = make_jrm_file(buf, outbuf);
294 free(buf);
295 if(length < 0)
296 {
297 free(outbuf);
298 printf("Error in making JRM file!\n");
299 return -1;
300 }
301 if(enable_ciff)
302 {
303 buf = (unsigned char*)malloc(length+0x200);
304 if ( !buf )
305 {
306 free(outbuf);
307 printf("Out of memory!\n");
308 return -1;
309 }
310 memset(buf, 0, length+0x200);
311 length = make_ciff_file(outbuf, length, buf, device);
312 free(outbuf);
313 }
314 else
315 buf = outbuf;
316
317 file = fopen(oname, "wb");
318 if (!file)
319 {
320 free(buf);
321 perror(oname);
322 return -3;
323 }
324
325 len = fwrite(buf, 1, length, file);
326 if(len < (size_t)length)
327 {
328 free(buf);
329 perror(oname);
330 return -4;
331 }
332
333 free(buf);
334
335 fclose(file);
336
337 return 0;
338}