<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>Tilman Sauerbeck's non-blog and stuff</title>
		<description/>
		<link>http://code-monkey.de/</link>
		<language>en-us</language>
		<ttl>40</ttl>
<item>
	<title>Decoding yEnc one word at a time</title>
	<guid>http://code-monkey.de/articles/2013/03/06/decoding-yenc-one-word-at-a-time</guid>
	<pubDate>Wed, 06 Mar 2013 17:22:49 +0000</pubDate>
	<link>http://code-monkey.de/articles/2013/03/06/decoding-yenc-one-word-at-a-time</link>
	<category>yenc</category>
	<description>
&lt;p&gt;Some weeks ago I have been trying to figure out how to decode &lt;a href="http://yenc.org"&gt;yEnc&lt;/a&gt;-encoded files one word at a time since decoding them byte-by-byte is both slow and lame ;)&lt;/p&gt;
&lt;p&gt;Let's first look at how the naive implementation of a yEnc decoder looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uint8_t input[...]; // Input bytes, NUL terminated.
uint8_t output[...]; // Output bytes
uint8_t escape = 0x3d;
int i = 0, j = 0;

while (input[i]) {
    uint8_t c = input[i++];

    // Escape character?
    if (c == escape)
        c = input[i++] - 64;

    output[j++] = c - 42;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is what I've come up with. Note that this code only works if 0x3d itself is never escaped, ie there will be no pairs 3d3d in the input stream. Thus we will have at most two escaped bytes per word. Yes, this is cheating, but it seems to work well enough with the encoders that are in commong use today.&lt;/p&gt;
&lt;p&gt;On the ARMv5 CPU powering my GuruPlug, this code is ~10% faster than the naive approach.&lt;/p&gt;
&lt;p&gt;So here's the (optimized) code. The explanations in there aren't nearly as good as they should be, but they are all you'll get for now ;p&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void decode_line()
{
    uint8_t input[...];
    uint8_t output[...];
    size_t length = number of input bytes to process;

    /* Align to a multiple of 4. */
    size_t orig_length = length;
    length = (length + 3) &amp;amp; ~3;
    ssize_t faked = length - orig_length;

    uint32_t state = 0;
    uint32_t *wp = (uint32_t *) input;
    int j = 0;

    for (; length; length -= 4) {
        uint32_t word = *wp++;
        uint32_t decoded, ndecoded;

        decoded = decode (&amp;amp;state, word, &amp;amp;ndecoded);

        output[j++] = decoded;

        decoded &amp;gt;&amp;gt;= 8;
        output[j++] = decoded;

        ndecoded--;

        if (--ndecoded) {
            decoded &amp;gt;&amp;gt;= 8;
            output[j++] = decoded;

            if (--ndecoded) {
                decoded &amp;gt;&amp;gt;= 8;
                output[j++] = decoded;
            }
        }
    }

    /* We cheated before when we aligned 'length'.
     * Adjust for that now, so j will contain the
     * actual number of output bytes written.
     */
    j -= faked;
}

/**
 * @param state Used to remember whether the first byte was meant to be escaped.
 * @param word The word to decode.
 * @param ndecoded Will store the number of decoded bytes (ranging from 2 to 4).
 * @return The decoded word.
 */
uint32_t decode (uint32_t *state, uint32_t word, uint32_t *ndecoded)
{
    uint32_t b64 = *state &amp;gt;&amp;gt; 25;
    uint32_t add_magic = 0xd6d6d6d6 &amp;amp; ~b64; /* 256 - 42 = 214 = 0xd6 */
    uint32_t mask, result;

    /* Find the 0x3d bytes. */
    mask = find_eq (word | b64);

    /* From the mask, we can deduce how many bytes we will decode. */
    *ndecoded = count00 (mask);

    /* Perform the actual decoding.
     * Since we need to apply the offset to the bytes _following_ the
     * escape bytes, we're shifting the mask.
     *
     * We're using add instead of sub because the former needs
     * fewer instructions in ARM machine code.
     */
    result = add (word, add_magic &amp;amp; ~(mask &amp;lt;&amp;lt; 7));

    /* Check for MSB to see if we had 0x3d in the leftmost byte. */
    *state = mask;

    /* Kick out bytes that originated from 0x3d. */
    return compress (result, mask);
}

/* Turns bytes that are 0x3d in x into 0x80 and all others into 0x00
 * (known as the Mycroft test).
 */
static inline uint32_t
find_eq (uint32_t x)
{
    x ^= 0x3d3d3d3d;

    return (x - 0x01010101) &amp;amp; ~x &amp;amp; 0x80808080;
}

/* Multibyte add, from Hacker's Delight. */
uint32_t add (uint32_t x, uint32_t y)
{
    uint32_t a, b;

    a = (x &amp;amp; 0x7f7f7f7f) + (y &amp;amp; 0x7f7f7f7f);
    b = (x ^ y) &amp;amp; ~0x7f7f7f7f;

    return a ^ b;
}

/* Exchange bits m in x that are k bits apart
 * (from Hacker's Delight).
 */
uint32_t exch (uint32_t x, uint32_t m, uint32_t k)
{
    uint32_t t = (x ^ (x &amp;gt;&amp;gt; k)) &amp;amp; m;

    return x ^ t ^ (t &amp;lt;&amp;lt; k);
}

uint32_t compress (uint32_t x, uint32_t m)
{
    if (m) {
        x = exch (x, 0x0000ff, (m &amp;amp; 0x008000) &amp;gt;&amp;gt; 12);
        x = exch (x, 0xff0000, (m &amp;amp; 0x800000) &amp;gt;&amp;gt; 20);

        if (m &amp;amp; 0x008080)
            x &amp;gt;&amp;gt;= 8;
    }

    return x;
}

/* Count number of zero bytes in x. */
uint32_t count00 (uint32_t x)
{
    /* In x, zero bytes are the bytes that were !0x3d
     * in the input word.
     * We know there can be at most two 0x3d bytes,
     * thus we will have 2-4 zero bytes in x.
     */
    uint32_t count = 4;

    if (x)
        count--;

    x = x &amp;amp; (x - 1);

    if (x)
        count--;

    return count;
}
&lt;/code&gt;&lt;/pre&gt;
	</description>
</item>
<item>
	<title>Thinking about buying a GuruPlug?</title>
	<guid>http://code-monkey.de/articles/2010/05/27/thinking-about-buying-a-guruplug</guid>
	<pubDate>Thu, 27 May 2010 19:52:35 +0000</pubDate>
	<link>http://code-monkey.de/articles/2010/05/27/thinking-about-buying-a-guruplug</link>
	<category>guruplug</category>
	<description>
&lt;p&gt;In case you're considering to buy a &lt;a href="http://www.globalscaletechnologies.com/t-guruplugdetails.aspx"&gt;GuruPlug&lt;/a&gt;, you should read about the &lt;a href="http://plugcomputer.org/plugforum/index.php?topic=1735.0"&gt;heat problems&lt;/a&gt; that cause random &lt;a href="http://plugcomputer.org/plugforum/index.php?topic=1650.0"&gt;reboots&lt;/a&gt; and possibly &lt;a href="http://plugcomputer.org/plugforum/index.php?topic=1734.0"&gt;hardware death&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Right now it looks like you need to open up the device and swap the internal power supply for an external one or add more heatsinks or somesuch :(&lt;/p&gt;
	</description>
</item>
<item>
	<title>Multi-scrobbling at last!</title>
	<guid>http://code-monkey.de/articles/2009/12/30/multi-scrobbling-at-last</guid>
	<pubDate>Wed, 30 Dec 2009 17:15:24 +0000</pubDate>
	<link>http://code-monkey.de/articles/2009/12/30/multi-scrobbling-at-last</link>
	<category>xmms2</category>
	<category>xmms2-scrobbler</category>
	<description>
&lt;p&gt;New &lt;a href="http://code-monkey.de/pages/xmms2-scrobbler"&gt;XMMS2-Scrobbler&lt;/a&gt; release. Better than ever: multi-scrobbling is supported now. libre.fm users rejoice! See README for the details.&lt;/p&gt;
	</description>
</item>
<item>
	<title>XMMS2-Scrobbler 0.3.0 released</title>
	<guid>http://code-monkey.de/articles/2009/05/10/xmms2-scrobbler-0-3-0-released</guid>
	<pubDate>Sun, 10 May 2009 12:15:05 +0000</pubDate>
	<link>http://code-monkey.de/articles/2009/05/10/xmms2-scrobbler-0-3-0-released</link>
	<category>xmms2</category>
	<category>xmms2-scrobbler</category>
	<description>
&lt;p&gt;So here's an &lt;a href="http://code-monkey.de/pages/xmms2-scrobbler"&gt;XMMS2-Scrobbler&lt;/a&gt; release that will work with the recently released DrMattDestruction. This new version is witten in C instead of Ruby (so it's much less memory hungry) and includes support for last.fm's now-playing notifications.&lt;/p&gt;
	</description>
