Skip to content

Instantly share code, notes, and snippets.

@cecekpawon
Last active August 7, 2017 21:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cecekpawon/66111de5e5a7bcb2f407811be2c0d52b to your computer and use it in GitHub Desktop.
Save cecekpawon/66111de5e5a7bcb2f407811be2c0d52b to your computer and use it in GitHub Desktop.
Parse Ozmosis theme data.
#!/usr/bin/php
<?php
# Ozmosis theme (un)packer.
# @cecekpawon: Sun Aug 6 19:26:08 2017
# chmod +x script
function help ($str = "") {
$script = basename (__FILE__);
$usage = <<<YODA
Usage: ./$script -[dc] themefile(.bin) prefixed_by_type
- [c] New packed file will be in: 'script_dir/themefile_packed.bin'.
- [d] New unpacked files will be in: 'script_dir/themefile'.
- [prefixed_by_type (optional)]: true (dumped files will prefixed by type instead of id).
YODA;
if ($str) {
$usage .= "\n** [!] {$str}\n";
}
die ($usage);
}
if (!isset($argv) || (count($argv) < 3)) help ();
else {
$opt = strtolower ($argv[1]);
switch ($opt) {
case "-d":
$unpack = true;
break;
case "-c":
$pack = true;
break;
default:
help ();
}
$theme_name = $argv[2];
$prefixed_by_type = (bool)(isset ($argv[3]) && (strtolower ($argv[3]) === "true"));
}
define ("SCRIPT_DIR", __DIR__);
define ("THEME_BIN_USER", $theme_name);
define ("THEME_NAME", pathinfo ($theme_name)["filename"]);
define ("THEME_PLIST_NAME", "theme.plist");
define ("THEME_PACKED_NAME", THEME_NAME . "_packed.bin");
define ("NULL_TERMINATOR", "0a00");
define ("PNG_SIGNATURE", "89504e470d0a1a0a");
define ("XML_TAG", "3c3f786d6c");
define ("PREFIXED_BY_TYPE", $prefixed_by_type);
// 00:443 00:000 Installed Font OregonMedium 21 pt 95 Glyphs Proportional (4)
// 00:444 00:000 Installed Pointer Image 15 x 22 Id 01 Frame 00 "Default" (1)
// 49484452 00000080 00000080 08060000 00C33E61 CB000000 13744558 74426164 67650055 62756E74 755F3531 5F30307E 718AF17D 00000E50
// ^^ ^^ ^^ ^^ ^^
// IHDR Width Height tEXt tEXtEnd
/*
IHDR:
Width: 4 bytes
Height: 4 bytes
Bit depth: 1 byte
Color type: 1 byte
Compression method: 1 byte
Filter method: 1 byte
Interlace method: 1 byte
tEXt Textual data:
Keyword: 1-79 bytes (character string)
Null separator: 1 byte
Text: n bytes (character string)
if (sub_4f51c(rcx, "Device") != 0x0) {
rbx = rbx + 0x200;
}
if (sub_4f51c(rsi, 0x23144) != 0x0) { // [ds:0x35244]
rbx = rbx + 0x10; // 0x7474754200737542 ttuB suB
} // + 0x6f + 0x6e on
if (sub_4f51c(rsi, 0x23148) != 0x0) { // [ds:0x35248]
rbx = rbx + 0x8;
}
if (sub_4f51c(rsi, "Badge") != 0x0) {
rbx = rbx - 0xffffff80;
}
if (sub_4f51c(rsi, "Pointer") != 0x0) {
rbx = rbx + 0x1;
}
if (sub_4f51c(rsi, "Selector") != 0x0) {
rbx = rbx + 0x20;
}
if (sub_4f51c(rsi, "Special") != 0x0) {
rbx = rbx + 0x100;
}
*/
function get_meta ($str) {
preg_match ('#49484452(.{8})(.{8}).*(.{2})74455874(.*?)00(.*?)5F(.*?)5F(.*?)7E(.*?)00#i', $str, $matches);
//var_dump ($matches);
$iWidth = hexdec ($matches[1]);
$iHeight = hexdec ($matches[2]);
//$iHmm = hexdec ($matches[3]);
$iType = hex2bin ($matches[4]);
$iLabel = hex2bin ($matches[5]);
$iRest1a = $matches[6];
$iRest1b = hex2bin ($iRest1a);
$iRest2a = $matches[7];
$iRest2b = hex2bin ($iRest2a);
$iID = sprintf("%d", pack ("H*", $iRest1a));
$iFrame = sprintf("%d", pack ("H*", $iRest2a));
switch ($iType) {
case "Pointer":
$iID += 1; //0x1
$num = 1;
break;
case "Bus":
$iID += 16; //0x10
$num = 2;
break;
case "Button":
$iID += 8; //0x8
$num = 3;
break;
case "Device":
$iID += 512; //0x200
$num = 4;
break;
case "Badge":
$iID += 128; //0x80?
$num = 5;
break;
case "Selector":
$iID += 32; //0x20
$num = 6;
break;
case "Special":
$iID += 256; //0x100
$num = 7;
break;
default:
if ($iID) return;
$num = 0;
break;
}
$fn = sprintf ("%03d_{$iType}_{$iLabel}_{$iRest1b}_{$iRest2b}.png", $iID);
if (PREFIXED_BY_TYPE) {
$fn = sprintf ("%02d_%s", $num, $fn);
}
printf (" - {$iType}: (w_{$iWidth} x h_{$iHeight}) \"{$iLabel}\" {$iRest1a}({$iRest1b})_{$iRest2a}({$iRest2b}) - (id_%d frame_%d)\n", $iID, $iFrame);
return $fn;
}
function pack_theme () {
printf ("Packing as '%s'.\n", THEME_PACKED_NAME);
chdir (THEME_NAME);
printf (" - %s\n", THEME_PLIST_NAME);
$str = unpack ("H*", @file_get_contents (THEME_PLIST_NAME))[1];
$str .= NULL_TERMINATOR;
$a = glob ("*.png");
foreach ($a as $v) {
echo " - {$v}\n";
$str .= unpack ("H*", @file_get_contents ("{$v}"))[1];
}
@file_put_contents (SCRIPT_DIR . "/" . THEME_PACKED_NAME, pack ("H*", $str));
}
function unpack_thene () {
printf ("Unpacking '%s'.\n", THEME_BIN_USER);
if (!is_dir (THEME_NAME)) {
mkdir (THEME_NAME);
}
$str = unpack ("H*", @file_get_contents (THEME_BIN_USER));
//$i = 0;
$a = preg_split ("#" . PNG_SIGNATURE . "#i", $str[1]);
foreach ($a as $v) {
if (preg_match ("/^" . XML_TAG . "/i", $v)) {
$fn = THEME_PLIST_NAME;
$v = rtrim ($v, NULL_TERMINATOR);
} else {
$v = PNG_SIGNATURE . $v;
if (!($fn = get_meta ($v))) {
continue;
}
}
$b = pack ("H*", $v);
@file_put_contents (THEME_NAME . "/" . $fn, $b);
//$i++;
}
}
chdir (SCRIPT_DIR);
if ($unpack) {
if (!file_exists (THEME_BIN_USER)) {
help (THEME_BIN_USER . " not exists.\n");
}
unpack_thene ();
}
elseif ($pack) {
if (!file_exists (THEME_NAME . "/" . THEME_PLIST_NAME)) {
help (THEME_NAME . "/" . THEME_PLIST_NAME . " not exists.\n");
}
pack_theme ();
}
echo ("Done.\n");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment