Looking for a job (again)

August 10th, 2026

Pre script: I’ll try to keep this post above the rest for obvious reasons and you should find newer posts about the usual stuff below.

For circumstances out of our control I don’t have a job any more (after sixteen years of it) and I’m completely free starting from February next year. And while I can live more or less comfortably for a couple of years on my savings I consider proper to have a job, preferably an interesting one. Since it is hard to find an interesting job for my qualification, I post this in faint hope that somebody will offer me one.

First of all, let’s start with what I can do. I have a good knowledge of C (but not C++ — nobody knows C++ in its fullness, I just don’t lie about it), Rust and various assembly languages (not just x86/AMD64 and ARM, I have some experience with a couple of more exotic ones; most of the assembly code I wrote is SIMD optimisations). I also have a knack for reverse engineering things and documenting them afterwards, which involves nor merely looking at the decompiled output (or disassembly when a decompiler can’t handle it or lies) and copying it verbatim but rather understanding it and comparing various parts to the known methods. And of course I have vast knowledge of multimedia and adjacent technologies (up to OS and CPU architecture). What I don’t know I can learn.

Then, why you should consider hiring me. If you need somebody who can write safe, portable code or fast platform-dependent assembly code that will not need much maintenance afterwards. If you need somebody to work on low-level multimedia stuff (not just integrating an existing framework but messing with protocols and decoders directly) or related image/audio processing. Or if you need somebody to work on low-level stuff e.g. for embedded systems or microcontrollers. If you need somebody to debug complex cases or reverse engineer third-party stuff for interoperability (digital sovereignty is supposedly a thing now in the EU, maybe you need somebody to implement a part of it).

Last, working conditions. I’m a naturalised German citizen, so I’d prefer my work to be inside EU, preferably remote or close to Karlsruhe where I live; or at least not requiring a relocation to another country (which is still possible for EU but the offer must be very appealing). Additionally I prefer to work in a small company instead of being a cog in a large corporation. Finally, the unpleasant question of money: I’m not going to work for exposure, peanuts or partnering up for the future profits (I had enough of that in my student times, thanks); it should be enough for a decent living here i.e. what any other middle-class worker can afford and anything above that is nice but not mandatory.

If nothing works maybe I’ll just get some useful menial job instead.

Here’s my email (repeated for convenience as it’s hidden in the links way below):
Who knows, I might be more lucky this time.

na_game_tool 0.6.0, AVI edition

September 5th, 2026

What should follow a political rant that nobody would read? A release of a tool that nobody would use of course!

I’m indifferent to announce the release of na_game_tool version 0.6.0, now with AVI support. Beside being able to write output to AVI it can now also de-obfuscate some AVI files that employ some simple scheme (like XORing with a 32-bit counter). And in addition to that it can also reconstruct Smacker and audio files from AVIs (or IAVFs) used in Black Dahlia and Ripper games.

The rest of the newly-added formats are mostly those I found at discmaster.textfiles.com by searching for unknown files over several megabytes large (and filtering out corrupted samples, segments from the multi-part archives, etc). Despite discmaster not being updated anymore (you know whom to thank for the storage shortage), I’ve found enough to have another release in the future.

Meanwhile here are some short notes about some formats:

  • Elige Tu Muerte is extremely short but very FMV game: it’s a dozen of .mov files with animations plus 20kB .exe engine. You just click on one of four exits and 3D-rendered figure walks there to its demise (which should be obvious from the game title). The coding format is slightly more complex than normal RLE but still nothing to write a full post about;
  • Lords of the Realm VAS format is the one I halfway reverse-engineered from the files themselves and then found corresponding RLE decompression code in the binary specification to fill in the missing details. The main problem there is that it’s an overlay executable so some parts are not loaded by default and there are no references to the decompression functions;
  • Tie Break Tennis 98 intro file was reverse engineered from its contents because it was less effort than to manually load LE segment of the binary specification into Ghidra. After all it has just four opcodes (fill block, raw block, skip block, and palette) so guessing the whole structure was easy;
  • Gunmetal SBV gets another mention here by being the only wavelet video codec I’ve encountered in a game so far;
  • this time I had three formats that should’ve been video files in theory but turned out to be an archive of video and audio tracks in stand-alone formats, optionally with some commands telling how to play them. Those formats are AVI, SMS and Knowledge Adventure movie v3.