</item>
<item>
	<title>A decoder for Archimedean Dynasty's MVI files</title>
	<guid>http://code-monkey.de/articles/2008/12/12/a-decoder-for-archimedean-dynastys-mvi-files</guid>
	<pubDate>Fri, 12 Dec 2008 19:19:56 +0000</pubDate>
	<link>http://code-monkey.de/articles/2008/12/12/a-decoder-for-archimedean-dynastys-mvi-files</link>
	<category>archimedean_dynasty</category>
	<description>
&lt;p&gt;Earlier this year, I poked at some of the file formats used by Archimedean Dynasty (released as Schleichfahrt in Germany). Some of the easy ones are documented on the &lt;a href="http://projectaqua.sourceforge.net/cgi-bin/wiki.pl?SfFileFormats"&gt;ProjectAqua wiki&lt;/a&gt; but they are missing information on the movie files (MVI) used by the game. So in February/March I spent several weeks figuring out that MVI format, and I wrote a &lt;a href="http://files.code-monkey.de/archimedean_dynasty_mvi_decoder.tar.gz"&gt;prototype decoder in Ruby&lt;/a&gt;. I'm writing about it mostly so people can find it using Google.&lt;/p&gt;
	</description>
</item>
<item>
	<title>XMMS2-Scrobbler 0.2.1</title>
	<guid>http://code-monkey.de/articles/2008/04/18/xmms2-scrobbler-0-2-1</guid>
	<pubDate>Fri, 18 Apr 2008 13:00:36 +0000</pubDate>
	<link>http://code-monkey.de/articles/2008/04/18/xmms2-scrobbler-0-2-1</link>
	<category>xmms2</category>
	<category>xmms2-scrobbler</category>
	<description>
