A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 261 lines 7.1 kB view raw
1/* zenutils - Utilities for working with creative firmwares. 2 * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19#include <iostream> 20#include <sstream> 21#include <getpot/GetPot> 22#include <file.h> 23#include <firmware.h> 24#include <utils.h> 25 26 27static const char VERSION[] = "0.1"; 28 29void print_version() 30{ 31 std::cout 32 << "firmware_make - Creates a Creative firmware archive." << std::endl 33 << "Version " << VERSION << std::endl 34 << "Copyright (c) 2007 Rasmus Ry" << std::endl; 35} 36 37void print_help() 38{ 39 print_version(); 40 std::cout << std::endl 41 << "Usage: firmware_make [command] [options]" << std::endl 42 << std::endl 43 << " Commands:" << std::endl 44 << " -h,--help" << std::endl 45 << " prints this message." << std::endl 46 << " -m,--makefile [file]" << std::endl 47 << " specifies the .mk file to build the firmware archive from." 48 << std::endl << std::endl 49 << " Options:" << std::endl 50 << " -V,--verbose" << std::endl 51 << " prints verbose messages." << std::endl 52 << " -f,--firmware [file]" << std::endl 53 << " specifies the output firmware file name" << std::endl 54 << std::endl 55 ; 56} 57 58dword get_tag_value(std::string tag) 59{ 60 if (tag[0] == '0' && tag[1] == 'x') 61 { 62 dword val = 0; 63 if (sscanf(tag.c_str(), "0x%08X", &val) == 1) 64 return val; 65 if (sscanf(tag.c_str(), "0x%08x", &val) == 1) 66 return val; 67 } 68 else 69 { 70 return shared::swap(*(dword*)&tag[0]); 71 } 72 return 0; 73} 74 75bool process_child(const GetPot& mkfile, const std::string& root, int index, 76 zen::firmware_entry& entry) 77{ 78 std::stringstream sstm; 79 sstm << root << "/" << index; 80 std::string var = sstm.str() + "/tag"; 81 std::string tag = mkfile(var.c_str(), ""); 82 var = sstm.str() + "/name"; 83 std::string name = mkfile(var.c_str(), ""); 84 var = sstm.str() + "/file"; 85 std::string file = mkfile(var.c_str(), ""); 86 87 if (file.empty() || tag.empty()) 88 { 89 std::cerr << "Invalid file or tag for var: " << sstm.str() 90 << std::endl; 91 return false; 92 } 93 94 shared::bytes buffer; 95 if (!shared::read_file(file, buffer)) 96 { 97 std::cerr << "Failed to read the file: " << file << std::endl; 98 return false; 99 } 100 101 entry.get_bytes().clear(); 102 entry.get_header().tag = get_tag_value(tag); 103 size_t contoff = entry.get_content_offset(); 104 if (contoff) 105 { 106 entry.get_bytes().resize(contoff, 0); 107 if (!name.empty()) 108 { 109 size_t endoff = entry.is_big_endian() ? 1 : 0; 110 for (int i = 0; i < name.size(); ++i) 111 entry.get_bytes()[i * 2 + endoff] = name[i]; 112 } 113 } 114 entry.get_bytes().insert(entry.get_bytes().end(), buffer.begin(), 115 buffer.end()); 116 117 entry.get_header().size = entry.get_bytes().size(); 118 119 return true; 120} 121 122int process_arguments(int argc, char* argv[]) 123{ 124 //-------------------------------------------------------------------- 125 // Parse input variables. 126 //-------------------------------------------------------------------- 127 128 GetPot cl(argc, argv); 129 if (cl.size() == 1 || cl.search(2, "-h", "--help")) 130 { 131 print_help(); 132 return 1; 133 } 134 135 std::string makefile; 136 if (cl.search("-m") || cl.search("--makefile")) 137 makefile = cl.next(""); 138 if (makefile.empty()) 139 { 140 std::cerr << "Makefile must be specified." << std::endl; 141 return 2; 142 } 143 144 std::string firmware; 145 if (cl.search("-f") || cl.search("--firmware")) 146 firmware = cl.next(""); 147 if (firmware.empty()) 148 { 149 std::cerr << "Firmware must be specified." << std::endl; 150 return 3; 151 } 152 153 bool verbose = false; 154 if (cl.search("-V") || cl.search("--verbose")) 155 verbose = true; 156 157 GetPot mkfile(makefile.c_str()); 158 if (verbose) 159 mkfile.print(); 160 161 bool big_endian; 162 std::string endian = mkfile("endian", "little"); 163 if (endian == "little") 164 { 165 big_endian = false; 166 } 167 else if (endian == "big") 168 { 169 big_endian = true; 170 } 171 else 172 { 173 std::cerr << "Invalid value of 'endian'" << std::endl; 174 return 4; 175 } 176 177 zen::firmware_archive archive(big_endian); 178 int childcount = mkfile("children/count", 0); 179 if (!childcount) 180 { 181 std::cerr << "A firmware archive must have at least one child entry." 182 << std::endl; 183 return 5; 184 } 185 186 for (int i = 0; i < childcount; i++) 187 { 188 zen::firmware_entry entry(big_endian); 189 if (!process_child(mkfile, "children", i, entry)) 190 { 191 return 6; 192 } 193 archive.get_children().push_back(entry); 194 } 195 196 int neighbourcount = mkfile("neighbours/count", 0); 197 for (int i = 0; i < neighbourcount; i++) 198 { 199 zen::firmware_entry entry(big_endian); 200 if (!process_child(mkfile, "neighbours", i, entry)) 201 { 202 return 7; 203 } 204 archive.get_neighbours().push_back(entry); 205 } 206 207 std::ofstream ofs; 208 ofs.open(firmware.c_str(), std::ios::out|std::ios::binary|std::ios::trunc); 209 if (!ofs) 210 { 211 std::cerr << "Failed to create the firmware file." << std::endl; 212 return 8; 213 } 214 215 if (!archive.write(ofs)) 216 { 217 std::cerr << "Failed to save the firmware archive." << std::endl; 218 return 9; 219 } 220 ofs.close(); 221 222 size_t length = archive.calc_size(); 223 if (!length) 224 { 225 std::cerr << "Failed to determine the size of the firmware archive." 226 << std::endl; 227 return 10; 228 } 229 230 int align = length % 4; 231 if (align) 232 { 233 shared::bytes padding(4 - align, 0); 234 if (!shared::write_file(firmware, padding, false, length)) 235 { 236 std::cerr << "Failed to write padding data." << std::endl; 237 return 11; 238 } 239 } 240 241 return 0; 242} 243 244int main(int argc, char* argv[]) 245{ 246 try 247 { 248 return process_arguments(argc, argv); 249 } 250 catch (const std::exception& xcpt) 251 { 252 std::cerr << "Exception caught: " << xcpt.what() << std::endl; 253 return -1; 254 } 255 catch (...) 256 { 257 std::cerr << "Unknown exception caught." << std::endl; 258 return -2; 259 } 260 return -3; 261}