Last active
October 3, 2024 20:25
-
-
Save benthetechguy/9cc8e5b83fdae4fa74be9ab77332c985 to your computer and use it in GitHub Desktop.
Generate a CHRP script with custom icon to dual boot with Linux on PowerPC Macs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
chrp.cpp - Generate a CHRP script to dual boot with Linux on PowerPC Macs | |
Copyright (C) 2024 Ben Westover <[email protected]> | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <https://www.gnu.org/licenses/>. | |
*/ | |
#include <iostream> | |
#include <string> | |
#include <bitset> | |
#include <png++/png.hpp> | |
using namespace std; | |
string generateLogo(string logoPath, string hoverPath) { | |
string logoText = "<OS-BADGE-ICONS>\n"; | |
png::image< png::rgba_pixel > logoImage(logoPath); | |
png::image< png::rgba_pixel > hoverImage(hoverPath); | |
png::image< png::rgba_pixel > image[2] = {logoImage, hoverImage}; | |
png::uint_32 width[2] = {image[0].get_width(), image[1].get_width()}; | |
png::uint_32 height[2] = {image[0].get_height(), image[1].get_height()}; | |
if (width[0] == 16 && height[0] == 16) { | |
logoText += "1010\n"; | |
} else if (width[0] == 52 && height[0] == 52) { | |
logoText += "3434\n"; | |
} else { | |
return "logoSizeError"; | |
} | |
if ((width[1] != 16 || height[1] != 16) && (width[1] != 52 || height[1] != 52)) { | |
return "hoverSizeError"; | |
} | |
for (int i = 0; i < 2; i++) { | |
cout << i; | |
for (int y = 0; y < height[i]; y++) { | |
for (int x = 0; x < width[i]; x++) { | |
png::rgba_pixel pixel = image[i].get_pixel(x, y); | |
int red = round(pixel.red * (7.0 / 255.0)); | |
int green = round(pixel.green * (7.0 / 255.0)); | |
int blue = round(pixel.blue * (3.0 / 255.0)); | |
string redBits = bitset< 3 >(red).to_string(); | |
string greenBits = bitset< 3 >(green).to_string(); | |
string blueBits = bitset< 2 >(blue).to_string(); | |
string pixelBits = redBits + greenBits + blueBits; | |
for(int j = 0; j < 8; j += 4) { | |
if (pixelBits.substr(j, 4) == "0000") logoText += "0"; | |
else if (pixelBits.substr(j, 4) == "0001") logoText += "1"; | |
else if (pixelBits.substr(j, 4) == "0010") logoText += "2"; | |
else if (pixelBits.substr(j, 4) == "0011") logoText += "3"; | |
else if (pixelBits.substr(j, 4) == "0100") logoText += "4"; | |
else if (pixelBits.substr(j, 4) == "0101") logoText += "5"; | |
else if (pixelBits.substr(j, 4) == "0110") logoText += "6"; | |
else if (pixelBits.substr(j, 4) == "0111") logoText += "7"; | |
else if (pixelBits.substr(j, 4) == "1000") logoText += "8"; | |
else if (pixelBits.substr(j, 4) == "1001") logoText += "9"; | |
else if (pixelBits.substr(j, 4) == "1010") logoText += "A"; | |
else if (pixelBits.substr(j, 4) == "1011") logoText += "B"; | |
else if (pixelBits.substr(j, 4) == "1100") logoText += "C"; | |
else if (pixelBits.substr(j, 4) == "1101") logoText += "D"; | |
else if (pixelBits.substr(j, 4) == "1110") logoText += "E"; | |
else if (pixelBits.substr(j, 4) == "1111") logoText += "F"; | |
else return "pixelProcessingError"; | |
} | |
} | |
logoText += "\n"; | |
} | |
} | |
for (int y = 0; y < height[0]; y++) { | |
for (int x = 0; x < width[0]; x++) { | |
png::rgba_pixel pixel = image[0].get_pixel(x, y); | |
if (pixel.alpha == 0) logoText += "00"; | |
else logoText += "FF"; | |
} | |
logoText += "\n"; | |
} | |
logoText += "</OS-BADGE-ICONS>\n"; | |
return logoText; | |
} | |
int main() { | |
string chrpScript = "<CHRP-BOOT>\n" | |
"<COMPATIBLE>\n" | |
"MacRISC MacRISC3 MacRISC4\n" | |
"</COMPATIBLE>\n" | |
"<DESCRIPTION>\n" | |
"PowerPC GNU/Linux First Stage Bootstrap\n" | |
"</DESCRIPTION>\n" | |
"<BOOT-SCRIPT>\n" | |
": .printf fb8-write drop ;\n" | |
": bootgrub \" Loading GRUB...\" .printf 100 ms load-base release-load-area \" &device;:&partition;,\\grub\" $boot ;\n"; | |
int otherOsCount; | |
cout << "How many non-Linux operating systems are there?\nNon-Linux OS Count: "; | |
cin >> otherOsCount; | |
string osNames[otherOsCount]; | |
for (int i = 0; i < otherOsCount; i++) { | |
cout << "\nWhat is the name of OS " << i+1 << "?\nOS " << i+1 << " name: "; | |
getline(cin >> ws, osNames[i]); | |
int osPartition; | |
cout << "\nWhat partition is " << osNames[i] << "'s bootloader located on?\nOS " << i+1 << " Bootloader partition: "; | |
cin >> osPartition; | |
chrpScript += ": bootother" + to_string(i+1) + " \" Booting " + osNames[i] + "...\" .printf 100 ms load-base release-load-area \" &device;:" + to_string(osPartition) + ",\\\\:tbxi\" $boot ;\n"; | |
} | |
int usbPorts; | |
cout << "\nHow many USB ports does the machine have? If it cannot boot from USB, put 0.\nBootable USB port count: "; | |
cin >> usbPorts; | |
if (usbPorts < 0 || usbPorts > 4) { | |
cout << "Error: Only 0-4 USB ports allowed.\n"; | |
return 1; | |
} | |
for (int i = 0; i < usbPorts; i++) { | |
chrpScript += ": bootusb" + to_string(i+1) + " \" Booting USB " + to_string(i+1) + "...\" .printf 100 ms load-base release-load-area \" usb" + to_string(i) + "/disk@1:,\\\\:tbxi\" $boot ;\n"; | |
} | |
chrpScript += ": bootcd \" Booting CDROM...\" .printf 100 ms load-base release-load-area \" cd:,\\:tbxi\" $boot ;\n" | |
"\" screen\" output\n" | |
"variable interactive\n" | |
"1 interactive !\n\n" | |
"0 interactive @ = if\n" | |
" bootgrub\n" | |
"then\n\n" | |
"dev screen\n" | |
"\" \"(0000000000aa00aa0000aaaaaa0000aa00aaaa5500aaaaaa)\" drop 0 7 set-colors\n" | |
"\" \"(5555555555ff55ff5555ffffff5555ff55ffffff55ffffff)\" drop 8 15 set-colors\n" | |
"device-end\n" | |
"f to foreground-color\n" | |
"0 to background-color\n" | |
"\" \"(0C)\" .printf\n\n" | |
"\" First Stage Debian GNU/Linux Bootstrap\"(0d 0a)\" .printf\n" | |
"\" \"(0d 0a)\" .printf\n" | |
"\" Press g for GNU/Linux,\"(0d 0a)\" .printf\n"; | |
for (int i = 0; i < otherOsCount; i++) { | |
chrpScript += "\" " + to_string(i+1) + " for " + osNames[i] + ",\"(0d 0a)\" .printf\n"; | |
} | |
const string usbPortLetters[4] = {"u", "s", "b", "a"}; | |
for (int i = 0; i < usbPorts; i++) { | |
chrpScript += "\" " + usbPortLetters[i] + " for USB " + to_string(i+1) + ".\"(0d 0a)\" .printf\n"; | |
} | |
chrpScript += "\" c for CDROM.\"(0d 0a)\" .printf\n" | |
"\" \"(0d 0a)\" .printf\n" | |
"\" Stage 1 Boot: \" .printf\n" | |
"get-msecs d# 10 3E8 * +\n" | |
"begin\n" | |
" key? if\n" | |
" key case\n" | |
" ascii g of \" g \"(0d 0a)\" .printf bootgrub endof\n"; | |
for (int i = 0; i < otherOsCount; i++) { | |
chrpScript += " ascii " + to_string(i+1) + " of \" " + to_string(i+1) + " \"(0d 0a)\" .printf bootother" + to_string(i+1) + " endof\n"; | |
} | |
for (int i = 0; i < usbPorts; i++) { | |
chrpScript += " ascii " + usbPortLetters[i] + " of \" " + usbPortLetters[i] + " \"(0d 0a)\" .printf bootusb" + to_string(i+1) + " endof\n"; | |
} | |
chrpScript += " ascii c of \" c \"(0d 0a)\" .printf bootcd endof\n" | |
" endcase\n" | |
" then\n" | |
" dup get-msecs <\n" | |
"until\n" | |
"drop\n" | |
"\" \"(0d 0a)\" .printf bootgrub\n" | |
"</BOOT-SCRIPT>\n"; | |
string logoPath; | |
string hoverPath; | |
cout << "\nWhere is your logo png located?\nLogo icon path: "; | |
cin >> logoPath; | |
cout << "\nThere is an option for a second icon that will be shown when clicking on the boot option. Where is this icon png located? The same logo png as before can also be used.\nHover icon path: "; | |
cin >> hoverPath; | |
string logoText = generateLogo(logoPath, hoverPath); | |
if (logoText == "logoSizeError") { | |
cout << "Error: Logo must be 16x16 or 52x52.\n"; | |
return 1; | |
} else if (logoText == "hoverSizeError") { | |
cout << "Error: Hover logo must be 16x16 or 52x52.\n"; | |
return 1; | |
} else if (logoText == "pixelProcessingError") { | |
cout << "Error: Something went wrong while processing the pixels."; | |
return 1; | |
} | |
chrpScript += logoText + "</CHRP-BOOT>\n"; | |
cout << chrpScript; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment