On more than a few occasions over the past nine years, I’ve felt the desire to create an icon. There’ve been many reasons, but each time I’ve felt it deep within my non-existent soul. And each time I was crushed.
Well, maybe not crushed but I could never seem to find a program that would export .ICO files while remaining free. (With the possible exception of pixel editors, but who wants to use those?)
And each time I encountered that problem, I realized that I should just make one. So I did.
C or C++ probably would have been the obvious choice – so I decided to go with PHP. But how to deal with reading binary data at such a low-level, in a good way?
It was this problem that piqued my interest. A low-level binary-data manipulation engine in a high-level scripting language? Well, that sounded both challenging and interesting, if potentially super inefficient. And with something like that, well, an Icon maker should become a good deal simpler to make.
So that’s where it started — with the engine.
There are two types of data in the engine: structures and primitives.
Primitives are things like words, dwords, byte, etc.
$PRIMITIVES = array(
"WORD" => array("size"=>2, "char"=>"v"),
"DWORD" => array("size"=>4, "char"=>"V"),
"LONG" => array("size"=>4, "char"=>"l"),
"BYTE" => array("size"=>1, "char"=>"C"),
);
Structures are more complex. Structures are made of of fields. Each field in a structure has a type (which can either be another structure, or a primitive) and can have an optional expected value (for rudimentary automated data-checking). Structures are recursively type-checked by the engine, to make sure they resolve to known primitives, before processing.
//http://msdn2.microsoft.com/en-us/library/ms997538.aspx
$ICONDIR = array( //this one needs its own read function because it has an array
"idReserved" => array("type"=>"WORD", "expected_value"=>0), // Reserved (must be 0)
"idType" => array("type"=>"WORD", "expected_value"=>1), // Resource Type (1 for icons)
"idCount" => array("type"=>"WORD"), // How many images?
"idEntries" => array("type"=>"ICONDIRENTRY"), // An entry for each image (idCount of them)
);
Of course, one could define a structure recursively – which would be bad – but whatever, let’s ignore that.
The engine takes care of simple loading and storing of functions automatically, but allows you to write your functions if necessary (in the case of structures that contain arrays, for example) and will make use of those if they exist. So you only have to call the default load/store functions, after you define your custom functions.
In cases like ICONDIR, which contains an array whose length is defined by another field in the structure, I had to write a custom load function for it but was not required to write a custom store function (as the general store function handles arrays).
function read_ICONDIR($file_handle) {
global $ICONDIR, $WARNINGS;
$out = array();
foreach($ICONDIR as $k=>$v) {
if (!in_array($k, array('idEntries'))) {
$out[$k] = read_structure($file_handle, $v['type']);
if (array_key_exists('expected_value', $v) and $out[$k] != $v['expected_value']) //basic checking
$WARNINGS[] = "value read does not match defined expected value: ". "ICONDIR" . "->". $k . ": ". ($out[$k]);
}
}
return $out;
}
So, with karl helping me to track down and fix bugs, I got the engine working.
Coming soon: The icon maker, the interface, and the link! :O
OH MY GOD CLIFFHANGER BLOG
When will Brad blog next?
That’s a pretty crazy binary interface you made? Are you going to re-use it for other stuff?
only if I have to read/write files for some reason and also remember that it exists? So probably not 🙁
When should I put up the next part?
but reading and writing files is something that happens a lot?
you could put it up the next blog right now and appease my constant desire for visual input? or you could wait a while and save yourself having to think of a blog again?
we should have a crazy revolution and use semicolons or something to end sentences instead of question marks?