na_game_tool is available at the usual place in the usual format.

Now I can move to work on a different tool which would tackle a format that’s very widespread and extremely exotic at the same time.

Pride and downsides

September 4th, 2026

Late (and still great) Sir Pterry was a writer who wrote great footnotes as well as the books to contain them (name any other author who put a footnote even into the book title!). And while Thief of Time probably was not written for this particular footnote, it would’ve not been half as good without it:

Every society needs a cry like that, but only in a very few do they come out with the complete, unvarnished version, which is “Remember-the-Atrocity-Committed-Against-Us-Last-Time-That-Will-Excuse-the-Atrocity-That-We’re-About-to-Commit-Today! And So On! Hurrah!”

I think this describes the best the situation observed in this world as well: too many groups (from individuals to communities spanning many nations) think they were greatly wronged in the past and this excuses whatever they’re going to do. In the best case it’s merely against the perceived/appointed enemies, in the worst case it’s against everybody. Of course since those people think they’re right (or don’t think at all) they don’t want to understand that their enemies are likely to retaliate in the same way with the same reasoning.

The classic example would be Christianity with its usual claim about great persecutions during Diocletian times (not paying attention to how many religions were there and practiced legally while only a couple of them were forbidden—probably for being too peaceful). That apparently gave them right to pursue the competitors opponents in equally or even more cruel ways; and of course that has not stopped when neither the original opponents nor the Roman Empire were around.

Another classic example would be Israel. I whole-heartedly agree that Jews should not have been killed or persecuted just for being different (neither in 1938-1945 nor in other time periods) and they deserve their own state. What I don’t agree is that their tragedy gives them the right to behave in the same way as it was done unto them back in the day. Yet paradoxically enough currently Israel has an anti-Semitic government in both senses, hostile both to Palestinians and Jews except of very special sort (who don’t want to defend Israel by themselves). At least they’re not talking expanding their Lebensraum, otherwise the similarity would too much to bear. And no friendly country does not do much against it because of the unfortunate associations (even with a token ICC verdict against Netanyahu some European countries openly declared they won’t comply because it would be anti-Semitism). Mind you, I don’t have anything against the population itself beside the fact they elected this government (more than once) which may lead their country to destruction by pissing off allies and courting with enemies. But I’ll talk about USA a bit later.

Moving to Europe, there’s a Catholic version of Israel called Poland. Since most of the people do not have a reason to learn about it, here’s a short version: the golden years of it were when the Kingdom of Poland united with Grand Duchy of Lithuania forming Rzeczpospolita (essentially the word “republic” or “commonwealth” translated into Polish). With that union they got a lot of Ukrainian lands whose agricultural output was responsible for a good deal of Rzeczpospolita wealth. And yet, unlike Lithuanians, they treated Ukrainians badly for being of a different branch of Christianity (and maybe not having their own state). Eventually Ukrainians started an uprising, ending up with their own republic and dealing a mortal blow to Rzeczpospolita in a Pyrrhic victory—the weakened Poland was eventually conquered and split up between two European empires (Austro-Hungarian and German) and russia. Wiser people would’ve made some conclusions about tolerance and treating own population decently, Poles instead found no fault with them (because nobody does) and decided that it’s a martyrdom they have to bear because they’re special. So the next times they re-instated their republic it went the same way: mistreating non-Poles, suffering from the mistakes, only reinforcing them in their idea of martyr nation. And nowadays it looks like they’ve not learned anything, still holding 80-year old grudges against Ukrainians (because they dared to kill occupational Polish officers and settlers on Ukrainian territory) fuelling them into anti-Semitism level of hate. If you look you can see the news in any given week about Poles either beating Ukrainians for speaking Ukrainian (which sounds not that different from Polish BTW) or other Poles for mistaking them for Ukrainians. And those notions are instigated predominantly by their current president and the main opposition party who, unlike the government and many ordinary Poles, do not even formally condemn such behaviour.