&lt;p&gt;New &lt;a href="http://code-monkey.de/pages/xmms2-scrobbler"&gt;XMMS2-Scrobbler&lt;/a&gt;. Thanks to &lt;a href="http://perldition.org"&gt;rafl&lt;/a&gt;, the lock file issues should be gone now.&lt;/p&gt;
	</description>
</item>
<item>
	<title>XMMS2-Scrobbler 0.2.0</title>
	<guid>http://code-monkey.de/articles/2007/10/18/xmms2-scrobbler-0-2-0</guid>
	<pubDate>Thu, 18 Oct 2007 19:32:11 +0000</pubDate>
	<link>http://code-monkey.de/articles/2007/10/18/xmms2-scrobbler-0-2-0</link>
	<category>xmms2</category>
	<category>xmms2-scrobbler</category>
	<description>
&lt;p&gt;Last week I updated &lt;a href="http://code-monkey.de/pages/xmms2-scrobbler"&gt;XMMS2-Scrobbler&lt;/a&gt; to the latest version of the AudioScrobbler protocol. Their guidelines on when to submit a song that has been played have been simplified a bit, which also means that I could kill some of my code. Otherwise the protocol changes aren't that exciting for XMMS2 users IMO. The other new thing is "now playing" notifications.&lt;/p&gt;
&lt;p&gt;So: &lt;a href="http://code-monkey.de/pages/xmms2-scrobbler"&gt;XMMS2-Scrobbler 0.2.0&lt;/a&gt;.&lt;/p&gt;
	</description>
</item>
<item>
	<title>New GnuPG key</title>
	<guid>http://code-monkey.de/articles/2007/09/29/new-gnupg-key</guid>
	<pubDate>Sat, 29 Sep 2007 10:40:11 +0000</pubDate>
	<link>http://code-monkey.de/articles/2007/09/29/new-gnupg-key</link>
	<category>code-monkey.de</category>
	<description>
