Merge pull request #2572 from xexyl/otterness-unob

Add unobfuscated alt code to 2020/otterness
This commit is contained in:
Landon Curt Noll authored and GitHub committed 2024-07-15 15:35:44 -07:00
commit 8cd567e700
14 files changed
+411 -4

No files matched your search

+16
View File
@@ -33,6 +33,14 @@
"display_via_github" : true,
"entry_text" : "original source code"
},
{
"file_path" : "try.alt.sh",
"inventory_order" : 100,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "script to try alternate code"
},
{
"file_path" : "try.sh",
"inventory_order" : 100,
@@ -41,6 +49,14 @@
"display_via_github" : true,
"entry_text" : "script to try entry"
},
{
"file_path" : "prog.alt.c",
"inventory_order" : 120,
"OK_to_edit" : true,
"display_as" : "c",
"display_via_github" : true,
"entry_text" : "unobfuscated source code"
},
{
"file_path" : "cvikl.mid",
"inventory_order" : 150,
+1
View File
@@ -6,6 +6,7 @@ indent
indent.c
indent.o
prog
prog.alt
prog.orig
!cvikl.mid
!entertainer.mid
+5 -2
View File
@@ -115,8 +115,8 @@ OBJ= ${PROG}.o
DATA=
TARGET= ${PROG}
#
ALT_OBJ=
ALT_TARGET=
ALT_OBJ= ${PROG}.alt.o
ALT_TARGET= ${PROG}.alt
#################
@@ -139,6 +139,9 @@ ${PROG}: ${PROG}.c
alt: data ${ALT_TARGET}
@${TRUE}
${PROG}.alt: ${PROG}.alt.c
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS}
# data files
#
data: ${DATA}
+41
View File
@@ -4,6 +4,9 @@
make
```
There is an unobfuscated version for those who wish to see the original final
prior to obfuscation. See [Alternate code](#alternate-code) below.
### Bugs and (Mis)features:
@@ -33,6 +36,37 @@ Now play `output.mid` and `output2.mid` in an audio player that can play MIDI
files.
## Alternate code:
### NOTICE to those who wish for a greater challenge:
**If you want a greater challenge, don't check this version**:
just try to understand the program via the entry source.
If you get stuck, come back and take a look at the alternate, unobfuscated code,
described by the author as:
> If you're curious about the un-obfuscated program that I originally wrote,
this was the final working version. I tried to keep the functions names and
comments understandable, but it will make a lot more sense to readers familiar
with the MIDI "SMF" file format.
... at their [web page about the
entry](https://www.nathanotterness.com/2021/04/obfuscated_c_2020.html).
## Alternate use:
Use `prog.alt` as you would `prog`.
### Alternate try:
``` <!---sh-->
./try.alt.sh
```
## Judges' remarks:
In an entry that boasts not using literals, one would expect to see
@@ -105,6 +139,13 @@ especially true for "live performance" .mid files.
correctly parse, but I have rarely seen this in practice. The largest
cause of program failures, in my experience, has been Limitation 2.
### NOTICE to those who wish for a greater challenge:
**If you want a greater challenge, don't read any further**:
just try to understand the program via the source.
If you get stuck, come back and read below for additional hints and information.
#### Obfuscation notes
+22
View File
@@ -409,6 +409,8 @@ Location: <a href="../../location.html#US">US</a> - <em>United States of America
<!-- BEFORE: 1st line of markdown file: 2020/otterness/README.md -->
<h2 id="to-build">To build:</h2>
<pre><code> make</code></pre>
<p>There is an unobfuscated version for those who wish to see the original final
prior to obfuscation. See <a href="#alternate-code">Alternate code</a> below.</p>
<h3 id="bugs-and-misfeatures">Bugs and (Mis)features:</h3>
<p>The current status of this entry is:</p>
<pre><code> STATUS: INABIAF - please DO NOT fix</code></pre>
@@ -419,6 +421,24 @@ Location: <a href="../../location.html#US">US</a> - <em>United States of America
<pre><code> ./try.sh</code></pre>
<p>Now play <code>output.mid</code> and <code>output2.mid</code> in an audio player that can play MIDI
files.</p>
<h2 id="alternate-code">Alternate code:</h2>
<h3 id="notice-to-those-who-wish-for-a-greater-challenge">NOTICE to those who wish for a greater challenge:</h3>
<p><strong>If you want a greater challenge, don’t check this version</strong>:
just try to understand the program via the entry source.</p>
<p>If you get stuck, come back and take a look at the alternate, unobfuscated code,
described by the author as:</p>
<blockquote>
<p>If you’re curious about the un-obfuscated program that I originally wrote,
this was the final working version. I tried to keep the functions names and
comments understandable, but it will make a lot more sense to readers familiar
with the MIDI “SMF” file format.</p>
</blockquote>
<p>… at their <a href="https://www.nathanotterness.com/2021/04/obfuscated_c_2020.html">web page about the
entry</a>.</p>
<h2 id="alternate-use">Alternate use:</h2>
<p>Use <code>prog.alt</code> as you would <code>prog</code>.</p>
<h3 id="alternate-try">Alternate try:</h3>
<pre><code> ./try.alt.sh</code></pre>
<h2 id="judges-remarks">Judges’ remarks:</h2>
<p>In an entry that boasts not using literals, one would expect to see
straightforward ways to produce small integers like <code>!(x^x)&lt;&lt;!(x^x)</code>, etc. but
@@ -537,7 +557,9 @@ very thoroughly).</li>
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/prog.c">prog.c</a> - entry source code</li>
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/Makefile">Makefile</a> - entry Makefile</li>
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/prog.orig.c">prog.orig.c</a> - original source code</li>
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.alt.sh">try.alt.sh</a> - script to try alternate code</li>
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.sh">try.sh</a> - script to try entry</li>
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/prog.alt.c">prog.alt.c</a> - unobfuscated source code</li>
<li><a href="cvikl.mid">cvikl.mid</a> - sample MIDI file</li>
<li><a href="entertainer.mid">entertainer.mid</a> - sample MIDI file</li>
</ul>
+284
View File
@@ -0,0 +1,284 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
uint16_t ReadBigEndian16(uint8_t *c) {
return *(c + 1) | (uint16_t) (*c) << 8;
}
void WriteBigEndian16(uint8_t *c, uint16_t v) {
c[1] = v;
c[0] = v >> 8;
}
uint32_t ReadBigEndian32(uint8_t *c) {
return (uint32_t) ReadBigEndian16(c) << 16 | ReadBigEndian16(c + 2);
}
void WriteBigEndian32(uint8_t *c, uint32_t v) {
WriteBigEndian16(c + 2, v);
WriteBigEndian16(c, v >> 16);
}
// Fills in the *value. Returns the length in bytes.
int ReadVarInt(uint8_t *content, uint32_t *value) {
int i;
uint8_t b;
*value = 0;
for (i = 0; i < 4; i++) {
b = content[i];
*value |= b & 0x7f;
if (!(b & 0x80)) return i + 1;
*value = *value << 7;
}
fprintf(stderr, "Bad variable int.\n");
exit(1);
}
uint8_t HighestBit(uint32_t n) {
uint8_t r = 1;
if (!n) return 0;
while (n >>= 1) r++;
return r;
}
uint8_t VarIntBytes(uint32_t n) {
uint8_t bits = HighestBit(n);
return bits / 7 + !!(bits % 7);
}
int WriteVarInt(uint32_t n, uint8_t *c) {
uint8_t bytes_needed = VarIntBytes(n);
*c = 0;
if (!n) return bytes_needed;
if (bytes_needed > 4) {
fprintf(stderr, "Int too big for MIDI.\n");
exit(1);
}
c += bytes_needed - 1;
while (n != 0) {
*c = n & 0x7f;
n = n >> 7;
c--;
}
return bytes_needed;
}
// Advances past the next MIDI message, returning a pointer after it, and
// updating running status if necessary.
uint8_t* AdvancePastMessage(uint8_t *c, uint8_t *running_status) {
uint32_t tmp;
uint8_t b;
switch (*c) {
case 0xf0:
case 0xf7:
// Skip past system exclusive messages
*running_status = 0;
c++;
c += ReadVarInt(c, &tmp);
return c + tmp;
case 0xff:
// Skip past meta events
*running_status = 0;
c++;
c++;
c += ReadVarInt(c, &tmp);
return c + tmp;
}
// We're assuming this is a channel voice message now.
if (*c & 0x80) {
// Advance past the new status byte.
b = *c;
c++;
*running_status = b;
} else {
b = *running_status;
}
// Just test the different channel voice message types.
switch (b >> 4) {
case 8:
case 9:
case 10:
case 11:
case 14:
return c + 2;
case 12:
case 13:
return c + 1;
}
fprintf(stderr, "Bad message status byte: %x\n", b);
exit(1);
return c;
}
// Assumes we're pointing at the start of a MTrk. Returns a pointer to the
// start of the next track.
uint8_t* GetTrackTicks(uint8_t *c, uint32_t *ticks) {
uint32_t length, tmp;
uint8_t *end;
uint8_t running_status = 0;
*ticks = 0;
if (c[3] != 'k') {
fprintf(stderr, "Not at a track start.\n");
exit(1);
}
length = ReadBigEndian32(c + 4);
c += 8;
end = c + length;
while (c < end) {
c += ReadVarInt(c, &tmp);
*ticks += tmp;
c = AdvancePastMessage(c, &running_status);
}
return c;
}
// Requires a pointer to the start of the first track, and the total number of
// tracks.
uint32_t GetHighestTrackTicks(uint8_t *c, int track_count) {
uint32_t tmp, max = 0;
int i;
for (i = 0; i < track_count; i++) {
c = GetTrackTicks(c, &tmp);
fprintf(stderr, "Track %d: %u ticks\n", i, (unsigned) tmp);
if (tmp > max) max = tmp;
}
return max;
}
void DumpHex(uint8_t *data, int size) {
int i;
for (i = 0; i < size; i++) {
fprintf(stderr, "%p + %d: 0x%02x\n", data, i, data[i]);
}
}
uint8_t *beat = NULL;
uint8_t *note_off_note = NULL;
// Writes a beat at the given offset. Requires the beat size.
uint8_t* WriteBeat(uint8_t *c, int i, int bs) {
uint8_t n = 42, v = 80;
if ((i % 4) == 0) {
n = 36;
v = 120;
} else if ((i % 4) == 2) {
n = 40;
v = 100;
}
beat[1] = n;
beat[2] = v;
*note_off_note = n;
memcpy(c, beat, bs);
return c + bs;
}
void WriteBootsAndCats(uint8_t *c, uint32_t length) {
uint16_t ticks_per_beat, track_count;
uint32_t beats_to_generate, tmp, data_size, beat_size;
uint8_t *cur, *data = NULL;
track_count = ReadBigEndian16(c + 10);
ticks_per_beat = ReadBigEndian16(c + 12) >> 1;
if (ticks_per_beat >> 15) {
fprintf(stderr, "SMPTE timing isn't supported\n");
exit(1);
}
beats_to_generate = GetHighestTrackTicks(c + 14, track_count) / ticks_per_beat;
// A "beat" is simply a note-on followed by a note-off event. The tricky part
// is the delta time may be more than one byte. We'll assume running status.
// Note on = 00 <note> <velocity>
// Note off = <delta time> <note> 00
beat_size = 5 + VarIntBytes(ticks_per_beat);
beat = malloc(beat_size);
if (!beat) {
fprintf(stderr, "Failed allocating beat.\n");
exit(1);
}
// This requires 8 bytes in the track header + 4 bytes for end-of-track +
// the track data, plus an additional byte to set up running status in the
// first beat.
data_size = beats_to_generate * beat_size + 13;
data = malloc(data_size);
if (!data) {
fprintf(stderr, "Failed allocating data.\n");
exit(1);
}
fprintf(stderr, "Data size: %d (0x%x), beat size %d, # beats %d\n",
(int) data_size, data_size, beat_size, beats_to_generate);
memcpy(data, "MTrk", 4);
WriteBigEndian32(data + 4, data_size - 8);
fprintf(stderr, "Data size: %d\n", (int) data_size);
// Build the "beat" data
cur = beat;
*cur++ = 0;
// Initial note number and velocity.
*cur++ = 36;
*cur++ = 120;
cur += WriteVarInt(ticks_per_beat, cur);
// Keep a pointer to where to write the note to turn off
note_off_note = cur;
*cur++ = 36;
// The note-off velocity is 0.
*cur = 0;
cur = data + 8;
// Write the first note-on and off:
*cur++ = 0;
*cur++ = 0x99;
memcpy(cur, beat + 1, beat_size - 1);
cur += beat_size - 1;
for (tmp = 1; tmp < beats_to_generate; tmp++) {
cur = WriteBeat(cur, tmp, beat_size);
}
*cur++ = 0;
*cur++ = 0xff;
*cur++ = 0x2f;
*cur = 0;
// Update the original MIDI header to increment the track count and make sure
// the format is 1.
c[9] = 1;
WriteBigEndian16(c + 10, track_count + 1);
fwrite(c, length, 1, stdout);
fwrite(data, data_size, 1, stdout);
}
int main(int argc, char **argv) {
FILE *f = NULL;
uint8_t *content = NULL;
long size = 0;
int result;
if (argc != 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return 1;
}
f = fopen(argv[1], "rb");
if (!f) {
fprintf(stderr, "Coudn't open %s\n", argv[1]);
return 1;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
content = malloc(size);
if (!content) {
fprintf(stderr, "Couldn't allocate content buffer.\n");
fclose(f);
return 1;
}
result = fread(content, size, 1, f);
fclose(f);
if (result != 1) {
fprintf(stderr, "Couldn't read %s.\n", argv[1]);
free(content);
return 1;
}
if ((content[3] != 'd') || (content[7] != 6)) {
fprintf(stderr, "Bad MIDI file.\n");
free(content);
return 1;
}
WriteBootsAndCats(content, size);
free(content);
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
#
# try.sh - demonstrate IOCCC entry 2020/otterness alt code
#
# make sure CC is set so that when we do make CC="$CC" it isn't empty. Doing it
# this way allows us to have the user specify a different compiler in an easy
# way.
[[ -z "$CC" || ! -f "$CC" || ! -x "$CC" ]] && CC="cc"
make CC="$CC" alt >/dev/null || exit 1
# clear screen after compilation so that only the entry is shown
clear
read -r -n 1 -p "Press any key to run: ./prog.alt < cvikl.mid > output.mid: "
echo 1>&2
./prog.alt < cvikl.mid > output.mid
echo "Now play output.wav in an audio player that can play MIDI files." 1>&2
echo 1>&2
read -r -n 1 -p "Press any key to run: ./prog.alt < entertainer.mid > output2.mid: "
echo 1>&2
./prog.alt < entertainer.mid > output2.mid
echo "Now play output2.wav in an audio player that can play MIDI files." 1>&2
echo 1>&2
+4 -1
View File
@@ -4659,7 +4659,10 @@ Tolkien</a>.</p>
<a href="2020/otterness/entertainer.mid">entertainer.mid</a> from the URLs we suggested so
that one need not download them and to make sure they can always be obtained
even if the domain or link goes dead.</p>
<p>Cody also added the <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.sh">try.sh</a> script.</p>
<p>Cody also added the <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.sh">try.sh</a> script and the
<a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/try.alt.sh">try.alt.sh</a> script for the author’s
unobfuscated version that Cody added as
<a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/otterness/prog.alt.c">prog.alt.c</a>.</p>
<div id="2020_tsoj">
<h2 id="winning-entry-2020tsoj">Winning entry: <a href="2020/tsoj/index.html">2020/tsoj</a></h2>
<h3 id="winning-entry-source-code-prog.c-62">Winning entry source code: <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/2020/tsoj//prog.c">prog.c</a></h3>
+4 -1
View File
@@ -6038,7 +6038,10 @@ Tolkien](https://www.tolkienestate.com/life/biography/).
that one need not download them and to make sure they can always be obtained
even if the domain or link goes dead.
Cody also added the [try.sh](%%REPO_URL%%/2020/otterness/try.sh) script.
Cody also added the [try.sh](%%REPO_URL%%/2020/otterness/try.sh) script and the
[try.alt.sh](%%REPO_URL%%/2020/otterness/try.alt.sh) script for the author's
unobfuscated version that Cody added as
[prog.alt.c](%%REPO_URL%%/2020/otterness/prog.alt.c).
<div id="2020_tsoj">
+2
View File
@@ -4319,7 +4319,9 @@
2020,otterness,prog.c,20,true,c,true,entry source code
2020,otterness,Makefile,30,true,makefile,true,entry Makefile
2020,otterness,prog.orig.c,50,false,c,true,original source code
2020,otterness,try.alt.sh,100,true,shellscript,true,script to try alternate code
2020,otterness,try.sh,100,true,shellscript,true,script to try entry
2020,otterness,prog.alt.c,120,true,c,true,unobfuscated source code
2020,otterness,cvikl.mid,150,true,midi,false,sample MIDI file
2020,otterness,entertainer.mid,159,true,midi,false,sample MIDI file
2020,otterness,2020_otterness.tar.bz2,1415926535,false,tbz2,false,download entry tarball
1 # year dir file_path inventory_order OK_to_edit display_as display_via_github entry_text
4319 2020 otterness prog.c 20 true c true entry source code
4320 2020 otterness Makefile 30 true makefile true entry Makefile
4321 2020 otterness prog.orig.c 50 false c true original source code
4322 2020 otterness try.alt.sh 100 true shellscript true script to try alternate code
4323 2020 otterness try.sh 100 true shellscript true script to try entry
4324 2020 otterness prog.alt.c 120 true c true unobfuscated source code
4325 2020 otterness cvikl.mid 150 true midi false sample MIDI file
4326 2020 otterness entertainer.mid 159 true midi false sample MIDI file
4327 2020 otterness 2020_otterness.tar.bz2 1415926535 false tbz2 false download entry tarball
Binary file not shown.
+2
View File
@@ -4324,8 +4324,10 @@
2020/otterness/cvikl.mid
2020/otterness/entertainer.mid
2020/otterness/index.html
2020/otterness/prog.alt.c
2020/otterness/prog.c
2020/otterness/prog.orig.c
2020/otterness/try.alt.sh
2020/otterness/try.sh
2020/tsoj/.entry.json
2020/tsoj/.gitignore
+2
View File
@@ -4324,8 +4324,10 @@
2020/otterness/cvikl.mid
2020/otterness/entertainer.mid
2020/otterness/index.html
2020/otterness/prog.alt.c
2020/otterness/prog.c
2020/otterness/prog.orig.c
2020/otterness/try.alt.sh
2020/otterness/try.sh
2020/tsoj/.entry.json
2020/tsoj/.gitignore
+2
View File
@@ -3091,7 +3091,9 @@
2020/otterness/README.md
2020/otterness/cvikl.mid
2020/otterness/entertainer.mid
2020/otterness/prog.alt.c
2020/otterness/prog.c
2020/otterness/try.alt.sh
2020/otterness/try.sh
2020/tsoj/.entry.json
2020/tsoj/.gitignore