And finally let’s talk about USA. It is hard to argue that they suffered any injustice beside being forced to pay taxes (some claim that taxes were rather the pretext and the real reason was prohibition of trade with French colonies from which rum distilleries in British colonies obtained cheap and abundant molasses; in either case it was about the money and unwillingness to give them away). So in order to be less ashamed about it they threw it some ideas about liberty and human rights in general (no slaves need apply) and started an uprising. Apparently this combination of being the first democratic republic (if you don’t count the ones appearing in Europe a century before) and reluctance to pay money gave them the main two pretexts for doing anything: being the missionaries of democracy (which compelled them to occupy various other lands at different times, democratic or not, as well as trying to annex Canada) and paying for something being a great offence. Or maybe rather “we could smuggle our greed under a pretence of higher moral ideals, we can do it again”. No wonder they spawn the ideologies like effective altruism (aka “I know better what to do with my money, don’t make me pay taxes”). I’ve started writing this post before the current USian president made a claim that he wants European countries to pay for the past military aid that Ukraine received for free before his term, but it’s definitely not against the trend. Timeo Danaos…

The sad thing those examples show is that such behaviour is not self-destructive (enough) and it can mutually subsist on the similar behaviour from the other side (think about the classic example of long-lasting blood feud from Romeo and Juliet Adventures of Huckleberry Finn) but its substrate (people infected with those ideas) will suffer even if they feel great and superior to everybody else. I’d recommend scepticism and clear thinking but I know that people don’t like to think in general, let alone about the things that would make them feel bad and less important.

Yet another FLI flavour

September 2nd, 2026

There’s an Argentinian game called La Mágica Aventura del Cine or (The Magical Movie Adventure in English language release) which has animations in ordinary and custom FLI format. The files are hidden inside large resource files along with .voc and other types with no obvious index (probably it is stored in accompanying .lod file which was not useful even after I uncompressed it). Anyway, custom FLIs have marker 0xAF66 with chunk types 110 (contiguous VGA palette) and 100 (LZ77-compressed frame). I’ve added support for it to na_game_tool but, like with Cross Racing Championship RoQ files, I won’t count it towards the total number of formats supported.

What’s curious is the compression scheme employed here. It is slightly more complex than classic LZSS since it has more modes of coding offset and length (8/13-bit offsets, 2/3/8/16-bit lengths). Nothing special but it looks almost the same as the compression employed in HNM except for one bit meaning inverted, LSB bitstream reading and large lengths handling. And like HNM there are two slightly different variants of the compression method used here as well: ordinary compressed files seem to use the version with 16-bit flags while frames (and some other, probably also image, formats) employ the version with 32-bit flags. I somewhat wonder if there was a widespread version of this particular compression format that got adapted by two different companies in the same way as LZSS.c from Haruhiko Okumura (which is so common that I often recognise the format even without looking at the binary specification).

In either case it’s time to move on, there are still two or three formats left to RE and implement for the na_game_tool release.

Knowledge Adventure movie v2/v3 done

August 31st, 2026

I’ve finally finished adding Knowledge Adventure movie v2/v3 support to na_game_tool—just a couple of formats more and I can make a release.

Meanwhile I want to talk about what I discovered.

First of all, the original format still looks too hard to implement, mostly because of its incomprehensible binary specification. With all known samples employing arithmetic coding if you get one thing wrong you won’t get any thing right.

Let’s jump to version 3. As it turned out, it is not a movie file per se but rather an archive containing interleaved chunks of version 2 movie format and optionally an audio track. It even stores the original file names in the header. What’s curious is that version 2 supports embedded audio track just fine.

So now the most interesting part left. Version 2 movies as I described in the previous post use static Huffman coding for multiple streams (like mode bytes, motion vector indices, colours and such). The main thing I didn’t understand back then was its pattern mode: apparently the decoder keeps track of two significant colours used by all blocks in the line (e.g. last column of the raw block, or last pixel of each motion-compensated sub-block, or two colours used in a pattern block) and may re-use them from a neighbouring block for a pattern fill.

There are also some other fun things, like older games using transposed images (i.e. it’s coded as columns in left-to-right mode) while newer games use bottom-to-top coding. And single images are often coded as a sequence of strips (e.g. first you have strip 132 pixels wide, next to it a strip 128 pixels wide and so on until the whole image is decoded).