&lt;p&gt;I had to create a new GnuPG key, because the old one expired today.&lt;/p&gt;
&lt;p&gt;Grab the &lt;a href="http://files.code-monkey.de/tsauerbeck-public-key.asc"&gt;new public key&lt;/a&gt;, the fingerprint is E3B5 FB50 70F3 376F 53C9  9957 EADC 791F 5E58 7462.&lt;/p&gt;
	</description>
</item>
<item>
	<title>Embrace 0.1.0</title>
	<guid>http://code-monkey.de/articles/2007/08/27/embrace-0-1-0</guid>
	<pubDate>Mon, 27 Aug 2007 18:51:46 +0000</pubDate>
	<link>http://code-monkey.de/articles/2007/08/27/embrace-0-1-0</link>
	<category>embrace</category>
	<description>
&lt;p&gt;So I finally decided to make a tarball of &lt;a href="http://code-monkey.de/pages/embrace"&gt;Embrace2&lt;/a&gt; and call it v0.1.0. Embrace2 is an IMAP mailbox checker/monitor (a la biff) with some eye candy, based on the &lt;a href="http://enlightenment.org"&gt;EFL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This one is more usable than 0.0.x (cause it only shows the mailboxes that carry new mail, which is probably what you're interested in). It's also cuter, since it has nice animations for incoming new mail etc.&lt;/p&gt;
&lt;p&gt;This has been rotting unreleased on my hdd for a long time now, but I think there might be some people who find a use for it. The &lt;a href="http://code-monkey.de/pages/embrace"&gt;screenshot&lt;/a&gt; doesn't really do it justice, but my stupid screen capture program doesn't work with ARGB windows, which makes it look silly. So no AVI today.&lt;/p&gt;
	</description>
</item>
<item>
	<title>MGA status update</title>
	<guid>http://code-monkey.de/articles/2007/08/11/mga-status-update</guid>
	<pubDate>Sat, 11 Aug 2007 08:02:38 +0000</pubDate>
	<link>http://code-monkey.de/articles/2007/08/11/mga-status-update</link>
	<category>xorg</category>
	<category>mga</category>
	<description>
&lt;p&gt;Now that this craptastic blog thing is working again it's time for an mga status update \o/&lt;/p&gt;
&lt;p&gt;The randr-1.2 branch is in a nice state. Last week idr told me how to do output detection with the vbios' PInS block, so now the driver automatically creates the output objects corresponding to the hardware. This makes the driver usable without having to edit the source code \o/&lt;/p&gt;
&lt;p&gt;I tested all of my cards with that output detection code, and almost all of them passed. The one that didn't is my G450 DVI, which has a single DVI connector. Unsurprisingly the PInS data says exactly that. However, I got the card with a DVI -&amp;gt; 2 * VGA adapter cable. If that cable is plugged in, we want to have two VGA outputs instead. So it looks like I'll really have to make it possible to override output detection in xorg.conf :/&lt;/p&gt;
&lt;p&gt;The G550 dual dvi still has the same stupid problems as always. Another big issue is hardware cursor support. The problem is that Matrox' G series cards only have one hardware cursor, which is tied to CRTC1. For the 2nd CRTC, there's no hardware cursor. Unfortunately, the randr 1.2 API for hardware cursors works correctly only if every CRTC has a hardware cursor, so we can't use it (yet).&lt;/p&gt;
&lt;p&gt;I've also done some EXA work--it seems that most (all?) of my previous tests were flawed. I think that EXA's pixmap migration caused EXA not calling into the MGA code for all operations. A few days ago I told it to always migrate pixmaps from system to video RAM and vice versa, and voila, GTK+ apps were unusable because all those nice Over blends that it does were fucked up. Anyway, I managed to fix that. Doing full rendercheck runs on G450 and G550 then revealed that the A8 writes problem isn't fixed at all. Previously I thought that only Add operations on A8 textures were b0rked, but it turns out that all A8 writes are broken. On both the G450 and G550. Bogus tests ftw \o/&lt;/p&gt;
	</description>
</item>
	</channel>
</rss>