#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
uint8_t ulaw_encode(int16_t audio);
void print_byte(FILE *out, uint8_t b);
void filename2samplename(void);
uint32_t padding(uint32_t length, uint32_t block);
uint8_t read_uint8(FILE *in);
int16_t read_int16(FILE *in);
uint32_t read_uint32(FILE *in);
void die(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
// WAV file format:
// http://w...content-available-to-author-only...l.ca/Documents/AudioFormats/WAVE/WAVE.html
const char *filename="";
char samplename[64];
unsigned int bcount, wcount;
unsigned int total_length=0;
int pcm_mode=0;
void wav2c(FILE *in, FILE *out, FILE *outh)
{
uint32_t header[4];
int16_t format, channels, bits;
uint32_t rate;
uint32_t i, length, padlength=0, arraylen;
uint32_t chunkSize;
int32_t audio=0;
// read the WAV file's header
for (i=0; i < 4; i++) {
header[i] = read_uint32(in);
}
while (header[3] != 0x20746D66) {
// skip past unknown sections until "fmt "
chunkSize = read_uint32(in);
for (i=0; i < chunkSize; i++) {
read_uint8(in);
}
header[3] = read_uint32(in);
}
chunkSize = read_uint32(in);
// read the audio format parameters
format = read_int16(in);
channels = read_int16(in);
rate = read_uint32(in);
read_uint32(in); // ignore byterate
read_int16(in); // ignore blockalign
bits = read_int16(in);
//printf("format: %d, channels: %d, rate: %d, bits %d\n", format, channels, rate, bits);
if (format != 1)
die("file %s is compressed, only uncompressed supported", filename);
if (rate != 44100 && rate != 22050 && rate != 11025 /*&& rate != 8000*/ )
die("sample rate %d in %s is unsupported\n"
"Only 44100, 22050, 11025 work", rate, filename);
if (channels != 1 && channels != 2)
die("file %s has %d channels, but only 1 & 2 are supported", filename, channels);
if (bits != 16)
die("file %s has %d bit format, but only 16 is supported", filename, bits);
// skip past any extra data on the WAVE header (hopefully it doesn't matter?)
for (chunkSize -= 16; chunkSize > 0; chunkSize--) {
read_uint8(in);
}
// read the data header, skip non-audio data
while (1) {
header[0] = read_uint32(in);
length = read_uint32(in);
if (header[0] == 0x61746164) break; // beginning of actual audio data
// skip over non-audio data
for (i=0; i < length; i++) {
read_uint8(in);
}
}
// the length must be a multiple of the data size
if (channels == 2) {
if (length % 4) die("file %s data length is not a multiple of 4", filename);
length = length / 4;
}
if (channels == 1) {
if (length % 1) die("file %s data length is not a multiple of 2", filename);
length = length / 2;
}
if (length > 0xFFFFFF) die("file %s data length is too long", filename);
bcount = 0;
// AudioPlayMemory requires padding to 2.9 ms boundary (128 samples @ 44100)
if (rate == 44100) {
padlength = padding(length, 128);
format = 1;
} else if (rate == 22050) {
padlength = padding(length, 64);
format = 2;
} else if (rate == 11025) {
padlength = padding(length, 32);
format = 3;
}
if (pcm_mode) {
arraylen = ((length + padlength) * 2 + 3) / 4 + 1;
format |= 0x80;
} else {
arraylen = (length + padlength + 3) / 4 + 1;
}
total_length += arraylen;
// output a minimal header, just the length, #bits and sample rate
fprintf(outh, "extern const unsigned int AudioSample%s[%d];\n", samplename, arraylen);
fprintf(out, "// Converted from %s, using %d Hz, %s encoding\n", filename, rate,
(pcm_mode ? "16 bit PCM" : "u-law"));
fprintf(out, "PROGMEM const unsigned int AudioSample%s[%d] = {\n", samplename, arraylen);
fprintf(out, "0x%08X,", length | (format << 24));
wcount = 1;
// finally, read the audio data
while (length > 0) {
if (channels == 1) {
audio = read_int16(in);
} else {
audio = read_int16(in);
audio += read_int16(in);
audio /= 2;
}
if (pcm_mode) {
print_byte(out, audio);
print_byte(out, audio >> 8);
} else {
print_byte(out, ulaw_encode(audio));
}
length--;
}
while (padlength > 0) {
print_byte(out, 0);
padlength--;
}
while (bcount > 0) {
print_byte(out, 0);
}
if (wcount > 0) fprintf(out, "\n");
fprintf(out, "};\n");
}
uint8_t ulaw_encode(int16_t audio)
{
uint32_t mag, neg;
// http://e...content-available-to-author-only...a.org/wiki/G.711
if (audio >= 0) {
mag = audio;
neg = 0;
} else {
mag = audio * -1;
neg = 0x80;
}
mag += 128;
if (mag > 0x7FFF) mag = 0x7FFF;
if (mag >= 0x4000) return neg | 0x70 | ((mag >> 10) & 0x0F); // 01wx yz00 0000 0000
if (mag >= 0x2000) return neg | 0x60 | ((mag >> 9) & 0x0F); // 001w xyz0 0000 0000
if (mag >= 0x1000) return neg | 0x50 | ((mag >> 8) & 0x0F); // 0001 wxyz 0000 0000
if (mag >= 0x0800) return neg | 0x40 | ((mag >> 7) & 0x0F); // 0000 1wxy z000 0000
if (mag >= 0x0400) return neg | 0x30 | ((mag >> 6) & 0x0F); // 0000 01wx yz00 0000
if (mag >= 0x0200) return neg | 0x20 | ((mag >> 5) & 0x0F); // 0000 001w xyz0 0000
if (mag >= 0x0100) return neg | 0x10 | ((mag >> 4) & 0x0F); // 0000 0001 wxyz 0000
else return neg | 0x00 | ((mag >> 3) & 0x0F); // 0000 0000 1wxy z000
}
// compute the extra padding needed
uint32_t padding(uint32_t length, uint32_t block)
{
uint32_t extra;
extra = length % block;
if (extra == 0) return 0;
return block - extra;
}
// pack the output bytes into 32 bit words, lsb first, and
// format the data nicely with commas and newlines
void print_byte(FILE *out, uint8_t b)
{
static uint32_t buf32=0;
buf32 |= (b << (8 * bcount++));
if (bcount >= 4) {
fprintf(out, "0x%08X,", buf32);
buf32 = 0;
bcount = 0;
if (++wcount >= 8) {
fprintf(out, "\n");
wcount = 0;
}
}
}
// convert the WAV filename into a C-compatible name
void filename2samplename(void)
{
int len, i, n;
char c;
len = strlen(filename) - 4;
if (len >= sizeof(samplename)-1) len = sizeof(samplename)-1;
for (i=0, n=0; n < len; i++) {
c = filename[i];
if (isalpha(c) || c == '_' || (isdigit(c) && n > 0)) {
samplename[n] = (n == 0) ? toupper(c) : tolower(c);
n++;
}
}
samplename[n] = 0;
}
const char *title = "// Audio data converted from WAV file by wav2sketch\n\n";
int main(int argc, char **argv)
{
DIR *dir;
struct dirent *f;
struct stat s;
FILE *fp, *outc=NULL, *outh=NULL;
char buf[128];
int i, len;
// By default, audio is u-law encoded to reduce the memory requirement
// in half. However, u-law does add distortion. If "-16" is specified
// on the command line, the original 16 bit PCM samples are used.
for (i=1; i < argc; i++) {
if (strcmp(argv[i], "-16") == 0) pcm_mode = 1;
}
dir = opendir(".");
if (!dir) die("unable to open directory");
while (1) {
f = readdir(dir);
if (!f) break;
//if ((f->d_type & DT_DIR)) continue; // skip directories
//if (!(f->d_type & DT_REG)) continue; // skip special files
if (stat(f->d_name, &s) < 0) continue; // skip if unable to stat
if (S_ISDIR(s.st_mode)) continue; // skip directories
if (!S_ISREG(s.st_mode)) continue; // skip special files
filename = f->d_name;
len = strlen(filename);
if (len < 5) continue;
if (strcasecmp(filename + len - 4, ".wav") != 0) continue;
fp = fopen(filename, "rb");
if (!fp) die("unable to read file %s", filename);
filename2samplename();
printf("converting: %s --> AudioSample%s\n", filename, samplename);
snprintf(buf, sizeof(buf), "AudioSample%s.cpp", samplename);
outc = fopen(buf, "w");
if (outc == NULL) die("unable to write %s", buf);
snprintf(buf, sizeof(buf), "AudioSample%s.h", samplename);
outh = fopen(buf, "w");
if (outh == NULL) die("unable to write %s\n", buf);
fprintf(outh, "%s", title);
fprintf(outc, "%s", title);
fprintf(outc, "#include <Arduino.h>\n");
fprintf(outc, "#include \"%s\"\n\n", buf);
wav2c(fp, outc, outh);
//wav2c(fp, stdout, stdout);
fclose(outc);
fclose(outh);
fclose(fp);
}
printf("Total data size %d bytes\n", total_length * 4);
return 0;
}
uint8_t read_uint8(FILE *in)
{
int c1;
c1 = fgetc(in);
if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
c1 &= 255;
return c1;
}
int16_t read_int16(FILE *in)
{
int c1, c2;
c1 = fgetc(in);
if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
c2 = fgetc(in);
if (c2 == EOF) die("error, end of data while reading from %s\n", filename);
c1 &= 255;
c2 &= 255;
return (c2 << 8) | c1;
}
uint32_t read_uint32(FILE *in)
{
int c1, c2, c3, c4;
c1 = fgetc(in);
if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
c2 = fgetc(in);
if (c2 == EOF) die("error, end of data while reading from %s\n", filename);
c3 = fgetc(in);
if (c3 == EOF) die("error, end of data while reading from %s\n", filename);
c4 = fgetc(in);
if (c4 == EOF) die("error, end of data while reading from %s\n", filename);
c1 &= 255;
c2 &= 255;
c3 &= 255;
c4 &= 255;
return (c4 << 24) | (c3 << 16) | (c2 << 8) | c1;
}
void die(const char *format, ...)
{
va_list args;
va_start(args, format);
fprintf(stderr, "wav2sketch: ");
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
exit(1);
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0ZGludC5oPgojaW5jbHVkZSA8c3RkYXJnLmg+CiNpbmNsdWRlIDxzdHJpbmcuaD4KI2luY2x1ZGUgPGN0eXBlLmg+CiNpbmNsdWRlIDxzeXMvdHlwZXMuaD4KI2luY2x1ZGUgPHN5cy9zdGF0Lmg+CiNpbmNsdWRlIDxkaXJlbnQuaD4KCnVpbnQ4X3QgdWxhd19lbmNvZGUoaW50MTZfdCBhdWRpbyk7CnZvaWQgcHJpbnRfYnl0ZShGSUxFICpvdXQsIHVpbnQ4X3QgYik7CnZvaWQgZmlsZW5hbWUyc2FtcGxlbmFtZSh2b2lkKTsKdWludDMyX3QgcGFkZGluZyh1aW50MzJfdCBsZW5ndGgsIHVpbnQzMl90IGJsb2NrKTsKdWludDhfdCByZWFkX3VpbnQ4KEZJTEUgKmluKTsKaW50MTZfdCByZWFkX2ludDE2KEZJTEUgKmluKTsKdWludDMyX3QgcmVhZF91aW50MzIoRklMRSAqaW4pOwp2b2lkIGRpZShjb25zdCBjaGFyICpmb3JtYXQsIC4uLikgX19hdHRyaWJ1dGVfXyAoKGZvcm1hdCAocHJpbnRmLCAxLCAyKSkpOwoKLy8gV0FWIGZpbGUgZm9ybWF0OgovLyBodHRwOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ubC5jYS9Eb2N1bWVudHMvQXVkaW9Gb3JtYXRzL1dBVkUvV0FWRS5odG1sCgpjb25zdCBjaGFyICpmaWxlbmFtZT0iIjsKY2hhciBzYW1wbGVuYW1lWzY0XTsKdW5zaWduZWQgaW50IGJjb3VudCwgd2NvdW50Owp1bnNpZ25lZCBpbnQgdG90YWxfbGVuZ3RoPTA7CmludCBwY21fbW9kZT0wOwoKdm9pZCB3YXYyYyhGSUxFICppbiwgRklMRSAqb3V0LCBGSUxFICpvdXRoKQp7Cgl1aW50MzJfdCBoZWFkZXJbNF07CglpbnQxNl90IGZvcm1hdCwgY2hhbm5lbHMsIGJpdHM7Cgl1aW50MzJfdCByYXRlOwoJdWludDMyX3QgaSwgbGVuZ3RoLCBwYWRsZW5ndGg9MCwgYXJyYXlsZW47Cgl1aW50MzJfdCBjaHVua1NpemU7CglpbnQzMl90IGF1ZGlvPTA7CgoJLy8gcmVhZCB0aGUgV0FWIGZpbGUncyBoZWFkZXIKCWZvciAoaT0wOyBpIDwgNDsgaSsrKSB7CgkJaGVhZGVyW2ldID0gcmVhZF91aW50MzIoaW4pOwoJfQoJd2hpbGUgKGhlYWRlclszXSAhPSAweDIwNzQ2RDY2KSB7CgkJLy8gc2tpcCBwYXN0IHVua25vd24gc2VjdGlvbnMgdW50aWwgImZtdCAiCgkJY2h1bmtTaXplID0gcmVhZF91aW50MzIoaW4pOwoJCWZvciAoaT0wOyBpIDwgY2h1bmtTaXplOyBpKyspIHsKCQkJcmVhZF91aW50OChpbik7CgkJfQoJCWhlYWRlclszXSA9IHJlYWRfdWludDMyKGluKTsKCX0KCWNodW5rU2l6ZSA9IHJlYWRfdWludDMyKGluKTsKCgkvLyByZWFkIHRoZSBhdWRpbyBmb3JtYXQgcGFyYW1ldGVycwoJZm9ybWF0ID0gcmVhZF9pbnQxNihpbik7CgljaGFubmVscyA9IHJlYWRfaW50MTYoaW4pOwoJcmF0ZSA9IHJlYWRfdWludDMyKGluKTsKCXJlYWRfdWludDMyKGluKTsgLy8gaWdub3JlIGJ5dGVyYXRlCglyZWFkX2ludDE2KGluKTsgIC8vIGlnbm9yZSBibG9ja2FsaWduCgliaXRzID0gcmVhZF9pbnQxNihpbik7CgkvL3ByaW50ZigiZm9ybWF0OiAlZCwgY2hhbm5lbHM6ICVkLCByYXRlOiAlZCwgYml0cyAlZFxuIiwgZm9ybWF0LCBjaGFubmVscywgcmF0ZSwgYml0cyk7CglpZiAoZm9ybWF0ICE9IDEpCgkJZGllKCJmaWxlICVzIGlzIGNvbXByZXNzZWQsIG9ubHkgdW5jb21wcmVzc2VkIHN1cHBvcnRlZCIsIGZpbGVuYW1lKTsKCWlmIChyYXRlICE9IDQ0MTAwICYmIHJhdGUgIT0gMjIwNTAgJiYgcmF0ZSAhPSAxMTAyNSAvKiYmIHJhdGUgIT0gODAwMCovICkKCQlkaWUoInNhbXBsZSByYXRlICVkIGluICVzIGlzIHVuc3VwcG9ydGVkXG4iCgkJICAiT25seSA0NDEwMCwgMjIwNTAsIDExMDI1IHdvcmsiLCByYXRlLCBmaWxlbmFtZSk7CglpZiAoY2hhbm5lbHMgIT0gMSAmJiBjaGFubmVscyAhPSAyKQoJCWRpZSgiZmlsZSAlcyBoYXMgJWQgY2hhbm5lbHMsIGJ1dCBvbmx5IDEgJiAyIGFyZSBzdXBwb3J0ZWQiLCBmaWxlbmFtZSwgY2hhbm5lbHMpOwoJaWYgKGJpdHMgIT0gMTYpCgkJZGllKCJmaWxlICVzIGhhcyAlZCBiaXQgZm9ybWF0LCBidXQgb25seSAxNiBpcyBzdXBwb3J0ZWQiLCBmaWxlbmFtZSwgYml0cyk7CgoJLy8gc2tpcCBwYXN0IGFueSBleHRyYSBkYXRhIG9uIHRoZSBXQVZFIGhlYWRlciAoaG9wZWZ1bGx5IGl0IGRvZXNuJ3QgbWF0dGVyPykKCWZvciAoY2h1bmtTaXplIC09IDE2OyBjaHVua1NpemUgPiAwOyBjaHVua1NpemUtLSkgewoJCXJlYWRfdWludDgoaW4pOwoJfQoKCS8vIHJlYWQgdGhlIGRhdGEgaGVhZGVyLCBza2lwIG5vbi1hdWRpbyBkYXRhCgl3aGlsZSAoMSkgewoJCWhlYWRlclswXSA9IHJlYWRfdWludDMyKGluKTsKCQlsZW5ndGggPSByZWFkX3VpbnQzMihpbik7CgkJaWYgKGhlYWRlclswXSA9PSAweDYxNzQ2MTY0KSBicmVhazsgLy8gYmVnaW5uaW5nIG9mIGFjdHVhbCBhdWRpbyBkYXRhCgkJLy8gc2tpcCBvdmVyIG5vbi1hdWRpbyBkYXRhCgkJZm9yIChpPTA7IGkgPCBsZW5ndGg7IGkrKykgewoJCQlyZWFkX3VpbnQ4KGluKTsKCQl9Cgl9CgoJLy8gdGhlIGxlbmd0aCBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgdGhlIGRhdGEgc2l6ZQoJaWYgKGNoYW5uZWxzID09IDIpIHsKCQlpZiAobGVuZ3RoICUgNCkgZGllKCJmaWxlICVzIGRhdGEgbGVuZ3RoIGlzIG5vdCBhIG11bHRpcGxlIG9mIDQiLCBmaWxlbmFtZSk7CgkJbGVuZ3RoID0gbGVuZ3RoIC8gNDsKCX0KCWlmIChjaGFubmVscyA9PSAxKSB7CgkJaWYgKGxlbmd0aCAlIDEpIGRpZSgiZmlsZSAlcyBkYXRhIGxlbmd0aCBpcyBub3QgYSBtdWx0aXBsZSBvZiAyIiwgZmlsZW5hbWUpOwoJCWxlbmd0aCA9IGxlbmd0aCAvIDI7Cgl9CglpZiAobGVuZ3RoID4gMHhGRkZGRkYpIGRpZSgiZmlsZSAlcyBkYXRhIGxlbmd0aCBpcyB0b28gbG9uZyIsIGZpbGVuYW1lKTsKCWJjb3VudCA9IDA7CgoJLy8gQXVkaW9QbGF5TWVtb3J5IHJlcXVpcmVzIHBhZGRpbmcgdG8gMi45IG1zIGJvdW5kYXJ5ICgxMjggc2FtcGxlcyBAIDQ0MTAwKQoJaWYgKHJhdGUgPT0gNDQxMDApIHsKCQlwYWRsZW5ndGggPSBwYWRkaW5nKGxlbmd0aCwgMTI4KTsKCQlmb3JtYXQgPSAxOwoJfSBlbHNlIGlmIChyYXRlID09IDIyMDUwKSB7CgkJcGFkbGVuZ3RoID0gcGFkZGluZyhsZW5ndGgsIDY0KTsKCQlmb3JtYXQgPSAyOwoJfSBlbHNlIGlmIChyYXRlID09IDExMDI1KSB7CgkJcGFkbGVuZ3RoID0gcGFkZGluZyhsZW5ndGgsIDMyKTsKCQlmb3JtYXQgPSAzOwoJfQoJaWYgKHBjbV9tb2RlKSB7CgkJYXJyYXlsZW4gPSAoKGxlbmd0aCArIHBhZGxlbmd0aCkgKiAyICsgMykgLyA0ICsgMTsKCQlmb3JtYXQgfD0gMHg4MDsKCX0gZWxzZSB7CgkJYXJyYXlsZW4gPSAobGVuZ3RoICsgcGFkbGVuZ3RoICsgMykgLyA0ICsgMTsKCX0KCXRvdGFsX2xlbmd0aCArPSBhcnJheWxlbjsKCgkvLyBvdXRwdXQgYSBtaW5pbWFsIGhlYWRlciwganVzdCB0aGUgbGVuZ3RoLCAjYml0cyBhbmQgc2FtcGxlIHJhdGUKCWZwcmludGYob3V0aCwgImV4dGVybiBjb25zdCB1bnNpZ25lZCBpbnQgQXVkaW9TYW1wbGUlc1slZF07XG4iLCBzYW1wbGVuYW1lLCBhcnJheWxlbik7CQoJZnByaW50ZihvdXQsICIvLyBDb252ZXJ0ZWQgZnJvbSAlcywgdXNpbmcgJWQgSHosICVzIGVuY29kaW5nXG4iLCBmaWxlbmFtZSwgcmF0ZSwKCSAgKHBjbV9tb2RlID8gIjE2IGJpdCBQQ00iIDogInUtbGF3IikpOwoJZnByaW50ZihvdXQsICJQUk9HTUVNIGNvbnN0IHVuc2lnbmVkIGludCBBdWRpb1NhbXBsZSVzWyVkXSA9IHtcbiIsIHNhbXBsZW5hbWUsIGFycmF5bGVuKTsKCWZwcmludGYob3V0LCAiMHglMDhYLCIsIGxlbmd0aCB8IChmb3JtYXQgPDwgMjQpKTsKCXdjb3VudCA9IDE7CgoJLy8gZmluYWxseSwgcmVhZCB0aGUgYXVkaW8gZGF0YQoJd2hpbGUgKGxlbmd0aCA+IDApIHsKCQlpZiAoY2hhbm5lbHMgPT0gMSkgewoJCQlhdWRpbyA9IHJlYWRfaW50MTYoaW4pOwoJCX0gZWxzZSB7CgkJCWF1ZGlvID0gcmVhZF9pbnQxNihpbik7CgkJCWF1ZGlvICs9IHJlYWRfaW50MTYoaW4pOwoJCQlhdWRpbyAvPSAyOwoJCX0KCQlpZiAocGNtX21vZGUpIHsKCQkJcHJpbnRfYnl0ZShvdXQsIGF1ZGlvKTsKCQkJcHJpbnRfYnl0ZShvdXQsIGF1ZGlvID4+IDgpOwoJCX0gZWxzZSB7CgkJCXByaW50X2J5dGUob3V0LCB1bGF3X2VuY29kZShhdWRpbykpOwoJCX0KCQlsZW5ndGgtLTsKCX0KCXdoaWxlIChwYWRsZW5ndGggPiAwKSB7CgkJcHJpbnRfYnl0ZShvdXQsIDApOwoJCXBhZGxlbmd0aC0tOwoJfQoJd2hpbGUgKGJjb3VudCA+IDApIHsKCQlwcmludF9ieXRlKG91dCwgMCk7Cgl9CglpZiAod2NvdW50ID4gMCkgZnByaW50ZihvdXQsICJcbiIpOwoJZnByaW50ZihvdXQsICJ9O1xuIik7Cn0KCgp1aW50OF90IHVsYXdfZW5jb2RlKGludDE2X3QgYXVkaW8pCnsKCXVpbnQzMl90IG1hZywgbmVnOwoKCS8vIGh0dHA6Ly9lLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5hLm9yZy93aWtpL0cuNzExCglpZiAoYXVkaW8gPj0gMCkgewoJCW1hZyA9IGF1ZGlvOwoJCW5lZyA9IDA7Cgl9IGVsc2UgewoJCW1hZyA9IGF1ZGlvICogLTE7CgkJbmVnID0gMHg4MDsKCX0KCW1hZyArPSAxMjg7CglpZiAobWFnID4gMHg3RkZGKSBtYWcgPSAweDdGRkY7CglpZiAobWFnID49IDB4NDAwMCkgcmV0dXJuIG5lZyB8IDB4NzAgfCAoKG1hZyA+PiAxMCkgJiAweDBGKTsgIC8vIDAxd3ggeXowMCAwMDAwIDAwMDAKCWlmIChtYWcgPj0gMHgyMDAwKSByZXR1cm4gbmVnIHwgMHg2MCB8ICgobWFnID4+IDkpICYgMHgwRik7ICAgLy8gMDAxdyB4eXowIDAwMDAgMDAwMAoJaWYgKG1hZyA+PSAweDEwMDApIHJldHVybiBuZWcgfCAweDUwIHwgKChtYWcgPj4gOCkgJiAweDBGKTsgICAvLyAwMDAxIHd4eXogMDAwMCAwMDAwCglpZiAobWFnID49IDB4MDgwMCkgcmV0dXJuIG5lZyB8IDB4NDAgfCAoKG1hZyA+PiA3KSAmIDB4MEYpOyAgIC8vIDAwMDAgMXd4eSB6MDAwIDAwMDAKCWlmIChtYWcgPj0gMHgwNDAwKSByZXR1cm4gbmVnIHwgMHgzMCB8ICgobWFnID4+IDYpICYgMHgwRik7ICAgLy8gMDAwMCAwMXd4IHl6MDAgMDAwMAoJaWYgKG1hZyA+PSAweDAyMDApIHJldHVybiBuZWcgfCAweDIwIHwgKChtYWcgPj4gNSkgJiAweDBGKTsgICAvLyAwMDAwIDAwMXcgeHl6MCAwMDAwCglpZiAobWFnID49IDB4MDEwMCkgcmV0dXJuIG5lZyB8IDB4MTAgfCAoKG1hZyA+PiA0KSAmIDB4MEYpOyAgIC8vIDAwMDAgMDAwMSB3eHl6IDAwMDAKCWVsc2UgICAgICAgICAgICAgICByZXR1cm4gbmVnIHwgMHgwMCB8ICgobWFnID4+IDMpICYgMHgwRik7ICAgLy8gMDAwMCAwMDAwIDF3eHkgejAwMAp9CgoKCi8vIGNvbXB1dGUgdGhlIGV4dHJhIHBhZGRpbmcgbmVlZGVkCnVpbnQzMl90IHBhZGRpbmcodWludDMyX3QgbGVuZ3RoLCB1aW50MzJfdCBibG9jaykKewoJdWludDMyX3QgZXh0cmE7CgoJZXh0cmEgPSBsZW5ndGggJSBibG9jazsKCWlmIChleHRyYSA9PSAwKSByZXR1cm4gMDsKCXJldHVybiBibG9jayAtIGV4dHJhOwp9CgovLyBwYWNrIHRoZSBvdXRwdXQgYnl0ZXMgaW50byAzMiBiaXQgd29yZHMsIGxzYiBmaXJzdCwgYW5kCi8vIGZvcm1hdCB0aGUgZGF0YSBuaWNlbHkgd2l0aCBjb21tYXMgYW5kIG5ld2xpbmVzCnZvaWQgcHJpbnRfYnl0ZShGSUxFICpvdXQsIHVpbnQ4X3QgYikKewoJc3RhdGljIHVpbnQzMl90IGJ1ZjMyPTA7CgoJYnVmMzIgfD0gKGIgPDwgKDggKiBiY291bnQrKykpOwoJaWYgKGJjb3VudCA+PSA0KSB7CgkJZnByaW50ZihvdXQsICIweCUwOFgsIiwgYnVmMzIpOwoJCWJ1ZjMyID0gMDsKCQliY291bnQgPSAwOwoJCWlmICgrK3djb3VudCA+PSA4KSB7CgkJCWZwcmludGYob3V0LCAiXG4iKTsKCQkJd2NvdW50ID0gMDsKCQl9Cgl9Cn0KCi8vIGNvbnZlcnQgdGhlIFdBViBmaWxlbmFtZSBpbnRvIGEgQy1jb21wYXRpYmxlIG5hbWUKdm9pZCBmaWxlbmFtZTJzYW1wbGVuYW1lKHZvaWQpCnsKCWludCBsZW4sIGksIG47CgljaGFyIGM7CgoJbGVuID0gc3RybGVuKGZpbGVuYW1lKSAtIDQ7CglpZiAobGVuID49IHNpemVvZihzYW1wbGVuYW1lKS0xKSBsZW4gPSBzaXplb2Yoc2FtcGxlbmFtZSktMTsKCWZvciAoaT0wLCBuPTA7IG4gPCBsZW47IGkrKykgewoJCWMgPSBmaWxlbmFtZVtpXTsKCQlpZiAoaXNhbHBoYShjKSB8fCBjID09ICdfJyB8fCAoaXNkaWdpdChjKSAmJiBuID4gMCkpIHsKCQkJc2FtcGxlbmFtZVtuXSA9IChuID09IDApID8gdG91cHBlcihjKSA6IHRvbG93ZXIoYyk7CgkJCW4rKzsKCQl9Cgl9CglzYW1wbGVuYW1lW25dID0gMDsKfQoKCmNvbnN0IGNoYXIgKnRpdGxlID0gIi8vIEF1ZGlvIGRhdGEgY29udmVydGVkIGZyb20gV0FWIGZpbGUgYnkgd2F2MnNrZXRjaFxuXG4iOwoKaW50IG1haW4oaW50IGFyZ2MsIGNoYXIgKiphcmd2KQp7CglESVIgKmRpcjsKCXN0cnVjdCBkaXJlbnQgKmY7CglzdHJ1Y3Qgc3RhdCBzOwoJRklMRSAqZnAsICpvdXRjPU5VTEwsICpvdXRoPU5VTEw7CgljaGFyIGJ1ZlsxMjhdOwoJaW50IGksIGxlbjsKCgkvLyBCeSBkZWZhdWx0LCBhdWRpbyBpcyB1LWxhdyBlbmNvZGVkIHRvIHJlZHVjZSB0aGUgbWVtb3J5IHJlcXVpcmVtZW50CgkvLyBpbiBoYWxmLiAgSG93ZXZlciwgdS1sYXcgZG9lcyBhZGQgZGlzdG9ydGlvbi4gIElmICItMTYiIGlzIHNwZWNpZmllZAoJLy8gb24gdGhlIGNvbW1hbmQgbGluZSwgdGhlIG9yaWdpbmFsIDE2IGJpdCBQQ00gc2FtcGxlcyBhcmUgdXNlZC4KCWZvciAoaT0xOyBpIDwgYXJnYzsgaSsrKSB7CgkJaWYgKHN0cmNtcChhcmd2W2ldLCAiLTE2IikgPT0gMCkgcGNtX21vZGUgPSAxOwoJfQoJZGlyID0gb3BlbmRpcigiLiIpOwoJaWYgKCFkaXIpIGRpZSgidW5hYmxlIHRvIG9wZW4gZGlyZWN0b3J5Iik7Cgl3aGlsZSAoMSkgewoJCWYgPSByZWFkZGlyKGRpcik7CgkJaWYgKCFmKSBicmVhazsKCQkvL2lmICgoZi0+ZF90eXBlICYgRFRfRElSKSkgY29udGludWU7IC8vIHNraXAgZGlyZWN0b3JpZXMKCQkvL2lmICghKGYtPmRfdHlwZSAmIERUX1JFRykpIGNvbnRpbnVlOyAvLyBza2lwIHNwZWNpYWwgZmlsZXMKCQlpZiAoc3RhdChmLT5kX25hbWUsICZzKSA8IDApIGNvbnRpbnVlOyAvLyBza2lwIGlmIHVuYWJsZSB0byBzdGF0CgkJaWYgKFNfSVNESVIocy5zdF9tb2RlKSkgY29udGludWU7ICAvLyBza2lwIGRpcmVjdG9yaWVzCgkJaWYgKCFTX0lTUkVHKHMuc3RfbW9kZSkpIGNvbnRpbnVlOyAvLyBza2lwIHNwZWNpYWwgZmlsZXMKCQlmaWxlbmFtZSA9IGYtPmRfbmFtZTsKCQlsZW4gPSBzdHJsZW4oZmlsZW5hbWUpOwoJCWlmIChsZW4gPCA1KSBjb250aW51ZTsKCQlpZiAoc3RyY2FzZWNtcChmaWxlbmFtZSArIGxlbiAtIDQsICIud2F2IikgIT0gMCkgY29udGludWU7CgkJZnAgPSBmb3BlbihmaWxlbmFtZSwgInJiIik7CgkJaWYgKCFmcCkgZGllKCJ1bmFibGUgdG8gcmVhZCBmaWxlICVzIiwgZmlsZW5hbWUpOwoJCWZpbGVuYW1lMnNhbXBsZW5hbWUoKTsKCQlwcmludGYoImNvbnZlcnRpbmc6ICVzICAtLT4gIEF1ZGlvU2FtcGxlJXNcbiIsIGZpbGVuYW1lLCBzYW1wbGVuYW1lKTsKCQlzbnByaW50ZihidWYsIHNpemVvZihidWYpLCAiQXVkaW9TYW1wbGUlcy5jcHAiLCBzYW1wbGVuYW1lKTsKCQlvdXRjID0gZm9wZW4oYnVmLCAidyIpOwoJCWlmIChvdXRjID09IE5VTEwpIGRpZSgidW5hYmxlIHRvIHdyaXRlICVzIiwgYnVmKTsKCQlzbnByaW50ZihidWYsIHNpemVvZihidWYpLCAiQXVkaW9TYW1wbGUlcy5oIiwgc2FtcGxlbmFtZSk7CgkJb3V0aCA9IGZvcGVuKGJ1ZiwgInciKTsKCQlpZiAob3V0aCA9PSBOVUxMKSBkaWUoInVuYWJsZSB0byB3cml0ZSAlc1xuIiwgYnVmKTsKCQlmcHJpbnRmKG91dGgsICIlcyIsIHRpdGxlKTsKCQlmcHJpbnRmKG91dGMsICIlcyIsIHRpdGxlKTsKCQlmcHJpbnRmKG91dGMsICIjaW5jbHVkZSA8QXJkdWluby5oPlxuIik7CgkJZnByaW50ZihvdXRjLCAiI2luY2x1ZGUgXCIlc1wiXG5cbiIsIGJ1Zik7CgkJd2F2MmMoZnAsIG91dGMsIG91dGgpOwoJCS8vd2F2MmMoZnAsIHN0ZG91dCwgc3Rkb3V0KTsKCQlmY2xvc2Uob3V0Yyk7CgkJZmNsb3NlKG91dGgpOwoJCWZjbG9zZShmcCk7Cgl9CglwcmludGYoIlRvdGFsIGRhdGEgc2l6ZSAlZCBieXRlc1xuIiwgdG90YWxfbGVuZ3RoICogNCk7CglyZXR1cm4gMDsKfQoKdWludDhfdCByZWFkX3VpbnQ4KEZJTEUgKmluKQp7CglpbnQgYzE7CgoJYzEgPSBmZ2V0Yyhpbik7CglpZiAoYzEgPT0gRU9GKSBkaWUoImVycm9yLCBlbmQgb2YgZGF0YSB3aGlsZSByZWFkaW5nIGZyb20gJXNcbiIsIGZpbGVuYW1lKTsKCWMxICY9IDI1NTsKCXJldHVybiBjMTsKfQoKaW50MTZfdCByZWFkX2ludDE2KEZJTEUgKmluKQp7CglpbnQgYzEsIGMyOwoKCWMxID0gZmdldGMoaW4pOwoJaWYgKGMxID09IEVPRikgZGllKCJlcnJvciwgZW5kIG9mIGRhdGEgd2hpbGUgcmVhZGluZyBmcm9tICVzXG4iLCBmaWxlbmFtZSk7CgljMiA9IGZnZXRjKGluKTsKCWlmIChjMiA9PSBFT0YpIGRpZSgiZXJyb3IsIGVuZCBvZiBkYXRhIHdoaWxlIHJlYWRpbmcgZnJvbSAlc1xuIiwgZmlsZW5hbWUpOwoJYzEgJj0gMjU1OwoJYzIgJj0gMjU1OwoJcmV0dXJuIChjMiA8PCA4KSB8IGMxOwp9Cgp1aW50MzJfdCByZWFkX3VpbnQzMihGSUxFICppbikKewoJaW50IGMxLCBjMiwgYzMsIGM0OwoKCWMxID0gZmdldGMoaW4pOwoJaWYgKGMxID09IEVPRikgZGllKCJlcnJvciwgZW5kIG9mIGRhdGEgd2hpbGUgcmVhZGluZyBmcm9tICVzXG4iLCBmaWxlbmFtZSk7CgljMiA9IGZnZXRjKGluKTsKCWlmIChjMiA9PSBFT0YpIGRpZSgiZXJyb3IsIGVuZCBvZiBkYXRhIHdoaWxlIHJlYWRpbmcgZnJvbSAlc1xuIiwgZmlsZW5hbWUpOwoJYzMgPSBmZ2V0Yyhpbik7CglpZiAoYzMgPT0gRU9GKSBkaWUoImVycm9yLCBlbmQgb2YgZGF0YSB3aGlsZSByZWFkaW5nIGZyb20gJXNcbiIsIGZpbGVuYW1lKTsKCWM0ID0gZmdldGMoaW4pOwoJaWYgKGM0ID09IEVPRikgZGllKCJlcnJvciwgZW5kIG9mIGRhdGEgd2hpbGUgcmVhZGluZyBmcm9tICVzXG4iLCBmaWxlbmFtZSk7CgljMSAmPSAyNTU7CgljMiAmPSAyNTU7CgljMyAmPSAyNTU7CgljNCAmPSAyNTU7CglyZXR1cm4gKGM0IDw8IDI0KSB8IChjMyA8PCAxNikgfCAoYzIgPDwgOCkgfCBjMTsKfQoKdm9pZCBkaWUoY29uc3QgY2hhciAqZm9ybWF0LCAuLi4pCnsKCXZhX2xpc3QgYXJnczsKCXZhX3N0YXJ0KGFyZ3MsIGZvcm1hdCk7CglmcHJpbnRmKHN0ZGVyciwgIndhdjJza2V0Y2g6ICIpOwoJdmZwcmludGYoc3RkZXJyLCBmb3JtYXQsIGFyZ3MpOwoJZnByaW50ZihzdGRlcnIsICJcbiIpOwoJZXhpdCgxKTsKfQo=