Actually there are many feature flags in the play there, I’ve ended up implementing just the most common modes and giving up on more complex ones. At least it works on the majority of the files I tried (including the ones extracted from older and newer Knowledge Adventure archive formats—of course na_game_tool supports extracting from them now). The format will be documented shortly after the release (because it’s a thing I usually do when I have nothing better to do) so those willing to do it better will have both the code and the description to work from.

Meanwhile I’ll just chase another pair of some game codecs for completeness sake, make the release, and move to implementing a different multimedia tool…

SBV, an unusual game codec

August 24th, 2026

While I’m still preparing next na_game_tool release (still a couple of codecs to RE and implement!), I’ve finally encountered a very rare beast—wavelet game video codec!

Gunmetal features SBV format with the minimum header (frame table contains just timestamps and start offsets) but each of those frames is coded using fast wavelet coding algorithm. First level is transmitted as byte values, the other levels are coded in 4×4 or 8×8 blocks, one level after another, using fixed-bits non-zero coefficient coding (the number of bits depends on the block coding mode) plus some bit flags to code zero runs. (De)quantisation is done by simple shift operation. Wavelet looks like the traditional LGT 5/3.

One might think the scheme is truly scalable but unfortunately you have to decode data for one plane before you move to another. Speaking of planes it’s a simplified YUV-like scheme with
Y = ( R + G + B) / 3
Cr = (2R - G - B) / 3,
Cb = (2B - R - G) / 3

with the traditional 4:2:0 sub-sampling.

This could’ve been a simple intermediate video codec for the cases where you’re really strapped for CPU power but still want some compression. And yet it’s a game format instead… I’m still delighted to encounter such format in a game (and in general).

Again on Knowledge Adventure MOV

August 14th, 2026

While I have time I’m preparing the next release of na_game_tool, which involves REing formats (of course!). And among the formats I want to add is Knowledge Adventure MOV. So I’ve revisited it and RE’d one of the flavours.

Apparently there are three versions of that MOV: the original format used in DOS games (with magic KAMv), version 2 (starting with LzH2) and version 3 (starting with LzH3) which seem to be used in both DOS games and some Internet applications (and I’ve used Mac binary for Undersea Adventure). So while I’m yet to progress on KAMv (because there’s only 16-bit DOS binary specification for it), I’ve mostly REd LzH2 and it’s rather crazy.

This codec splits image into rows of 4×2 tiles and unless I’m mistaken those rows are coded in scalable way (first just one row, then two, then four, then eight and so on until the whole frame is decoded). Each tile may be coded as motion (with a set of motion vectors selectable in the file header—it gives me flashbacks of DiVX 3 Hi/Lo-motion), raw tiles, or pattern-coded tiles. And those pattern-coded tiles actually may code colours explicitly or use another motion vector to re-use some existing ones, that’s not something I’ve seen before. Afterwards all those kinds of data (tile types, colours, patterns, motion vector indices) are grouped and compressed with their own static Huffman codes; the tree descriptions (just code lengths as the symbols are always the same) are transmitted at the beginning of each frame.

Overall, it reminds me of Smacker if not for the fact it uses per-frame Huffman trees instead of global ones (and raw PCM instead of Huffman-compressed data), smaller tiles and more ingenious use of motion vectors. Now I want to implement a decoder for it even if just to see what I understand wrong.

A bit about Pälzisch Dialekt

August 4th, 2026

I semi-jokingly say that that Alsace deserves to be called Südpfalz since the cultural border there is not clear unlike the country borders. And I mentioned back in the day that a lot of places in central Rheinland-Pfalz (or Rheinland-Palatinate if you don’t recognise its proper name) sound even more French than those close to the border (no matter from which side—e.g. both have river Lauter and a town named after it, be it Lauterbourg or Lauterecken; and Hœrdt is on comparable distance from the border as Hördt). But recently I’ve seen something that made me even more suspicious about the influences.

There’s a small town not far from Mainz called Gau-Algesheim and it has rather peculiar variation of the local dialect. Here are two examples of it:

