#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
/* #define DEBUG */
#if defined(DEBUG)
#include "xmalloc.h"
#else
#define xmalloc(x, y) malloc(x)
#define xfree(x, y) free(x)
#define xrealloc(x, y, z) realloc(x, y)
#define xmallocdump()
#endif
/* for xmalloc.c */
#define IDRGB 1001
#define IDPALETTE 1002
#define IDBMP 1003
#define NBYTE 1
#define NWORD 2
#define NDWORD 4
int LittleEndianRead(unsigned long *data, int size, FILE *fp) {
unsigned char lsb;
unsigned long msb;
if (size == 0) {
*data = 0;
return 1;
}
if (fread(&lsb
, 1, 1, fp
) != 1) return -1;
if (LittleEndianRead(&msb, size - 1, fp) < 0)
return -1;
*data = (unsigned long)lsb | (msb << 8);
return 1;
}
typedef struct {
unsigned long bfType1;
unsigned long bfType2;
unsigned long bfSize;
unsigned long bfReserved1;
unsigned long bfReserved2;
unsigned long bfOffBits;
} BitmapFileHeader;
int bmHeaderCheck(FILE *fp, BitmapFileHeader *bh) {
assert(sizeof(unsigned long) >= 4); if (LittleEndianRead(&(bh->bfType1), NBYTE, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&(bh->bfType2), NBYTE, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bh->bfSize, NDWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bh->bfReserved1, NWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bh->bfReserved2, NWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bh->bfOffBits, NDWORD, fp) < 0)
goto error_NotRead;
#if 0
printf("read:bfType1: %c\n", (char)bh
->bfType1
); printf("read:bfType2: %c\n", (char)bh
->bfType2
); printf("read:bfSize: %lu\n", bh
->bfSize
); printf("read:bfReserved1: %lu\n", bh
->bfReserved1
); printf("read:bfReserved2: %lu\n", bh
->bfReserved2
); printf("read:bfOffBits: %lu\n", bh
->bfOffBits
); #endif
if (bh->bfType1 != 'B' || bh->bfType2 != 'M')
goto error_NotBitmap;
if (bh->bfReserved1 != 0 || bh->bfReserved2 != 0)
goto error_NotBitmap;
return 1;
error_NotBitmap:
fprintf(stderr
, "cannot find bmp header\n"); return 0;
error_NotRead:
fprintf(stderr
, "cannot read bmp header\n"); return 0;
}
typedef struct {
unsigned long biSize;
long biWidth;
long biHeight;
unsigned long biPlanes;
unsigned long biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPixPerMeter;
long biYPixPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} BitmapInfoHeader;
int bmInfoHeaderCheck(FILE *fp, BitmapInfoHeader *bi) {
assert(sizeof(unsigned long) >= 4); if (LittleEndianRead(&bi->biSize, NDWORD, fp) < 0)
goto error_NotRead;
if (bi->biSize == 12) {
/* not supported */
} else if (bi->biSize == 40) {
if (LittleEndianRead((unsigned long *)&bi->biWidth, NDWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead((unsigned long *)&bi->biHeight, NDWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bi->biPlanes, NWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bi->biBitCount, NWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bi->biCompression, NDWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bi->biSizeImage, NDWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead((unsigned long *)&bi->biXPixPerMeter, NDWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead((unsigned long *)&bi->biYPixPerMeter, NDWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bi->biClrUsed, NDWORD, fp) < 0)
goto error_NotRead;
if (LittleEndianRead(&bi->biClrImportant, NDWORD, fp) < 0)
goto error_NotRead;
} else {
goto error_NotSupported1;
}
#if 0
printf("read:biSize: %lu\n", bi
->biSize
); printf("read:biWidth: %ld\n", bi
->biWidth
); printf("read:biHeight: %ld\n", bi
->biHeight
); printf("read:biPlanes: %lu\n", bi
->biPlanes
); printf("read:biBitcount: %lu\n", bi
->biBitCount
); if (bi->biSize == 40) {
printf("read:biCompression: %lu\n", bi
->biCompression
); printf("read:biSizeImage: %lu\n", bi
->biSizeImage
); printf("read:biXPixPerMeter %ld\n", bi
->biXPixPerMeter
); printf("read:biYPixPerMeter %ld\n", bi
->biYPixPerMeter
); printf("read:biClrUsed: %lu\n", bi
->biClrUsed
); printf("read:biClrImporant: %lu\n", bi
->biClrImportant
); }
#endif
if (bi->biSize != 40)
goto error_NotSupported1;
if (bi->biPlanes != 1)
goto error_NotSupported2;
if (bi->biBitCount != 24 && bi->biBitCount != 8 && bi->biBitCount != 4)
goto error_NotSupported3;
if (bi->biCompression != 0)
goto error_NotSupported4;
return 1;
error_NotSupported1:
fprintf(stderr
, "info header size: %lu, this format is not supported\n", bi
->biSize
); return 0;
error_NotSupported2:
fprintf(stderr
, "biPlanes: %lu, this format is not supported\n", bi
->biPlanes
); return 0;
error_NotSupported3:
fprintf(stderr
, "biBitCount: %lu, this format is not supported\n", bi
->biBitCount
); return 0;
error_NotSupported4:
fprintf(stderr
, "biCompression: %lu, this format is not supported\n", bi
->biCompression
); return 0;
error_NotRead:
#if 0
printf("read:biSize: %lu\n", bi
->biSize
); printf("read:biWidth: %ld\n", bi
->biWidth
); printf("read:biHeight: %ld\n", bi
->biHeight
); printf("read:biPlanes: %lu\n", bi
->biPlanes
); printf("read:biBitcount: %lu\n", bi
->biBitCount
); if (bi->biSize == 40) {
printf("read:biCompression: %lu\n", bi
->biCompression
); printf("read:biSizeImage: %lu\n", bi
->biSizeImage
); printf("read:biXPixPerMeter %ld\n", bi
->biXPixPerMeter
); printf("read:biYPixPerMeter %ld\n", bi
->biYPixPerMeter
); printf("read:biClrUsed: %lu\n", bi
->biClrUsed
); printf("read:biClrImporant: %lu\n", bi
->biClrImportant
); }
#endif
fprintf(stderr
, "cannot read bmp info header\n"); return 0;
}
int isFtellGood(FILE *fp, unsigned long pos) {
return (unsigned long)ftell(fp
) == pos
; }
long iabs(long n) {
return (n > 0) ? n : -n;
}
void task_read24(FILE *fp, BitmapFileHeader *bheader, BitmapInfoHeader *binfo,
unsigned char **dataR, unsigned char **dataG,
unsigned char **dataB)
{
long x, y, n;
unsigned char dummy;
int c;
if (!isFtellGood(fp, bheader->bfOffBits)) {
fprintf(stderr
, "Header or Image Data is corrupted.\n"); return;
}
*dataR = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
*dataG = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
*dataB = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
if (*dataR == NULL || *dataG == NULL || *dataB == NULL) {
fprintf(stderr
, "cannot alloc. enough memory.\n"); return;
}
for (y = 0; y < iabs(binfo->biHeight); y++) {
c = 0;
for (x = 0; x < iabs(binfo->biWidth); x++) {
fread((*dataB
+ y
* iabs
(binfo
->biWidth
) + x
), 1, 1, fp
); fread((*dataG
+ y
* iabs
(binfo
->biWidth
) + x
), 1, 1, fp
); fread((*dataR
+ y
* iabs
(binfo
->biWidth
) + x
), 1, 1, fp
); c += 3;
}
while (c % 4 != 0) {
c++;
}
}
n = iabs(binfo->biWidth) * 3;
if (n % 4 > 0)
n += 4 - (n % 4);
binfo->biSizeImage = n * iabs(binfo->biHeight);
bheader->bfSize = binfo->biSizeImage + binfo->biSize + 14;
}
void task_read_palette(FILE *fp, BitmapFileHeader *bh, BitmapInfoHeader *bi,
unsigned char **dataPalette)
{
int i, max;
unsigned char dummy;
if ((max = bi->biClrUsed) == 0) {
switch (bi->biBitCount) {
case 4:
max = 16;
break;
case 8:
max = 256;
break;
}
}
*dataPalette = xmalloc(sizeof(char) * 3 * max, IDPALETTE);
if (*dataPalette == NULL) {
fprintf(stderr
, "cannot alloc. enough memory.\n"); return;
}
for (i = 0; i < max; i++) {
fread((*dataPalette
+ 3 * i
+ 0), 1, 1, fp
); fread((*dataPalette
+ 3 * i
+ 1), 1, 1, fp
); fread((*dataPalette
+ 3 * i
+ 2), 1, 1, fp
); }
}
void task_read8(FILE *fp, BitmapFileHeader *bheader, BitmapInfoHeader *binfo,
unsigned char **dataR, unsigned char **dataG,
unsigned char **dataB, unsigned char *dataPalette)
{
long x, y, n;
unsigned char data;
int c;
if (!isFtellGood(fp, bheader->bfOffBits)) {
fprintf(stderr
, "Header or Image Data is corrupted.\n"); return;
}
*dataR = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
*dataG = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
*dataB = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
if (*dataR == NULL || *dataG == NULL || *dataB == NULL) {
fprintf(stderr
, "cannot alloc. enough memory.\n"); return;
}
for (y = 0; y < iabs(binfo->biHeight); y++) {
c = 0;
for (x = 0; x < iabs(binfo->biWidth); x++) {
*(*dataB + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 0];
*(*dataG + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 1];
*(*dataR + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 2];
c++;
}
while (c % 4 != 0) {
c++;
}
}
n = iabs(binfo->biWidth) * 3;
if (n % 4 > 0)
n += 4 - (n % 4);
binfo->biSizeImage = n * iabs(binfo->biHeight);
bheader->bfSize = binfo->biSizeImage + binfo->biSize + 14;
bheader->bfOffBits = 54;
binfo->biBitCount = 24;
binfo->biClrUsed = 0;
binfo->biClrImportant = 0;
}
void task_read4(FILE *fp, BitmapFileHeader *bheader, BitmapInfoHeader *binfo,
unsigned char **dataR, unsigned char **dataG,
unsigned char **dataB, unsigned char *dataPalette)
{
long x, y, n;
unsigned char data, rdata;
int c;
int bitHighLow;
if (!isFtellGood(fp, bheader->bfOffBits)) {
fprintf(stderr
, "Header or Image Data is corrupted.\n"); return;
}
*dataR = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
*dataG = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
*dataB = xmalloc(sizeof(char) * iabs(binfo->biWidth) * iabs(binfo->biHeight), IDRGB);
if (*dataR == NULL || *dataG == NULL || *dataB == NULL) {
fprintf(stderr
, "cannot alloc. enough memory.\n"); return;
}
bitHighLow = 1;
for (y = 0; y < iabs(binfo->biHeight); y++) {
c = 0;
for (x = 0; x < iabs(binfo->biWidth); x++) {
if (bitHighLow) {
data = rdata & 0xf0;
data >>= 4;
bitHighLow = 0;
} else {
data = rdata & 0x0f;
bitHighLow = 1;
}
*(*dataB + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 0];
*(*dataG + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 1];
*(*dataR + y * iabs(binfo->biWidth) + x) = dataPalette[3 * data + 2];
c++;
}
while (c % 4 != 0) {
c++;
}
}
n = iabs(binfo->biWidth) * 3;
if (n % 4 > 0)
n += 4 - (n % 4);
binfo->biSizeImage = n * iabs(binfo->biHeight);
bheader->bfSize = binfo->biSizeImage + binfo->biSize + 14;
bheader->bfOffBits = 54;
binfo->biBitCount = 24;
binfo->biClrUsed = 0;
binfo->biClrImportant = 0;
}
void LittleEndianWrite(unsigned long *data, int size, FILE *fp) {
unsigned char lsb;
unsigned long msb;
if (size == 0)
return;
lsb = (unsigned char)(*data & 0xff);
msb = *data >> 8;
LittleEndianWrite(&msb, size - 1, fp);
}
void task_write_header(FILE *fp, BitmapFileHeader *bh) {
assert(sizeof(unsigned long) >= 4); LittleEndianWrite(&(bh->bfType1), NBYTE, fp);
LittleEndianWrite(&(bh->bfType2), NBYTE, fp);
LittleEndianWrite(&(bh->bfSize), NDWORD, fp);
LittleEndianWrite(&(bh->bfReserved1), NWORD, fp);
LittleEndianWrite(&(bh->bfReserved2), NWORD, fp);
LittleEndianWrite(&(bh->bfOffBits), NDWORD, fp);
#if 0
printf("write:bfType1: %c\n", (char)bh
->bfType1
); printf("write:bfType2: %c\n", (char)bh
->bfType2
); printf("write:bfSize: %lu\n", bh
->bfSize
); printf("write:bfReserved1: %lu\n", bh
->bfReserved1
); printf("write:bfReserved2: %lu\n", bh
->bfReserved2
); printf("write:bfOffBits: %lu\n", bh
->bfOffBits
); #endif
}
void task_write_info(FILE *fp, BitmapInfoHeader *bi) {
assert(sizeof(unsigned short) == 2); assert(sizeof(unsigned long) == 4); LittleEndianWrite(&(bi->biSize), NDWORD, fp);
LittleEndianWrite((unsigned long *)&(bi->biWidth), NDWORD, fp);
LittleEndianWrite((unsigned long *)&(bi->biHeight), NDWORD, fp);
LittleEndianWrite(&(bi->biPlanes), NWORD, fp);
LittleEndianWrite(&(bi->biBitCount), NWORD, fp);
LittleEndianWrite(&(bi->biCompression), NDWORD, fp);
LittleEndianWrite(&(bi->biSizeImage), NDWORD, fp);
LittleEndianWrite((unsigned long *)&(bi->biXPixPerMeter), NDWORD, fp);
LittleEndianWrite((unsigned long *)&(bi->biYPixPerMeter), NDWORD, fp);
LittleEndianWrite(&(bi->biClrUsed), NDWORD, fp);
LittleEndianWrite(&(bi->biClrImportant), NDWORD, fp);
#if 0
printf("write:biSize: %lu\n", bi
->biSize
); printf("write:biWidth: %ld\n", bi
->biWidth
); printf("write:biHeight: %ld\n", bi
->biHeight
); printf("write:biPlanes: %lu\n", bi
->biPlanes
); printf("write:biBitcount: %lu\n", bi
->biBitCount
); printf("write:biCompression: %lu\n", bi
->biCompression
); printf("write:biSizeImage: %lu\n", bi
->biSizeImage
); printf("write:biXPixPerMeter %ld\n", bi
->biXPixPerMeter
); printf("write:biYPixPerMeter %ld\n", bi
->biYPixPerMeter
); printf("write:biClrUsed: %lu\n", bi
->biClrUsed
); printf("write:biClrImporant: %lu\n", bi
->biClrImportant
); #endif
}
void task_write24(FILE *fp,
BitmapFileHeader *bh, BitmapInfoHeader *bi,
unsigned char *dataR,
unsigned char *dataG,
unsigned char *dataB) {
int x, y;
int c;
unsigned char dummy = '\0';
task_write_header(fp, bh);
task_write_info(fp, bi);
for (y = 0; y < iabs(bi->biHeight); y++) {
c = 0;
for (x = 0; x < iabs(bi->biWidth); x++) {
fwrite(&dataB
[y
* iabs
(bi
->biWidth
) + x
], 1, 1, fp
); fwrite(&dataG
[y
* iabs
(bi
->biWidth
) + x
], 1, 1, fp
); fwrite(&dataR
[y
* iabs
(bi
->biWidth
) + x
], 1, 1, fp
); c += 3;
}
while (c % 4 != 0) {
c++;
}
}
}
/* ------------------------------------------------------------------------- */
struct BMP24 {
BitmapFileHeader bh;
BitmapInfoHeader bi;
unsigned char *dataR;
unsigned char *dataG;
unsigned char *dataB;
unsigned char *dataPalette;
};
int BMP24_read(FILE *fp, struct BMP24 *bmp) {
if (!bmHeaderCheck(fp, &(bmp->bh)))
return 0;
if (!bmInfoHeaderCheck(fp, &(bmp->bi)))
return 0;
bmp->dataR = bmp->dataG = bmp->dataB = bmp->dataPalette = NULL;
if ((bmp->bi).biBitCount == 24) {
task_read24(fp, &(bmp->bh), &(bmp->bi),
&(bmp->dataR), &(bmp->dataG), &(bmp->dataB));
} else if ((bmp->bi).biBitCount == 8) {
task_read_palette(fp, &bmp->bh, &bmp->bi, &bmp->dataPalette);
task_read8(fp, &bmp->bh, &bmp->bi,
&bmp->dataR, &bmp->dataG, &bmp->dataB, bmp->dataPalette);
xfree(bmp->dataPalette, IDPALETTE);
bmp->dataPalette = NULL;
} else if ((bmp->bi).biBitCount == 4) {
task_read_palette(fp, &bmp->bh, &bmp->bi, &bmp->dataPalette);
task_read4(fp, &bmp->bh, &bmp->bi,
&bmp->dataR, &bmp->dataG, &bmp->dataB, bmp->dataPalette);
xfree(bmp->dataPalette, IDPALETTE);
bmp->dataPalette = NULL;
}
if (!(bmp->dataR && bmp->dataG && bmp->dataB)) {
xfree(bmp->dataR, IDRGB);
xfree(bmp->dataG, IDRGB);
xfree(bmp->dataB, IDRGB);
return 0;
}
return 1;
}
void BMP24_write(FILE *fp, struct BMP24 *bmp) {
task_write24(fp, &bmp->bh, &bmp->bi,
bmp->dataR, bmp->dataG, bmp->dataB);
}
void BMP24_release(struct BMP24 *bmp) {
if (bmp->dataR) xfree(bmp->dataR, IDRGB);
if (bmp->dataG) xfree(bmp->dataG, IDRGB);
if (bmp->dataB) xfree(bmp->dataB, IDRGB);
if (bmp->dataPalette) xfree(bmp->dataPalette, IDPALETTE);
}
/* ------------------------------------------------------------------------- */
void task_bmp2pgm(FILE *fpbmp, FILE *fppgm) {
struct BMP24 *bmp;
long Width, Height, y, x;
bmp = xmalloc(sizeof(struct BMP24), IDBMP);
if (!BMP24_read(fpbmp, bmp)) {
fprintf(stderr
, "not a bitmap file, aborted.\n"); xfree(bmp, IDBMP);
return;
}
Width = iabs((bmp->bi).biWidth);
Height = iabs((bmp->bi).biHeight);
fprintf(fppgm
, "%ld %ld\n", Width
, Height
); if ((bmp->bi).biHeight < 0) {
for (y = 0; y < Height; y++) {
for (x = 0; x < Width; x++) {
fprintf(fppgm
, "%3d ", bmp
->dataR
[y
* Width
+ x
]); fprintf(fppgm
, "%3d ", bmp
->dataG
[y
* Width
+ x
]); fprintf(fppgm
, "%3d ", bmp
->dataB
[y
* Width
+ x
]); }
}
} else {
for (y = Height - 1; y >= 0; y--) {
for (x = 0; x < Width; x++) {
fprintf(fppgm
, "%3d ", bmp
->dataR
[y
* Width
+ x
]); fprintf(fppgm
, "%3d ", bmp
->dataG
[y
* Width
+ x
]); fprintf(fppgm
, "%3d ", bmp
->dataB
[y
* Width
+ x
]); }
}
}
BMP24_release(bmp);
xfree(bmp, IDBMP);
}
int main(int argc, char **argv) {
FILE *fpbmp, *fppgm;
if (argc != 3) {
fprintf(stderr
, "usage: %s <filename:bmp> <filename:pgm>\n", argv
[0]); }
if ((fpbmp
= fopen(argv
[1], "r")) == 0) { fprintf(stderr
, "cannot open the .bmp file for reading\n"); }
if ((fppgm
= fopen(argv
[2], "w")) == 0) { fprintf(stderr
, "cannot open the .bgm file for writing\n"); }
task_bmp2pgm(fpbmp, fppgm);
xmallocdump();
return 0;
}
/* end */
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPGFzc2VydC5oPgojaW5jbHVkZSA8bWF0aC5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CgovKiAjZGVmaW5lIERFQlVHICovCiNpZiBkZWZpbmVkKERFQlVHKQojaW5jbHVkZSAieG1hbGxvYy5oIgojZWxzZQojZGVmaW5lIHhtYWxsb2MoeCwgeSkgbWFsbG9jKHgpCiNkZWZpbmUgeGZyZWUoeCwgeSkgZnJlZSh4KQojZGVmaW5lIHhyZWFsbG9jKHgsIHksIHopIHJlYWxsb2MoeCwgeSkKI2RlZmluZSB4bWFsbG9jZHVtcCgpCiNlbmRpZgovKiBmb3IgeG1hbGxvYy5jICovCiNkZWZpbmUgSURSR0IgICAgIDEwMDEKI2RlZmluZSBJRFBBTEVUVEUgMTAwMgojZGVmaW5lIElEQk1QICAgICAxMDAzCgojZGVmaW5lIE5CWVRFICAxCiNkZWZpbmUgTldPUkQgIDIKI2RlZmluZSBORFdPUkQgNAoKaW50IExpdHRsZUVuZGlhblJlYWQodW5zaWduZWQgbG9uZyAqZGF0YSwgaW50IHNpemUsIEZJTEUgKmZwKSB7CiAgdW5zaWduZWQgY2hhciBsc2I7CiAgdW5zaWduZWQgbG9uZyBtc2I7CiAgaWYgKHNpemUgPT0gMCkgewogICAgKmRhdGEgPSAwOwogICAgcmV0dXJuIDE7CiAgfQogIGlmIChmcmVhZCgmbHNiLCAxLCAxLCBmcCkgIT0gMSkKICAgIHJldHVybiAtMTsKICBpZiAoTGl0dGxlRW5kaWFuUmVhZCgmbXNiLCBzaXplIC0gMSwgZnApIDwgMCkKICAgIHJldHVybiAtMTsKICAqZGF0YSA9ICh1bnNpZ25lZCBsb25nKWxzYiB8IChtc2IgPDwgOCk7CiAgcmV0dXJuIDE7Cn0KCnR5cGVkZWYgc3RydWN0IHsKICB1bnNpZ25lZCBsb25nIGJmVHlwZTE7CiAgdW5zaWduZWQgbG9uZyBiZlR5cGUyOwogIHVuc2lnbmVkIGxvbmcgYmZTaXplOwogIHVuc2lnbmVkIGxvbmcgYmZSZXNlcnZlZDE7CiAgdW5zaWduZWQgbG9uZyBiZlJlc2VydmVkMjsKICB1bnNpZ25lZCBsb25nIGJmT2ZmQml0czsKfSBCaXRtYXBGaWxlSGVhZGVyOwoKaW50IGJtSGVhZGVyQ2hlY2soRklMRSAqZnAsIEJpdG1hcEZpbGVIZWFkZXIgKmJoKSB7CiAgYXNzZXJ0KHNpemVvZih1bnNpZ25lZCBsb25nKSA+PSA0KTsKICBpZiAoTGl0dGxlRW5kaWFuUmVhZCgmKGJoLT5iZlR5cGUxKSwgTkJZVEUsIGZwKSA8IDApCiAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgaWYgKExpdHRsZUVuZGlhblJlYWQoJihiaC0+YmZUeXBlMiksIE5CWVRFLCBmcCkgPCAwKQogICAgZ290byBlcnJvcl9Ob3RSZWFkOwogIGlmIChMaXR0bGVFbmRpYW5SZWFkKCZiaC0+YmZTaXplLCBORFdPUkQsIGZwKSA8IDApCiAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgaWYgKExpdHRsZUVuZGlhblJlYWQoJmJoLT5iZlJlc2VydmVkMSwgTldPUkQsIGZwKSA8IDApCiAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgaWYgKExpdHRsZUVuZGlhblJlYWQoJmJoLT5iZlJlc2VydmVkMiwgTldPUkQsIGZwKSA8IDApCiAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgaWYgKExpdHRsZUVuZGlhblJlYWQoJmJoLT5iZk9mZkJpdHMsIE5EV09SRCwgZnApIDwgMCkKICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKI2lmIDAKICBwcmludGYoInJlYWQ6YmZUeXBlMTogJWNcbiIsIChjaGFyKWJoLT5iZlR5cGUxKTsKICBwcmludGYoInJlYWQ6YmZUeXBlMjogJWNcbiIsIChjaGFyKWJoLT5iZlR5cGUyKTsKICBwcmludGYoInJlYWQ6YmZTaXplOiAlbHVcbiIsIGJoLT5iZlNpemUpOwogIHByaW50ZigicmVhZDpiZlJlc2VydmVkMTogJWx1XG4iLCBiaC0+YmZSZXNlcnZlZDEpOwogIHByaW50ZigicmVhZDpiZlJlc2VydmVkMjogJWx1XG4iLCBiaC0+YmZSZXNlcnZlZDIpOwogIHByaW50ZigicmVhZDpiZk9mZkJpdHM6ICVsdVxuIiwgYmgtPmJmT2ZmQml0cyk7CiAgcHV0Y2hhcignXG4nKTsKI2VuZGlmCiAgaWYgKGJoLT5iZlR5cGUxICE9ICdCJyB8fCBiaC0+YmZUeXBlMiAhPSAnTScpCiAgICBnb3RvIGVycm9yX05vdEJpdG1hcDsKICBpZiAoYmgtPmJmUmVzZXJ2ZWQxICE9IDAgfHwgYmgtPmJmUmVzZXJ2ZWQyICE9IDApCiAgICBnb3RvIGVycm9yX05vdEJpdG1hcDsKICByZXR1cm4gMTsKCmVycm9yX05vdEJpdG1hcDoKICBmcHJpbnRmKHN0ZGVyciwgImNhbm5vdCBmaW5kIGJtcCBoZWFkZXJcbiIpOwogIHJldHVybiAwOwplcnJvcl9Ob3RSZWFkOgogIGZwcmludGYoc3RkZXJyLCAiY2Fubm90IHJlYWQgYm1wIGhlYWRlclxuIik7CiAgcmV0dXJuIDA7Cn0KCnR5cGVkZWYgc3RydWN0IHsKICB1bnNpZ25lZCBsb25nIGJpU2l6ZTsKICBsb25nIGJpV2lkdGg7CiAgbG9uZyBiaUhlaWdodDsKICB1bnNpZ25lZCBsb25nIGJpUGxhbmVzOwogIHVuc2lnbmVkIGxvbmcgYmlCaXRDb3VudDsKICB1bnNpZ25lZCBsb25nIGJpQ29tcHJlc3Npb247CiAgdW5zaWduZWQgbG9uZyBiaVNpemVJbWFnZTsKICBsb25nIGJpWFBpeFBlck1ldGVyOwogIGxvbmcgYmlZUGl4UGVyTWV0ZXI7CiAgdW5zaWduZWQgbG9uZyBiaUNsclVzZWQ7CiAgdW5zaWduZWQgbG9uZyBiaUNsckltcG9ydGFudDsKfSBCaXRtYXBJbmZvSGVhZGVyOwoKaW50IGJtSW5mb0hlYWRlckNoZWNrKEZJTEUgKmZwLCBCaXRtYXBJbmZvSGVhZGVyICpiaSkgewogIGFzc2VydChzaXplb2YodW5zaWduZWQgbG9uZykgPj0gNCk7CiAgYXNzZXJ0KHNpemVvZihsb25nKSA+PSA0KTsKICBpZiAoTGl0dGxlRW5kaWFuUmVhZCgmYmktPmJpU2l6ZSwgTkRXT1JELCBmcCkgPCAwKQogICAgZ290byBlcnJvcl9Ob3RSZWFkOwogIGlmIChiaS0+YmlTaXplID09IDEyKSB7CiAgICAvKiBub3Qgc3VwcG9ydGVkICovCiAgfSBlbHNlIGlmIChiaS0+YmlTaXplID09IDQwKSB7CiAgICBpZiAoTGl0dGxlRW5kaWFuUmVhZCgodW5zaWduZWQgbG9uZyAqKSZiaS0+YmlXaWR0aCwgTkRXT1JELCBmcCkgPCAwKQogICAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgICBpZiAoTGl0dGxlRW5kaWFuUmVhZCgodW5zaWduZWQgbG9uZyAqKSZiaS0+YmlIZWlnaHQsIE5EV09SRCwgZnApIDwgMCkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKExpdHRsZUVuZGlhblJlYWQoJmJpLT5iaVBsYW5lcywgTldPUkQsIGZwKSA8IDApCiAgICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKICAgIGlmIChMaXR0bGVFbmRpYW5SZWFkKCZiaS0+YmlCaXRDb3VudCwgTldPUkQsIGZwKSA8IDApCiAgICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKICAgIGlmIChMaXR0bGVFbmRpYW5SZWFkKCZiaS0+YmlDb21wcmVzc2lvbiwgTkRXT1JELCBmcCkgPCAwKQogICAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgICBpZiAoTGl0dGxlRW5kaWFuUmVhZCgmYmktPmJpU2l6ZUltYWdlLCBORFdPUkQsIGZwKSA8IDApCiAgICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKICAgIGlmIChMaXR0bGVFbmRpYW5SZWFkKCh1bnNpZ25lZCBsb25nICopJmJpLT5iaVhQaXhQZXJNZXRlciwgTkRXT1JELCBmcCkgPCAwKQogICAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgICBpZiAoTGl0dGxlRW5kaWFuUmVhZCgodW5zaWduZWQgbG9uZyAqKSZiaS0+YmlZUGl4UGVyTWV0ZXIsIE5EV09SRCwgZnApIDwgMCkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKExpdHRsZUVuZGlhblJlYWQoJmJpLT5iaUNsclVzZWQsIE5EV09SRCwgZnApIDwgMCkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKExpdHRsZUVuZGlhblJlYWQoJmJpLT5iaUNsckltcG9ydGFudCwgTkRXT1JELCBmcCkgPCAwKQogICAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgfSBlbHNlIHsKICAgIGdvdG8gZXJyb3JfTm90U3VwcG9ydGVkMTsKICB9CiNpZiAwCiAgcHJpbnRmKCJyZWFkOmJpU2l6ZTogJWx1XG4iLCBiaS0+YmlTaXplKTsKICBwcmludGYoInJlYWQ6YmlXaWR0aDogJWxkXG4iLCBiaS0+YmlXaWR0aCk7CiAgcHJpbnRmKCJyZWFkOmJpSGVpZ2h0OiAlbGRcbiIsIGJpLT5iaUhlaWdodCk7CiAgcHJpbnRmKCJyZWFkOmJpUGxhbmVzOiAlbHVcbiIsIGJpLT5iaVBsYW5lcyk7CiAgcHJpbnRmKCJyZWFkOmJpQml0Y291bnQ6ICVsdVxuIiwgYmktPmJpQml0Q291bnQpOwogIGlmIChiaS0+YmlTaXplID09IDQwKSB7CiAgICBwcmludGYoInJlYWQ6YmlDb21wcmVzc2lvbjogJWx1XG4iLCBiaS0+YmlDb21wcmVzc2lvbik7CiAgICBwcmludGYoInJlYWQ6YmlTaXplSW1hZ2U6ICVsdVxuIiwgYmktPmJpU2l6ZUltYWdlKTsKICAgIHByaW50ZigicmVhZDpiaVhQaXhQZXJNZXRlciAlbGRcbiIsIGJpLT5iaVhQaXhQZXJNZXRlcik7CiAgICBwcmludGYoInJlYWQ6YmlZUGl4UGVyTWV0ZXIgJWxkXG4iLCBiaS0+YmlZUGl4UGVyTWV0ZXIpOwogICAgcHJpbnRmKCJyZWFkOmJpQ2xyVXNlZDogJWx1XG4iLCBiaS0+YmlDbHJVc2VkKTsKICAgIHByaW50ZigicmVhZDpiaUNsckltcG9yYW50OiAlbHVcbiIsIGJpLT5iaUNsckltcG9ydGFudCk7CiAgfQojZW5kaWYKICBpZiAoYmktPmJpU2l6ZSAhPSA0MCkKICAgIGdvdG8gZXJyb3JfTm90U3VwcG9ydGVkMTsKICBpZiAoYmktPmJpUGxhbmVzICE9IDEpCiAgICBnb3RvIGVycm9yX05vdFN1cHBvcnRlZDI7CiAgaWYgKGJpLT5iaUJpdENvdW50ICE9IDI0ICYmIGJpLT5iaUJpdENvdW50ICE9IDggJiYgYmktPmJpQml0Q291bnQgIT0gNCkKICAgIGdvdG8gZXJyb3JfTm90U3VwcG9ydGVkMzsKICBpZiAoYmktPmJpQ29tcHJlc3Npb24gIT0gMCkKICAgIGdvdG8gZXJyb3JfTm90U3VwcG9ydGVkNDsKICByZXR1cm4gMTsKCmVycm9yX05vdFN1cHBvcnRlZDE6CiAgZnByaW50ZihzdGRlcnIsICJpbmZvIGhlYWRlciBzaXplOiAlbHUsIHRoaXMgZm9ybWF0IGlzIG5vdCBzdXBwb3J0ZWRcbiIsIGJpLT5iaVNpemUpOwogIHJldHVybiAwOwplcnJvcl9Ob3RTdXBwb3J0ZWQyOgogIGZwcmludGYoc3RkZXJyLCAiYmlQbGFuZXM6ICVsdSwgdGhpcyBmb3JtYXQgaXMgbm90IHN1cHBvcnRlZFxuIiwgYmktPmJpUGxhbmVzKTsKICByZXR1cm4gMDsKZXJyb3JfTm90U3VwcG9ydGVkMzoKICBmcHJpbnRmKHN0ZGVyciwgImJpQml0Q291bnQ6ICVsdSwgdGhpcyBmb3JtYXQgaXMgbm90IHN1cHBvcnRlZFxuIiwgYmktPmJpQml0Q291bnQpOwogIHJldHVybiAwOwplcnJvcl9Ob3RTdXBwb3J0ZWQ0OgogIGZwcmludGYoc3RkZXJyLCAiYmlDb21wcmVzc2lvbjogJWx1LCB0aGlzIGZvcm1hdCBpcyBub3Qgc3VwcG9ydGVkXG4iLCBiaS0+YmlDb21wcmVzc2lvbik7CiAgcmV0dXJuIDA7CmVycm9yX05vdFJlYWQ6CiNpZiAwCiAgcHJpbnRmKCJyZWFkOmJpU2l6ZTogJWx1XG4iLCBiaS0+YmlTaXplKTsKICBwcmludGYoInJlYWQ6YmlXaWR0aDogJWxkXG4iLCBiaS0+YmlXaWR0aCk7CiAgcHJpbnRmKCJyZWFkOmJpSGVpZ2h0OiAlbGRcbiIsIGJpLT5iaUhlaWdodCk7CiAgcHJpbnRmKCJyZWFkOmJpUGxhbmVzOiAlbHVcbiIsIGJpLT5iaVBsYW5lcyk7CiAgcHJpbnRmKCJyZWFkOmJpQml0Y291bnQ6ICVsdVxuIiwgYmktPmJpQml0Q291bnQpOwogIGlmIChiaS0+YmlTaXplID09IDQwKSB7CiAgICBwcmludGYoInJlYWQ6YmlDb21wcmVzc2lvbjogJWx1XG4iLCBiaS0+YmlDb21wcmVzc2lvbik7CiAgICBwcmludGYoInJlYWQ6YmlTaXplSW1hZ2U6ICVsdVxuIiwgYmktPmJpU2l6ZUltYWdlKTsKICAgIHByaW50ZigicmVhZDpiaVhQaXhQZXJNZXRlciAlbGRcbiIsIGJpLT5iaVhQaXhQZXJNZXRlcik7CiAgICBwcmludGYoInJlYWQ6YmlZUGl4UGVyTWV0ZXIgJWxkXG4iLCBiaS0+YmlZUGl4UGVyTWV0ZXIpOwogICAgcHJpbnRmKCJyZWFkOmJpQ2xyVXNlZDogJWx1XG4iLCBiaS0+YmlDbHJVc2VkKTsKICAgIHByaW50ZigicmVhZDpiaUNsckltcG9yYW50OiAlbHVcbiIsIGJpLT5iaUNsckltcG9ydGFudCk7CiAgfQojZW5kaWYKICBmcHJpbnRmKHN0ZGVyciwgImNhbm5vdCByZWFkIGJtcCBpbmZvIGhlYWRlclxuIik7CiAgcmV0dXJuIDA7Cn0KCmludCBpc0Z0ZWxsR29vZChGSUxFICpmcCwgdW5zaWduZWQgbG9uZyBwb3MpIHsKICByZXR1cm4gKHVuc2lnbmVkIGxvbmcpZnRlbGwoZnApID09IHBvczsKfQoKbG9uZyBpYWJzKGxvbmcgbikgewogIHJldHVybiAobiA+IDApID8gbiA6IC1uOwp9CgoKdm9pZCB0YXNrX3JlYWQyNChGSUxFICpmcCwgQml0bWFwRmlsZUhlYWRlciAqYmhlYWRlciwgQml0bWFwSW5mb0hlYWRlciAqYmluZm8sCiAgICAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgKipkYXRhUiwgdW5zaWduZWQgY2hhciAqKmRhdGFHLAogICAgICAgICAgICAgICB1bnNpZ25lZCBjaGFyICoqZGF0YUIpCnsKICBsb25nIHgsIHksIG47CiAgdW5zaWduZWQgY2hhciBkdW1teTsKICBpbnQgYzsKICBpZiAoIWlzRnRlbGxHb29kKGZwLCBiaGVhZGVyLT5iZk9mZkJpdHMpKSB7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkhlYWRlciBvciBJbWFnZSBEYXRhIGlzIGNvcnJ1cHRlZC5cbiIpOwogICAgcmV0dXJuOwogIH0KICAqZGF0YVIgPSB4bWFsbG9jKHNpemVvZihjaGFyKSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICogaWFicyhiaW5mby0+YmlIZWlnaHQpLCBJRFJHQik7CiAgKmRhdGFHID0geG1hbGxvYyhzaXplb2YoY2hhcikgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSAqIGlhYnMoYmluZm8tPmJpSGVpZ2h0KSwgSURSR0IpOwogICpkYXRhQiA9IHhtYWxsb2Moc2l6ZW9mKGNoYXIpICogaWFicyhiaW5mby0+YmlXaWR0aCkgKiBpYWJzKGJpbmZvLT5iaUhlaWdodCksIElEUkdCKTsgIAogIGlmICgqZGF0YVIgPT0gTlVMTCB8fCAqZGF0YUcgPT0gTlVMTCB8fCAqZGF0YUIgPT0gTlVMTCkgewogICAgZnByaW50ZihzdGRlcnIsICJjYW5ub3QgYWxsb2MuIGVub3VnaCBtZW1vcnkuXG4iKTsKICAgIHJldHVybjsKICB9CiAgZm9yICh5ID0gMDsgeSA8IGlhYnMoYmluZm8tPmJpSGVpZ2h0KTsgeSsrKSB7CiAgICBjID0gMDsKICAgIGZvciAoeCA9IDA7IHggPCBpYWJzKGJpbmZvLT5iaVdpZHRoKTsgeCsrKSB7CiAgICAgIGZyZWFkKCgqZGF0YUIgKyB5ICogaWFicyhiaW5mby0+YmlXaWR0aCkgKyB4KSwgMSwgMSwgZnApOwogICAgICBmcmVhZCgoKmRhdGFHICsgeSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICsgeCksIDEsIDEsIGZwKTsKICAgICAgZnJlYWQoKCpkYXRhUiArIHkgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSArIHgpLCAxLCAxLCBmcCk7CiAgICAgIGMgKz0gMzsKICAgIH0KICAgIHdoaWxlIChjICUgNCAhPSAwKSB7CiAgICAgIGZyZWFkKCZkdW1teSwgMSwgMSwgZnApOwogICAgICBjKys7CiAgICB9CiAgfQogIG4gPSBpYWJzKGJpbmZvLT5iaVdpZHRoKSAqIDM7CiAgaWYgKG4gJSA0ID4gMCkKICAgIG4gKz0gNCAtIChuICUgNCk7CiAgYmluZm8tPmJpU2l6ZUltYWdlID0gbiAqIGlhYnMoYmluZm8tPmJpSGVpZ2h0KTsKICBiaGVhZGVyLT5iZlNpemUgPSBiaW5mby0+YmlTaXplSW1hZ2UgKyBiaW5mby0+YmlTaXplICsgMTQ7Cn0KCnZvaWQgdGFza19yZWFkX3BhbGV0dGUoRklMRSAqZnAsIEJpdG1hcEZpbGVIZWFkZXIgKmJoLCBCaXRtYXBJbmZvSGVhZGVyICpiaSwKICAgICAgICAgICAgICAgICAgICAgICB1bnNpZ25lZCBjaGFyICoqZGF0YVBhbGV0dGUpCnsKICBpbnQgaSwgbWF4OwogIHVuc2lnbmVkIGNoYXIgZHVtbXk7CiAgaWYgKChtYXggPSBiaS0+YmlDbHJVc2VkKSA9PSAwKSB7CiAgICBzd2l0Y2ggKGJpLT5iaUJpdENvdW50KSB7CiAgICBjYXNlIDQ6CiAgICAgIG1heCA9IDE2OwogICAgICBicmVhazsKICAgIGNhc2UgODoKICAgICAgbWF4ID0gMjU2OwogICAgICBicmVhazsKICAgIH0KICB9CiAgKmRhdGFQYWxldHRlID0geG1hbGxvYyhzaXplb2YoY2hhcikgKiAzICogbWF4LCBJRFBBTEVUVEUpOwogIGlmICgqZGF0YVBhbGV0dGUgPT0gTlVMTCkgewogICAgZnByaW50ZihzdGRlcnIsICJjYW5ub3QgYWxsb2MuIGVub3VnaCBtZW1vcnkuXG4iKTsKICAgIHJldHVybjsKICB9CiAgZm9yIChpID0gMDsgaSA8IG1heDsgaSsrKSB7CiAgICBmcmVhZCgoKmRhdGFQYWxldHRlICsgMyAqIGkgKyAwKSwgMSwgMSwgZnApOwogICAgZnJlYWQoKCpkYXRhUGFsZXR0ZSArIDMgKiBpICsgMSksIDEsIDEsIGZwKTsKICAgIGZyZWFkKCgqZGF0YVBhbGV0dGUgKyAzICogaSArIDIpLCAxLCAxLCBmcCk7CiAgICBmcmVhZCgmZHVtbXksIDEsIDEsIGZwKTsgICAgCiAgfQp9Cgp2b2lkIHRhc2tfcmVhZDgoRklMRSAqZnAsIEJpdG1hcEZpbGVIZWFkZXIgKmJoZWFkZXIsIEJpdG1hcEluZm9IZWFkZXIgKmJpbmZvLAogICAgICAgICAgICAgICB1bnNpZ25lZCBjaGFyICoqZGF0YVIsIHVuc2lnbmVkIGNoYXIgKipkYXRhRywKICAgICAgICAgICAgICAgdW5zaWduZWQgY2hhciAqKmRhdGFCLCB1bnNpZ25lZCBjaGFyICpkYXRhUGFsZXR0ZSkKewogIGxvbmcgeCwgeSwgbjsKICB1bnNpZ25lZCBjaGFyIGRhdGE7CiAgaW50IGM7CgogIGlmICghaXNGdGVsbEdvb2QoZnAsIGJoZWFkZXItPmJmT2ZmQml0cykpIHsKICAgIGZwcmludGYoc3RkZXJyLCAiSGVhZGVyIG9yIEltYWdlIERhdGEgaXMgY29ycnVwdGVkLlxuIik7CiAgICByZXR1cm47CiAgfQogICpkYXRhUiA9IHhtYWxsb2Moc2l6ZW9mKGNoYXIpICogaWFicyhiaW5mby0+YmlXaWR0aCkgKiBpYWJzKGJpbmZvLT5iaUhlaWdodCksIElEUkdCKTsKICAqZGF0YUcgPSB4bWFsbG9jKHNpemVvZihjaGFyKSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICogaWFicyhiaW5mby0+YmlIZWlnaHQpLCBJRFJHQik7CiAgKmRhdGFCID0geG1hbGxvYyhzaXplb2YoY2hhcikgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSAqIGlhYnMoYmluZm8tPmJpSGVpZ2h0KSwgSURSR0IpOyAgCiAgaWYgKCpkYXRhUiA9PSBOVUxMIHx8ICpkYXRhRyA9PSBOVUxMIHx8ICpkYXRhQiA9PSBOVUxMKSB7CiAgICBmcHJpbnRmKHN0ZGVyciwgImNhbm5vdCBhbGxvYy4gZW5vdWdoIG1lbW9yeS5cbiIpOwogICAgcmV0dXJuOwogIH0KICBmb3IgKHkgPSAwOyB5IDwgaWFicyhiaW5mby0+YmlIZWlnaHQpOyB5KyspIHsKICAgIGMgPSAwOwogICAgZm9yICh4ID0gMDsgeCA8IGlhYnMoYmluZm8tPmJpV2lkdGgpOyB4KyspIHsKICAgICAgZnJlYWQoJmRhdGEsIDEsIDEsIGZwKTsKICAgICAgKigqZGF0YUIgKyB5ICogaWFicyhiaW5mby0+YmlXaWR0aCkgKyB4KSA9IGRhdGFQYWxldHRlWzMgKiBkYXRhICsgMF07CiAgICAgICooKmRhdGFHICsgeSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICsgeCkgPSBkYXRhUGFsZXR0ZVszICogZGF0YSArIDFdOwogICAgICAqKCpkYXRhUiArIHkgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSArIHgpID0gZGF0YVBhbGV0dGVbMyAqIGRhdGEgKyAyXTsKICAgICAgYysrOwogICAgfQogICAgd2hpbGUgKGMgJSA0ICE9IDApIHsKICAgICAgZnJlYWQoJmRhdGEsIDEsIDEsIGZwKTsKICAgICAgYysrOwogICAgfQogIH0KICBuID0gaWFicyhiaW5mby0+YmlXaWR0aCkgKiAzOwogIGlmIChuICUgNCA+IDApCiAgICBuICs9IDQgLSAobiAlIDQpOwogIGJpbmZvLT5iaVNpemVJbWFnZSA9IG4gKiBpYWJzKGJpbmZvLT5iaUhlaWdodCk7CiAgYmhlYWRlci0+YmZTaXplID0gYmluZm8tPmJpU2l6ZUltYWdlICsgYmluZm8tPmJpU2l6ZSArIDE0OwogIGJoZWFkZXItPmJmT2ZmQml0cyA9IDU0OwogIGJpbmZvLT5iaUJpdENvdW50ID0gMjQ7CiAgYmluZm8tPmJpQ2xyVXNlZCA9IDA7CiAgYmluZm8tPmJpQ2xySW1wb3J0YW50ID0gMDsKfQoKdm9pZCB0YXNrX3JlYWQ0KEZJTEUgKmZwLCBCaXRtYXBGaWxlSGVhZGVyICpiaGVhZGVyLCBCaXRtYXBJbmZvSGVhZGVyICpiaW5mbywKICAgICAgICAgICAgICAgdW5zaWduZWQgY2hhciAqKmRhdGFSLCB1bnNpZ25lZCBjaGFyICoqZGF0YUcsCiAgICAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgKipkYXRhQiwgdW5zaWduZWQgY2hhciAqZGF0YVBhbGV0dGUpCnsKICBsb25nIHgsIHksIG47CiAgdW5zaWduZWQgY2hhciBkYXRhLCByZGF0YTsKICBpbnQgYzsKICBpbnQgYml0SGlnaExvdzsKCiAgaWYgKCFpc0Z0ZWxsR29vZChmcCwgYmhlYWRlci0+YmZPZmZCaXRzKSkgewogICAgZnByaW50ZihzdGRlcnIsICJIZWFkZXIgb3IgSW1hZ2UgRGF0YSBpcyBjb3JydXB0ZWQuXG4iKTsKICAgIHJldHVybjsKICB9CiAgKmRhdGFSID0geG1hbGxvYyhzaXplb2YoY2hhcikgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSAqIGlhYnMoYmluZm8tPmJpSGVpZ2h0KSwgSURSR0IpOwogICpkYXRhRyA9IHhtYWxsb2Moc2l6ZW9mKGNoYXIpICogaWFicyhiaW5mby0+YmlXaWR0aCkgKiBpYWJzKGJpbmZvLT5iaUhlaWdodCksIElEUkdCKTsKICAqZGF0YUIgPSB4bWFsbG9jKHNpemVvZihjaGFyKSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICogaWFicyhiaW5mby0+YmlIZWlnaHQpLCBJRFJHQik7ICAKICBpZiAoKmRhdGFSID09IE5VTEwgfHwgKmRhdGFHID09IE5VTEwgfHwgKmRhdGFCID09IE5VTEwpIHsKICAgIGZwcmludGYoc3RkZXJyLCAiY2Fubm90IGFsbG9jLiBlbm91Z2ggbWVtb3J5LlxuIik7CiAgICByZXR1cm47CiAgfQogIGJpdEhpZ2hMb3cgPSAxOwogIGZvciAoeSA9IDA7IHkgPCBpYWJzKGJpbmZvLT5iaUhlaWdodCk7IHkrKykgewogICAgYyA9IDA7CiAgICBmb3IgKHggPSAwOyB4IDwgaWFicyhiaW5mby0+YmlXaWR0aCk7IHgrKykgewogICAgICBpZiAoYml0SGlnaExvdykgewogICAgICAgIGZyZWFkKCZyZGF0YSwgMSwgMSwgZnApOwogICAgICAgIGRhdGEgPSByZGF0YSAmIDB4ZjA7CiAgICAgICAgZGF0YSA+Pj0gNDsKICAgICAgICBiaXRIaWdoTG93ID0gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICBkYXRhID0gcmRhdGEgJiAweDBmOwogICAgICAgIGJpdEhpZ2hMb3cgPSAxOwogICAgICB9CiAgICAgICooKmRhdGFCICsgeSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICsgeCkgPSBkYXRhUGFsZXR0ZVszICogZGF0YSArIDBdOwogICAgICAqKCpkYXRhRyArIHkgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSArIHgpID0gZGF0YVBhbGV0dGVbMyAqIGRhdGEgKyAxXTsKICAgICAgKigqZGF0YVIgKyB5ICogaWFicyhiaW5mby0+YmlXaWR0aCkgKyB4KSA9IGRhdGFQYWxldHRlWzMgKiBkYXRhICsgMl07CiAgICAgIGMrKzsKICAgIH0KICAgIHdoaWxlIChjICUgNCAhPSAwKSB7CiAgICAgIGZyZWFkKCZkYXRhLCAxLCAxLCBmcCk7CiAgICAgIGMrKzsKICAgIH0KICB9CiAgbiA9IGlhYnMoYmluZm8tPmJpV2lkdGgpICogMzsKICBpZiAobiAlIDQgPiAwKQogICAgbiArPSA0IC0gKG4gJSA0KTsKICBiaW5mby0+YmlTaXplSW1hZ2UgPSBuICogaWFicyhiaW5mby0+YmlIZWlnaHQpOwogIGJoZWFkZXItPmJmU2l6ZSA9IGJpbmZvLT5iaVNpemVJbWFnZSArIGJpbmZvLT5iaVNpemUgKyAxNDsKICBiaGVhZGVyLT5iZk9mZkJpdHMgPSA1NDsKICBiaW5mby0+YmlCaXRDb3VudCA9IDI0OwogIGJpbmZvLT5iaUNsclVzZWQgPSAwOwogIGJpbmZvLT5iaUNsckltcG9ydGFudCA9IDA7Cn0KCnZvaWQgTGl0dGxlRW5kaWFuV3JpdGUodW5zaWduZWQgbG9uZyAqZGF0YSwgaW50IHNpemUsIEZJTEUgKmZwKSB7CiAgdW5zaWduZWQgY2hhciBsc2I7CiAgdW5zaWduZWQgbG9uZyBtc2I7CiAgaWYgKHNpemUgPT0gMCkKICAgIHJldHVybjsKICBsc2IgPSAodW5zaWduZWQgY2hhcikoKmRhdGEgJiAweGZmKTsKICBmd3JpdGUoJmxzYiwgMSwgMSwgZnApOwogIG1zYiA9ICpkYXRhID4+IDg7CiAgTGl0dGxlRW5kaWFuV3JpdGUoJm1zYiwgc2l6ZSAtIDEsIGZwKTsKfQoKdm9pZCB0YXNrX3dyaXRlX2hlYWRlcihGSUxFICpmcCwgQml0bWFwRmlsZUhlYWRlciAqYmgpIHsKICBhc3NlcnQoc2l6ZW9mKHVuc2lnbmVkIGxvbmcpID49IDQpOwogIGFzc2VydChzaXplb2YobG9uZykgPj0gNCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoJihiaC0+YmZUeXBlMSksIE5CWVRFLCBmcCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoJihiaC0+YmZUeXBlMiksIE5CWVRFLCBmcCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoJihiaC0+YmZTaXplKSwgTkRXT1JELCBmcCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoJihiaC0+YmZSZXNlcnZlZDEpLCBOV09SRCwgZnApOwogIExpdHRsZUVuZGlhbldyaXRlKCYoYmgtPmJmUmVzZXJ2ZWQyKSwgTldPUkQsIGZwKTsKICBMaXR0bGVFbmRpYW5Xcml0ZSgmKGJoLT5iZk9mZkJpdHMpLCBORFdPUkQsIGZwKTsKI2lmIDAKICBwcmludGYoIndyaXRlOmJmVHlwZTE6ICVjXG4iLCAoY2hhciliaC0+YmZUeXBlMSk7CiAgcHJpbnRmKCJ3cml0ZTpiZlR5cGUyOiAlY1xuIiwgKGNoYXIpYmgtPmJmVHlwZTIpOwogIHByaW50Zigid3JpdGU6YmZTaXplOiAlbHVcbiIsIGJoLT5iZlNpemUpOwogIHByaW50Zigid3JpdGU6YmZSZXNlcnZlZDE6ICVsdVxuIiwgYmgtPmJmUmVzZXJ2ZWQxKTsKICBwcmludGYoIndyaXRlOmJmUmVzZXJ2ZWQyOiAlbHVcbiIsIGJoLT5iZlJlc2VydmVkMik7CiAgcHJpbnRmKCJ3cml0ZTpiZk9mZkJpdHM6ICVsdVxuIiwgYmgtPmJmT2ZmQml0cyk7CiNlbmRpZgp9Cgp2b2lkIHRhc2tfd3JpdGVfaW5mbyhGSUxFICpmcCwgQml0bWFwSW5mb0hlYWRlciAqYmkpIHsKICBhc3NlcnQoc2l6ZW9mKHVuc2lnbmVkIHNob3J0KSA9PSAyKTsKICBhc3NlcnQoc2l6ZW9mKHVuc2lnbmVkIGxvbmcpID09IDQpOwogIGFzc2VydChzaXplb2YobG9uZykgPT0gNCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoJihiaS0+YmlTaXplKSwgTkRXT1JELCBmcCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoKHVuc2lnbmVkIGxvbmcgKikmKGJpLT5iaVdpZHRoKSwgTkRXT1JELCBmcCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoKHVuc2lnbmVkIGxvbmcgKikmKGJpLT5iaUhlaWdodCksIE5EV09SRCwgZnApOwogIExpdHRsZUVuZGlhbldyaXRlKCYoYmktPmJpUGxhbmVzKSwgTldPUkQsIGZwKTsKICBMaXR0bGVFbmRpYW5Xcml0ZSgmKGJpLT5iaUJpdENvdW50KSwgTldPUkQsIGZwKTsKICBMaXR0bGVFbmRpYW5Xcml0ZSgmKGJpLT5iaUNvbXByZXNzaW9uKSwgTkRXT1JELCBmcCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoJihiaS0+YmlTaXplSW1hZ2UpLCBORFdPUkQsIGZwKTsKICBMaXR0bGVFbmRpYW5Xcml0ZSgodW5zaWduZWQgbG9uZyAqKSYoYmktPmJpWFBpeFBlck1ldGVyKSwgTkRXT1JELCBmcCk7CiAgTGl0dGxlRW5kaWFuV3JpdGUoKHVuc2lnbmVkIGxvbmcgKikmKGJpLT5iaVlQaXhQZXJNZXRlciksIE5EV09SRCwgZnApOwogIExpdHRsZUVuZGlhbldyaXRlKCYoYmktPmJpQ2xyVXNlZCksIE5EV09SRCwgZnApOwogIExpdHRsZUVuZGlhbldyaXRlKCYoYmktPmJpQ2xySW1wb3J0YW50KSwgTkRXT1JELCBmcCk7CiNpZiAwCiAgcHJpbnRmKCJ3cml0ZTpiaVNpemU6ICVsdVxuIiwgYmktPmJpU2l6ZSk7CiAgcHJpbnRmKCJ3cml0ZTpiaVdpZHRoOiAlbGRcbiIsIGJpLT5iaVdpZHRoKTsKICBwcmludGYoIndyaXRlOmJpSGVpZ2h0OiAlbGRcbiIsIGJpLT5iaUhlaWdodCk7CiAgcHJpbnRmKCJ3cml0ZTpiaVBsYW5lczogJWx1XG4iLCBiaS0+YmlQbGFuZXMpOwogIHByaW50Zigid3JpdGU6YmlCaXRjb3VudDogJWx1XG4iLCBiaS0+YmlCaXRDb3VudCk7CiAgcHJpbnRmKCJ3cml0ZTpiaUNvbXByZXNzaW9uOiAlbHVcbiIsIGJpLT5iaUNvbXByZXNzaW9uKTsKICBwcmludGYoIndyaXRlOmJpU2l6ZUltYWdlOiAlbHVcbiIsIGJpLT5iaVNpemVJbWFnZSk7CiAgcHJpbnRmKCJ3cml0ZTpiaVhQaXhQZXJNZXRlciAlbGRcbiIsIGJpLT5iaVhQaXhQZXJNZXRlcik7CiAgcHJpbnRmKCJ3cml0ZTpiaVlQaXhQZXJNZXRlciAlbGRcbiIsIGJpLT5iaVlQaXhQZXJNZXRlcik7CiAgcHJpbnRmKCJ3cml0ZTpiaUNsclVzZWQ6ICVsdVxuIiwgYmktPmJpQ2xyVXNlZCk7CiAgcHJpbnRmKCJ3cml0ZTpiaUNsckltcG9yYW50OiAlbHVcbiIsIGJpLT5iaUNsckltcG9ydGFudCk7CiNlbmRpZgp9Cgp2b2lkIHRhc2tfd3JpdGUyNChGSUxFICpmcCwKICAgICAgICAgICAgICAgICAgQml0bWFwRmlsZUhlYWRlciAqYmgsIEJpdG1hcEluZm9IZWFkZXIgKmJpLAogICAgICAgICAgICAgICAgICB1bnNpZ25lZCBjaGFyICpkYXRhUiwKICAgICAgICAgICAgICAgICAgdW5zaWduZWQgY2hhciAqZGF0YUcsCiAgICAgICAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgKmRhdGFCKSB7CiAgaW50IHgsIHk7CiAgaW50IGM7CiAgdW5zaWduZWQgY2hhciBkdW1teSA9ICdcMCc7CiAgdGFza193cml0ZV9oZWFkZXIoZnAsIGJoKTsKICB0YXNrX3dyaXRlX2luZm8oZnAsIGJpKTsKICBmb3IgKHkgPSAwOyB5IDwgaWFicyhiaS0+YmlIZWlnaHQpOyB5KyspIHsKICAgIGMgPSAwOwogICAgZm9yICh4ID0gMDsgeCA8IGlhYnMoYmktPmJpV2lkdGgpOyB4KyspIHsKICAgICAgZndyaXRlKCZkYXRhQlt5ICogaWFicyhiaS0+YmlXaWR0aCkgKyB4XSwgMSwgMSwgZnApOwogICAgICBmd3JpdGUoJmRhdGFHW3kgKiBpYWJzKGJpLT5iaVdpZHRoKSArIHhdLCAxLCAxLCBmcCk7CiAgICAgIGZ3cml0ZSgmZGF0YVJbeSAqIGlhYnMoYmktPmJpV2lkdGgpICsgeF0sIDEsIDEsIGZwKTsKICAgICAgYyArPSAzOwogICAgfQogICAgd2hpbGUgKGMgJSA0ICE9IDApIHsKICAgICAgZndyaXRlKCZkdW1teSwgMSwgMSwgZnApOwogICAgICBjKys7CiAgICB9CiAgfQp9CgovKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCnN0cnVjdCBCTVAyNCB7CiAgQml0bWFwRmlsZUhlYWRlciBiaDsKICBCaXRtYXBJbmZvSGVhZGVyIGJpOwogIHVuc2lnbmVkIGNoYXIgKmRhdGFSOwogIHVuc2lnbmVkIGNoYXIgKmRhdGFHOwogIHVuc2lnbmVkIGNoYXIgKmRhdGFCOwogIHVuc2lnbmVkIGNoYXIgKmRhdGFQYWxldHRlOwp9OwoKaW50IEJNUDI0X3JlYWQoRklMRSAqZnAsIHN0cnVjdCBCTVAyNCAqYm1wKSB7CiAgaWYgKCFibUhlYWRlckNoZWNrKGZwLCAmKGJtcC0+YmgpKSkKICAgIHJldHVybiAwOwogIGlmICghYm1JbmZvSGVhZGVyQ2hlY2soZnAsICYoYm1wLT5iaSkpKQogICAgcmV0dXJuIDA7CiAgYm1wLT5kYXRhUiA9IGJtcC0+ZGF0YUcgPSBibXAtPmRhdGFCID0gYm1wLT5kYXRhUGFsZXR0ZSA9IE5VTEw7CiAgaWYgKChibXAtPmJpKS5iaUJpdENvdW50ID09IDI0KSB7CiAgICB0YXNrX3JlYWQyNChmcCwgJihibXAtPmJoKSwgJihibXAtPmJpKSwKICAgICAgICAgICAgICAgICYoYm1wLT5kYXRhUiksICYoYm1wLT5kYXRhRyksICYoYm1wLT5kYXRhQikpOwogIH0gZWxzZSBpZiAoKGJtcC0+YmkpLmJpQml0Q291bnQgPT0gOCkgewogICAgdGFza19yZWFkX3BhbGV0dGUoZnAsICZibXAtPmJoLCAmYm1wLT5iaSwgJmJtcC0+ZGF0YVBhbGV0dGUpOwogICAgdGFza19yZWFkOChmcCwgJmJtcC0+YmgsICZibXAtPmJpLAogICAgICAgICAgICAgICAmYm1wLT5kYXRhUiwgJmJtcC0+ZGF0YUcsICZibXAtPmRhdGFCLCBibXAtPmRhdGFQYWxldHRlKTsKICAgIHhmcmVlKGJtcC0+ZGF0YVBhbGV0dGUsIElEUEFMRVRURSk7CiAgICBibXAtPmRhdGFQYWxldHRlID0gTlVMTDsKICB9IGVsc2UgaWYgKChibXAtPmJpKS5iaUJpdENvdW50ID09IDQpIHsKICAgIHRhc2tfcmVhZF9wYWxldHRlKGZwLCAmYm1wLT5iaCwgJmJtcC0+YmksICZibXAtPmRhdGFQYWxldHRlKTsKICAgIHRhc2tfcmVhZDQoZnAsICZibXAtPmJoLCAmYm1wLT5iaSwKICAgICAgICAgICAgICAgJmJtcC0+ZGF0YVIsICZibXAtPmRhdGFHLCAmYm1wLT5kYXRhQiwgYm1wLT5kYXRhUGFsZXR0ZSk7CiAgICB4ZnJlZShibXAtPmRhdGFQYWxldHRlLCBJRFBBTEVUVEUpOwogICAgYm1wLT5kYXRhUGFsZXR0ZSA9IE5VTEw7CiAgfQogIGlmICghKGJtcC0+ZGF0YVIgJiYgYm1wLT5kYXRhRyAmJiBibXAtPmRhdGFCKSkgewogICAgeGZyZWUoYm1wLT5kYXRhUiwgSURSR0IpOwogICAgeGZyZWUoYm1wLT5kYXRhRywgSURSR0IpOwogICAgeGZyZWUoYm1wLT5kYXRhQiwgSURSR0IpOwogICAgcmV0dXJuIDA7CiAgfQogIHJldHVybiAxOwp9Cgp2b2lkIEJNUDI0X3dyaXRlKEZJTEUgKmZwLCBzdHJ1Y3QgQk1QMjQgKmJtcCkgewogIHRhc2tfd3JpdGUyNChmcCwgJmJtcC0+YmgsICZibXAtPmJpLAogICAgICAgICAgICAgICBibXAtPmRhdGFSLCBibXAtPmRhdGFHLCBibXAtPmRhdGFCKTsKfQoKdm9pZCBCTVAyNF9yZWxlYXNlKHN0cnVjdCBCTVAyNCAqYm1wKSB7CiAgaWYgKGJtcC0+ZGF0YVIpIHhmcmVlKGJtcC0+ZGF0YVIsIElEUkdCKTsKICBpZiAoYm1wLT5kYXRhRykgeGZyZWUoYm1wLT5kYXRhRywgSURSR0IpOwogIGlmIChibXAtPmRhdGFCKSB4ZnJlZShibXAtPmRhdGFCLCBJRFJHQik7CiAgaWYgKGJtcC0+ZGF0YVBhbGV0dGUpIHhmcmVlKGJtcC0+ZGF0YVBhbGV0dGUsIElEUEFMRVRURSk7Cn0KCi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8Kdm9pZCB0YXNrX2JtcDJwZ20oRklMRSAqZnBibXAsIEZJTEUgKmZwcGdtKSB7CiAgc3RydWN0IEJNUDI0ICpibXA7CiAgbG9uZyBXaWR0aCwgSGVpZ2h0LCB5LCB4OwoKICBibXAgPSB4bWFsbG9jKHNpemVvZihzdHJ1Y3QgQk1QMjQpLCBJREJNUCk7CiAgaWYgKCFCTVAyNF9yZWFkKGZwYm1wLCBibXApKSB7CiAgICBmcHJpbnRmKHN0ZGVyciwgIm5vdCBhIGJpdG1hcCBmaWxlLCBhYm9ydGVkLlxuIik7CiAgICB4ZnJlZShibXAsIElEQk1QKTsKICAgIHJldHVybjsgICAgICAKICB9CiAgV2lkdGggPSBpYWJzKChibXAtPmJpKS5iaVdpZHRoKTsKICBIZWlnaHQgPSBpYWJzKChibXAtPmJpKS5iaUhlaWdodCk7CiAgZnByaW50ZihmcHBnbSwgIlA1XG4iKTsKICBmcHJpbnRmKGZwcGdtLCAiJWxkICVsZFxuIiwgV2lkdGgsIEhlaWdodCk7CiAgZnByaW50ZihmcHBnbSwgIjI1NVxuIik7CiAgaWYgKChibXAtPmJpKS5iaUhlaWdodCA8IDApIHsKICAgIGZvciAoeSA9IDA7IHkgPCBIZWlnaHQ7IHkrKykgewogICAgICBmb3IgKHggPSAwOyB4IDwgV2lkdGg7IHgrKykgewogICAgICAgIGZwcmludGYoZnBwZ20sICIlM2QgIiwgYm1wLT5kYXRhUlt5ICogV2lkdGggKyB4XSk7CiAgICAgICAgZnByaW50ZihmcHBnbSwgIiUzZCAiLCBibXAtPmRhdGFHW3kgKiBXaWR0aCArIHhdKTsKICAgICAgICBmcHJpbnRmKGZwcGdtLCAiJTNkICIsIGJtcC0+ZGF0YUJbeSAqIFdpZHRoICsgeF0pOwogICAgICB9CiAgICAgIGZwcmludGYoZnBwZ20sICJcbiIpOwogICAgfQogIH0gZWxzZSB7CiAgICBmb3IgKHkgPSBIZWlnaHQgLSAxOyB5ID49IDA7IHktLSkgewogICAgICBmb3IgKHggPSAwOyB4IDwgV2lkdGg7IHgrKykgewogICAgICAgIGZwcmludGYoZnBwZ20sICIlM2QgIiwgYm1wLT5kYXRhUlt5ICogV2lkdGggKyB4XSk7CiAgICAgICAgZnByaW50ZihmcHBnbSwgIiUzZCAiLCBibXAtPmRhdGFHW3kgKiBXaWR0aCArIHhdKTsKICAgICAgICBmcHJpbnRmKGZwcGdtLCAiJTNkICIsIGJtcC0+ZGF0YUJbeSAqIFdpZHRoICsgeF0pOwogICAgICB9CiAgICAgIGZwcmludGYoZnBwZ20sICJcbiIpOwogICAgfQogIH0KICBCTVAyNF9yZWxlYXNlKGJtcCk7CiAgeGZyZWUoYm1wLCBJREJNUCk7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyICoqYXJndikgewogIEZJTEUgKmZwYm1wLCAqZnBwZ207CiAgaWYgKGFyZ2MgIT0gMykgewogICAgZnByaW50ZihzdGRlcnIsICJ1c2FnZTogJXMgPGZpbGVuYW1lOmJtcD4gPGZpbGVuYW1lOnBnbT5cbiIsIGFyZ3ZbMF0pOwogICAgZXhpdCgtMSk7CiAgfQogIGlmICgoZnBibXAgPSBmb3Blbihhcmd2WzFdLCAiciIpKSA9PSAwKSB7CiAgICBmcHJpbnRmKHN0ZGVyciwgImNhbm5vdCBvcGVuIHRoZSAuYm1wIGZpbGUgZm9yIHJlYWRpbmdcbiIpOwogICAgZXhpdCgtMSk7CiAgfQogIGlmICgoZnBwZ20gPSBmb3Blbihhcmd2WzJdLCAidyIpKSA9PSAwKSB7CiAgICBmcHJpbnRmKHN0ZGVyciwgImNhbm5vdCBvcGVuIHRoZSAuYmdtIGZpbGUgZm9yIHdyaXRpbmdcbiIpOwogICAgZmNsb3NlKGZwYm1wKTsKICAgIGV4aXQoLTEpOwogIH0KICB0YXNrX2JtcDJwZ20oZnBibXAsIGZwcGdtKTsKICBmY2xvc2UoZnBibXApOwogIGZjbG9zZShmcHBnbSk7CiAgeG1hbGxvY2R1bXAoKTsKICByZXR1cm4gMDsKfQovKiBlbmQgKi8K