Last active
August 7, 2017 21:11
-
-
Save cecekpawon/66111de5e5a7bcb2f407811be2c0d52b to your computer and use it in GitHub Desktop.
Parse Ozmosis theme data.
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
#!/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