This is a bench installed in the town centre in the memory of one of its distinguished citizens. The words on that bench are “Weck, Worscht & Woi” which I believe map to the common German “WerkBrötchen, Wurst & Wein” (or “workbun, sausage and wine” auf Englisch). Side note: thanks for the commenter for the correction, I should’ve looked in the dictionary first.

And this is one of the billboards you can encounter there. There are others, featuring other picturesque sights of the town like Graulturm, but the motto remains the same on all of them. I really have no idea what the words “so charmant” may mean in the local dialect but you cannot convince me that they don’t sound suspiciously French.

Hopefully I was able to demonstrate my point that there’s something fishy going there. I’ll keep investigating the mysteries of the land (here’s another example: the centre of local shoe industry was in Pirmasens and yet the museum dedicated to it is located in Hauenstein instead—with a shoe stolen from Montabaur, which is a very long way from either of them), at least for my own amusement.

Micro Wavelet: done

July 24th, 2026

So I’ve finally implemented NeXT Micro Wavelet decoder (and updated git bundles on the site while at it) and the codec turned out to be even more interesting than on the first glance.

The codec itself consists of three distinct phases: using delta prediction along with wavelet transform, packing results into 16-bit opcodes, and further packing the opcodes with Huffman or LZSS compression. There’s also a raw mode which simply transmits 8-bit deltas so it’s not particularly interesting.

First stage is probably where the codec name comes from: it works on 2×2 pixel blocks that get transformed into the difference from the previous block means (for each component) plus vertical and horizontal differences between block pixels (the same pair is used for all block components). In other words, not exactly full wavelet transform but not exactly no wavelet transform either.

Then the deltas get quantised to a small set of pre-defined values (13 values for red and blue, 15 values for green, 5 values for horizontal and vertical differences) and get packed into a single 16-bit value (that’s merely 63375 combinations out of 65536 possible, which leaves room for special opcodes). Normally one opcode represents a set of packed deltas but in theory it can hold “skip next N blocks” opcodes though I’ve not encountered a file with those.

After we got those opcodes it’s time to pack them (or write them as is). It can be done either with static Huffman coding or with LZSS that operates on 16-bit symbols. Huffman tree definitions are stored in the codec extradata after the main decoder configuration (which deserves its own mention and should get it below) and usually define about two thousand most common symbols, the rest are accessible via the special escape symbol.

Since I’ve mentioned decoder configuration, it needs to be described for being rather special too. First of all, it is not stored in the usual place (codec descriptor atom) but rather in the user data atom on the top level of track atoms. I actually had to modify a demuxer to handle it properly (and discoverd this fact by chance while looking at the end of MOV file and seeing it being suspiciously similar to the file with the default Huffman tree definition). This decoder configuration actually consists of two parts: fixed-size decoder state (essentially RAM data dumped into the file) and Huffman tree definitions. And the decoder configuration is flexible. Remember what I said above about the delta packing into 16-bit symbols? Well, it’s extensible—you can have different number of quantisation levels and delta values to be defined for each component, I simply decided not to support such rich features and stick to the hard-coded delta sets and packing scheme.

Overall, this codec reminded me about Duck TrueMotion 1 for some reason, maybe because of its custom delta tables. All things considered, that’s probably the most exotic codec I’ve ever worked on since it combines both unconventional coding methods (micro wavelets packing into mini-words) and the fact it comes from the rather obscure OS (at least it was ordinary M68K code). I probably had encountered and shall encounter more of crazy coding approaches but it’s not likely to be this combination of obscure technical approach and the obscure platform. As always, I’ll be glad to be proven wrong.

Another weird format

July 17th, 2026

Just couple of years ago I had a small rant about German RLE-based codecs named *PEG. Recently I’ve discovered yet another pointless format called NPEG.

Unlike the rest it’s Polish, targets Amiga instead of DOS and it’s essentially MPEG-1 frames stored in IFF. Considering that it appeared around 1998, NP1 is the original MP4 format (if you ignore MPEG-1 in MOV of course).

Currently I have no desire to implement support of it but maybe one day I’ll really have nothing better to do and add MPEG-1 support (with various exotic containers) to NihAV. Though I hope such day will never come.