#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 ID_GETLINE 1004
typedef struct {
unsigned char bfType1;
unsigned char bfType2;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BitmapFileHeader;
int bmHeaderCheck(FILE *fp, BitmapFileHeader *bh) {
assert(sizeof(unsigned short) == 2); assert(sizeof(unsigned long) == 4); if (fread(&(bh
->bfType1
), sizeof(unsigned char), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bh
->bfType2
), sizeof(unsigned char), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bh
->bfSize
), sizeof(unsigned long), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bh
->bfReserved1
), sizeof(unsigned short), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bh
->bfReserved2
), sizeof(unsigned short), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bh
->bfOffBits
), sizeof(unsigned long), 1, fp
) != 1) goto error_NotRead;
if (bh->bfType1 != 'B' || bh->bfType2 != 'M')
goto error_NotBitmap;
if (bh->bfReserved1 != 0 || bh->bfReserved2 != 0)
goto error_NotBitmap;
#if 0
printf("read:bfType1: %c\n", bh
->bfType1
); printf("read:bfType2: %c\n", bh
->bfType2
); printf("read:bfSize: %lu\n", bh
->bfSize
); printf("read:bfReserved1: %u\n", bh
->bfReserved1
); printf("read:bfReserved2: %u\n", bh
->bfReserved2
); printf("read:bfOffBits: %lu\n", bh
->bfOffBits
); #endif
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 short biPlanes;
unsigned short 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 short) == 2); assert(sizeof(unsigned long) == 4); if (fread(&(bi
->biSize
), sizeof(unsigned long), 1, fp
) != 1) goto error_NotRead;
if (bi->biSize == 12) {
bi->biWidth = 0;
if (fread(&(bi
->biWidth
), sizeof(short), 1, fp
) != 1) goto error_NotRead;
bi->biHeight = 0;
if (fread(&(bi
->biHeight
), sizeof(short), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biPlanes
), sizeof(unsigned short), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biBitCount
), sizeof(unsigned short), 1, fp
) != 1) goto error_NotRead;
if (bi->biWidth > 32768)
bi->biWidth = -bi->biWidth;
if (bi->biHeight > 32768)
bi->biWidth = -bi->biHeight;
} else if (bi->biSize == 40) {
if (fread(&(bi
->biWidth
), sizeof(long), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biHeight
), sizeof(long), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biPlanes
), sizeof(unsigned short), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biBitCount
), sizeof(unsigned short), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biCompression
), sizeof(unsigned long), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biSizeImage
), sizeof(unsigned long), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biXPixPerMeter
), sizeof(long), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biYPixPerMeter
), sizeof(long), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biClrUsed
), sizeof(unsigned long), 1, fp
) != 1) goto error_NotRead;
if (fread(&(bi
->biClrImportant
), sizeof(unsigned long), 1, fp
) != 1) 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: %u\n", bi
->biPlanes
); printf("read:biBitcount: %u\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)
goto error_NotSupported3;
if (bi->biCompression != 0)
goto error_NotSupported4;
return 1;
error_NotSupported1:
fprintf(stderr
, "info header size: this format is not supported\n"); return 0;
error_NotSupported2:
fprintf(stderr
, "biPlanes: this format is not supported\n"); return 0;
error_NotSupported3:
fprintf(stderr
, "biBitCount: this format is not supported\n"); return 0;
error_NotSupported4:
fprintf(stderr
, "biCompression: this format is not supported\n"); return 0;
error_NotRead:
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)
max = 256;
*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_write_header(FILE *fp, BitmapFileHeader *bh) {
assert(sizeof(unsigned short) == 2); assert(sizeof(unsigned long) == 4); fwrite(&(bh
->bfType1
), sizeof(unsigned char), 1, fp
); fwrite(&(bh
->bfType2
), sizeof(unsigned char), 1, fp
); fwrite(&(bh
->bfSize
), sizeof(unsigned long), 1, fp
); fwrite(&(bh
->bfReserved1
), sizeof(unsigned short), 1, fp
); fwrite(&(bh
->bfReserved2
), sizeof(unsigned short), 1, fp
); fwrite(&(bh
->bfOffBits
), sizeof(unsigned long), 1, fp
); #if 0
printf("write:bfType1: %c\n", bh
->bfType1
); printf("write:bfType2: %c\n", bh
->bfType2
); printf("write:bfSize: %lu\n", bh
->bfSize
); printf("write:bfReserved1: %u\n", bh
->bfReserved1
); printf("write:bfReserved2: %u\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); fwrite(&(bi
->biSize
), sizeof(unsigned long), 1, fp
); fwrite(&(bi
->biWidth
), sizeof(long), 1, fp
); fwrite(&(bi
->biHeight
), sizeof(long), 1, fp
); fwrite(&(bi
->biPlanes
), sizeof(unsigned short), 1, fp
); fwrite(&(bi
->biBitCount
), sizeof(unsigned short), 1, fp
); fwrite(&(bi
->biCompression
), sizeof(unsigned long), 1, fp
); fwrite(&(bi
->biSizeImage
), sizeof(unsigned long), 1, fp
); fwrite(&(bi
->biXPixPerMeter
), sizeof(long), 1, fp
); fwrite(&(bi
->biYPixPerMeter
), sizeof(long), 1, fp
); fwrite(&(bi
->biClrUsed
), sizeof(unsigned long), 1, fp
); fwrite(&(bi
->biClrImportant
), sizeof(unsigned long), 1, 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: %u\n", bi
->biPlanes
); printf("write:biBitcount: %u\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;
}
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_allocation(struct BMP24 **w_bmp, long width, long height) {
int n;
*w_bmp = xmalloc(sizeof(struct BMP24), IDBMP);
if (*w_bmp == NULL) {
return;
}
n = width * 3;
if (n % 4 > 0)
n += 4 - (n % 4);
(*w_bmp)->bi.biSizeImage = n * height;
(*w_bmp)->bi.biSize = 40;
(*w_bmp)->bh.bfSize = (*w_bmp)->bi.biSizeImage + (*w_bmp)->bi.biSize + 14;
(*w_bmp)->bh.bfType1 = 'B';
(*w_bmp)->bh.bfType2 = 'M';
(*w_bmp)->bh.bfReserved1 = 0;
(*w_bmp)->bh.bfReserved2 = 0;
(*w_bmp)->bh.bfOffBits = 54;
(*w_bmp)->bi.biPlanes = 1;
(*w_bmp)->bi.biBitCount = 24;
(*w_bmp)->bi.biCompression = 0;
(*w_bmp)->bi.biHeight = height;
(*w_bmp)->bi.biWidth = width;
(*w_bmp)->bi.biClrUsed = 0;
(*w_bmp)->bi.biClrImportant = 0;
(*w_bmp)->bi.biXPixPerMeter = 30;
(*w_bmp)->bi.biYPixPerMeter = 30;
(*w_bmp)->dataR = (*w_bmp)->dataG = (*w_bmp)->dataB = NULL;
(*w_bmp)->dataPalette = NULL;
for (;;) {
if (((*w_bmp)->dataR = xmalloc(width * height, IDRGB)) == 0)
break;
if (((*w_bmp)->dataG = xmalloc(width * height, IDRGB)) == 0)
break;
if (((*w_bmp)->dataB = xmalloc(width * height, IDRGB)) == 0)
break;
/* OK finished */
return;
}
/* exception */
xfree((*w_bmp)->dataR, IDRGB);
xfree((*w_bmp)->dataG, IDRGB);
xfree((*w_bmp)->dataB, IDRGB);
xfree(*w_bmp, IDBMP);
*w_bmp = 0;
return;
}
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);
}
/* ------------------------------------------------------------------------- */
#define BUFFSIZE 3 /* >= 2 */
char *mygetline(FILE *fp) {
static char inbuff[BUFFSIZE];
char *outbuff_malloc, *tmpbuff;
char *p, *r;
int fEOL;
if ((outbuff_malloc = xmalloc(1, ID_GETLINE)) == NULL) {
return NULL;
}
*outbuff_malloc = '\0';
fEOL = 0;
do {
r
= fgets(inbuff
, BUFFSIZE
, fp
); if (r == NULL)
break;
for (p = inbuff; *p != '\0'; p++)
;
if (*(p - 1) == '\n')
fEOL = 1;
if ((tmpbuff
= xrealloc
(outbuff_malloc
, strlen(outbuff_malloc
) + strlen(inbuff
) + 1, ID_GETLINE
)) == NULL
) { xfree(outbuff_malloc, ID_GETLINE);
return NULL;
}
outbuff_malloc = tmpbuff;
} while (!fEOL);
if (strlen(outbuff_malloc
) > 0) { for (p = outbuff_malloc; *p != '\0'; p++)
;
if (*(p - 1) == '\n')
*(p - 1) = '\0';
return outbuff_malloc;
}
xfree(outbuff_malloc, ID_GETLINE);
return NULL;
}
char *cutToken(char *p, char **s) {
char *t, *q;
int flag;
if (p == 0)
return 0;
flag = 0;
for (q = p; *q == ' ' && *q != '\0'; q++)
;
if (*q == '\0')
return 0;
t = q;
q++;
for (; *q != ' ' && *q != '\0'; q++)
;
if (*q == '\0')
flag = 1;
*q = '\0';
if (flag)
*s = 0;
else
*s = q + 1;
return t;
}
void task_pgm2bmp(FILE *fppgm, FILE *fpbmp) {
struct BMP24 *bmp;
long width, height, y, x, d;
char *line, *p, *q;
int c;
/* header */
if ((line = mygetline(fppgm)) == 0) {
fprintf(stderr
, "cannot read pgm file: header\n"); return;
}
if (strcmp(line
, "P2") != 0) { fprintf(stderr
, "pgm header %s: not supported\n", line
); xfree(line, ID_GETLINE);
return;
}
xfree(line, ID_GETLINE);
/* width, height */
if ((line = mygetline(fppgm)) == 0) {
fprintf(stderr
, "cannot read pgm file: width/height\n"); return;
}
if (sscanf(line
, "%ld %ld", &width
, &height
) != 2) { fprintf(stderr
, "pgm width/height: bad format\n"); xfree(line, ID_GETLINE);
return;
}
xfree(line, ID_GETLINE);
/* depth */
if ((line = mygetline(fppgm)) == 0) {
fprintf(stderr
, "cannot read pgm file: depth\n"); return;
}
if (sscanf(line
, "%ld", &d
) != 1) { fprintf(stderr
, "pgm depth: bad format\n"); xfree(line, ID_GETLINE);
return;
}
xfree(line, ID_GETLINE);
bmp = 0;
_BMP24_allocation(&bmp, width, height);
if (bmp == 0) {
fprintf(stderr
, "cannot allocate enough memory(_BMP24_allocation)\n"); return;
}
for (y = height - 1; y >= 0; --y) {
if ((line = mygetline(fppgm)) == 0) {
fprintf(stderr
, "pgm body: bad format(too small : height).\n"); xfree(line, ID_GETLINE);
return;
}
p = line;
for (x = 0; x < width; x++) {
if ((q = cutToken(p, &p)) == 0) {
fprintf(stderr
, "pgm body: bad format(too small : height).\n"); xfree(line, ID_GETLINE);
BMP24_release(bmp);
xfree(bmp, IDBMP);
return;
}
bmp->dataR[y * width + x] = bmp->dataG[y * width + x] = bmp->dataB[y * width + x] = (unsigned char)(255 * c / d);
}
xfree(line, ID_GETLINE);
}
BMP24_write(fpbmp, bmp);
BMP24_release(bmp);
xfree(bmp, IDBMP);
}
int main(int argc, char **argv) {
FILE *fpbmp, *fppgm;
if (argc != 3) {
fprintf(stderr
, "usage: %s <filename:pgm> <filename:bmp>\n", argv
[0]); }
if ((fppgm
= fopen(argv
[1], "r")) == 0) { fprintf(stderr
, "cannot open the .pgm file for reading\n"); }
if ((fpbmp
= fopen(argv
[2], "w")) == 0) { fprintf(stderr
, "cannot open the .bmp file for writing\n"); }
task_pgm2bmp(fppgm, fpbmp);
xmallocdump();
return 0;
}
/* end */
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPGFzc2VydC5oPgojaW5jbHVkZSA8bWF0aC5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CgovKiAjZGVmaW5lIERFQlVHICovCiNpZiBkZWZpbmVkKERFQlVHKQojaW5jbHVkZSAieG1hbGxvYy5oIgojZWxzZQojZGVmaW5lIHhtYWxsb2MoeCwgeSkgbWFsbG9jKHgpCiNkZWZpbmUgeGZyZWUoeCwgeSkgZnJlZSh4KQojZGVmaW5lIHhyZWFsbG9jKHgsIHksIHopIHJlYWxsb2MoeCwgeSkKI2RlZmluZSB4bWFsbG9jZHVtcCgpCiNlbmRpZgovKiBmb3IgeG1hbGxvYy5jICovCiNkZWZpbmUgSURSR0IgICAgIDEwMDEKI2RlZmluZSBJRFBBTEVUVEUgMTAwMgojZGVmaW5lIElEQk1QICAgICAxMDAzCiNkZWZpbmUgSURfR0VUTElORSAxMDA0Cgp0eXBlZGVmIHN0cnVjdCB7CiAgdW5zaWduZWQgY2hhciBiZlR5cGUxOwogIHVuc2lnbmVkIGNoYXIgYmZUeXBlMjsKICB1bnNpZ25lZCBsb25nIGJmU2l6ZTsKICB1bnNpZ25lZCBzaG9ydCBiZlJlc2VydmVkMTsKICB1bnNpZ25lZCBzaG9ydCBiZlJlc2VydmVkMjsKICB1bnNpZ25lZCBsb25nIGJmT2ZmQml0czsKfSBCaXRtYXBGaWxlSGVhZGVyOwoKaW50IGJtSGVhZGVyQ2hlY2soRklMRSAqZnAsIEJpdG1hcEZpbGVIZWFkZXIgKmJoKSB7CiAgYXNzZXJ0KHNpemVvZih1bnNpZ25lZCBzaG9ydCkgPT0gMik7CiAgYXNzZXJ0KHNpemVvZih1bnNpZ25lZCBsb25nKSA9PSA0KTsKICBpZiAoZnJlYWQoJihiaC0+YmZUeXBlMSksIHNpemVvZih1bnNpZ25lZCBjaGFyKSwgMSwgZnApICE9IDEpCiAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgaWYgKGZyZWFkKCYoYmgtPmJmVHlwZTIpLCBzaXplb2YodW5zaWduZWQgY2hhciksIDEsIGZwKSAhPSAxKQogICAgZ290byBlcnJvcl9Ob3RSZWFkOwogIGlmIChmcmVhZCgmKGJoLT5iZlNpemUpLCBzaXplb2YodW5zaWduZWQgbG9uZyksIDEsIGZwKSAhPSAxKQogICAgZ290byBlcnJvcl9Ob3RSZWFkOwogIGlmIChmcmVhZCgmKGJoLT5iZlJlc2VydmVkMSksIHNpemVvZih1bnNpZ25lZCBzaG9ydCksIDEsIGZwKSAhPSAxKQogICAgZ290byBlcnJvcl9Ob3RSZWFkOwogIGlmIChmcmVhZCgmKGJoLT5iZlJlc2VydmVkMiksIHNpemVvZih1bnNpZ25lZCBzaG9ydCksIDEsIGZwKSAhPSAxKQogICAgZ290byBlcnJvcl9Ob3RSZWFkOwogIGlmIChmcmVhZCgmKGJoLT5iZk9mZkJpdHMpLCBzaXplb2YodW5zaWduZWQgbG9uZyksIDEsIGZwKSAhPSAxKQogICAgZ290byBlcnJvcl9Ob3RSZWFkOwogIGlmIChiaC0+YmZUeXBlMSAhPSAnQicgfHwgYmgtPmJmVHlwZTIgIT0gJ00nKQogICAgZ290byBlcnJvcl9Ob3RCaXRtYXA7CiAgaWYgKGJoLT5iZlJlc2VydmVkMSAhPSAwIHx8IGJoLT5iZlJlc2VydmVkMiAhPSAwKQogICAgZ290byBlcnJvcl9Ob3RCaXRtYXA7CiNpZiAwCiAgcHJpbnRmKCJyZWFkOmJmVHlwZTE6ICVjXG4iLCBiaC0+YmZUeXBlMSk7CiAgcHJpbnRmKCJyZWFkOmJmVHlwZTI6ICVjXG4iLCBiaC0+YmZUeXBlMik7CiAgcHJpbnRmKCJyZWFkOmJmU2l6ZTogJWx1XG4iLCBiaC0+YmZTaXplKTsKICBwcmludGYoInJlYWQ6YmZSZXNlcnZlZDE6ICV1XG4iLCBiaC0+YmZSZXNlcnZlZDEpOwogIHByaW50ZigicmVhZDpiZlJlc2VydmVkMjogJXVcbiIsIGJoLT5iZlJlc2VydmVkMik7CiAgcHJpbnRmKCJyZWFkOmJmT2ZmQml0czogJWx1XG4iLCBiaC0+YmZPZmZCaXRzKTsKICBwdXRjaGFyKCdcbicpOwojZW5kaWYKICByZXR1cm4gMTsKCmVycm9yX05vdEJpdG1hcDoKICBmcHJpbnRmKHN0ZGVyciwgImNhbm5vdCBmaW5kIGJtcCBoZWFkZXJcbiIpOwogIHJldHVybiAwOwplcnJvcl9Ob3RSZWFkOgogIGZwcmludGYoc3RkZXJyLCAiY2Fubm90IHJlYWQgYm1wIGhlYWRlclxuIik7CiAgcmV0dXJuIDA7Cn0KCnR5cGVkZWYgc3RydWN0IHsKICB1bnNpZ25lZCBsb25nIGJpU2l6ZTsKICBsb25nIGJpV2lkdGg7CiAgbG9uZyBiaUhlaWdodDsKICB1bnNpZ25lZCBzaG9ydCBiaVBsYW5lczsKICB1bnNpZ25lZCBzaG9ydCBiaUJpdENvdW50OwogIHVuc2lnbmVkIGxvbmcgYmlDb21wcmVzc2lvbjsKICB1bnNpZ25lZCBsb25nIGJpU2l6ZUltYWdlOwogIGxvbmcgYmlYUGl4UGVyTWV0ZXI7CiAgbG9uZyBiaVlQaXhQZXJNZXRlcjsKICB1bnNpZ25lZCBsb25nIGJpQ2xyVXNlZDsKICB1bnNpZ25lZCBsb25nIGJpQ2xySW1wb3J0YW50Owp9IEJpdG1hcEluZm9IZWFkZXI7CgppbnQgYm1JbmZvSGVhZGVyQ2hlY2soRklMRSAqZnAsIEJpdG1hcEluZm9IZWFkZXIgKmJpKSB7CiAgYXNzZXJ0KHNpemVvZih1bnNpZ25lZCBzaG9ydCkgPT0gMik7CiAgYXNzZXJ0KHNpemVvZih1bnNpZ25lZCBsb25nKSA9PSA0KTsKICBhc3NlcnQoc2l6ZW9mKGxvbmcpID09IDQpOwogIGlmIChmcmVhZCgmKGJpLT5iaVNpemUpLCBzaXplb2YodW5zaWduZWQgbG9uZyksIDEsIGZwKSAhPSAxKQogICAgZ290byBlcnJvcl9Ob3RSZWFkOwogIGlmIChiaS0+YmlTaXplID09IDEyKSB7CiAgICBiaS0+YmlXaWR0aCA9IDA7CiAgICBpZiAoZnJlYWQoJihiaS0+YmlXaWR0aCksIHNpemVvZihzaG9ydCksIDEsIGZwKSAhPSAxKQogICAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgICBiaS0+YmlIZWlnaHQgPSAwOwogICAgaWYgKGZyZWFkKCYoYmktPmJpSGVpZ2h0KSwgc2l6ZW9mKHNob3J0KSwgMSwgZnApICE9IDEpCiAgICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKICAgIGlmIChmcmVhZCgmKGJpLT5iaVBsYW5lcyksIHNpemVvZih1bnNpZ25lZCBzaG9ydCksIDEsIGZwKSAhPSAxKQogICAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgICBpZiAoZnJlYWQoJihiaS0+YmlCaXRDb3VudCksIHNpemVvZih1bnNpZ25lZCBzaG9ydCksIDEsIGZwKSAhPSAxKQogICAgICBnb3RvIGVycm9yX05vdFJlYWQ7CiAgICBpZiAoYmktPmJpV2lkdGggPiAzMjc2OCkKICAgICAgYmktPmJpV2lkdGggPSAtYmktPmJpV2lkdGg7CiAgICBpZiAoYmktPmJpSGVpZ2h0ID4gMzI3NjgpCiAgICAgIGJpLT5iaVdpZHRoID0gLWJpLT5iaUhlaWdodDsKICB9IGVsc2UgaWYgKGJpLT5iaVNpemUgPT0gNDApIHsKICAgIGlmIChmcmVhZCgmKGJpLT5iaVdpZHRoKSwgc2l6ZW9mKGxvbmcpLCAxLCBmcCkgIT0gMSkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKGZyZWFkKCYoYmktPmJpSGVpZ2h0KSwgc2l6ZW9mKGxvbmcpLCAxLCBmcCkgIT0gMSkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKGZyZWFkKCYoYmktPmJpUGxhbmVzKSwgc2l6ZW9mKHVuc2lnbmVkIHNob3J0KSwgMSwgZnApICE9IDEpCiAgICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKICAgIGlmIChmcmVhZCgmKGJpLT5iaUJpdENvdW50KSwgc2l6ZW9mKHVuc2lnbmVkIHNob3J0KSwgMSwgZnApICE9IDEpCiAgICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKICAgIGlmIChmcmVhZCgmKGJpLT5iaUNvbXByZXNzaW9uKSwgc2l6ZW9mKHVuc2lnbmVkIGxvbmcpLCAxLCBmcCkgIT0gMSkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKGZyZWFkKCYoYmktPmJpU2l6ZUltYWdlKSwgc2l6ZW9mKHVuc2lnbmVkIGxvbmcpLCAxLCBmcCkgIT0gMSkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKGZyZWFkKCYoYmktPmJpWFBpeFBlck1ldGVyKSwgc2l6ZW9mKGxvbmcpLCAxLCBmcCkgIT0gMSkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKGZyZWFkKCYoYmktPmJpWVBpeFBlck1ldGVyKSwgc2l6ZW9mKGxvbmcpLCAxLCBmcCkgIT0gMSkKICAgICAgZ290byBlcnJvcl9Ob3RSZWFkOwogICAgaWYgKGZyZWFkKCYoYmktPmJpQ2xyVXNlZCksIHNpemVvZih1bnNpZ25lZCBsb25nKSwgMSwgZnApICE9IDEpCiAgICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKICAgIGlmIChmcmVhZCgmKGJpLT5iaUNsckltcG9ydGFudCksIHNpemVvZih1bnNpZ25lZCBsb25nKSwgMSwgZnApICE9IDEpCiAgICAgIGdvdG8gZXJyb3JfTm90UmVhZDsKICB9IGVsc2UKICAgIGdvdG8gZXJyb3JfTm90U3VwcG9ydGVkMTsKI2lmIDAKICBwcmludGYoInJlYWQ6YmlTaXplOiAlbHVcbiIsIGJpLT5iaVNpemUpOwogIHByaW50ZigicmVhZDpiaVdpZHRoOiAlbGRcbiIsIGJpLT5iaVdpZHRoKTsKICBwcmludGYoInJlYWQ6YmlIZWlnaHQ6ICVsZFxuIiwgYmktPmJpSGVpZ2h0KTsKICBwcmludGYoInJlYWQ6YmlQbGFuZXM6ICV1XG4iLCBiaS0+YmlQbGFuZXMpOwogIHByaW50ZigicmVhZDpiaUJpdGNvdW50OiAldVxuIiwgYmktPmJpQml0Q291bnQpOwogIGlmIChiaS0+YmlTaXplID09IDQwKSB7CiAgICBwcmludGYoInJlYWQ6YmlDb21wcmVzc2lvbjogJWx1XG4iLCBiaS0+YmlDb21wcmVzc2lvbik7CiAgICBwcmludGYoInJlYWQ6YmlTaXplSW1hZ2U6ICVsdVxuIiwgYmktPmJpU2l6ZUltYWdlKTsKICAgIHByaW50ZigicmVhZDpiaVhQaXhQZXJNZXRlciAlbGRcbiIsIGJpLT5iaVhQaXhQZXJNZXRlcik7CiAgICBwcmludGYoInJlYWQ6YmlZUGl4UGVyTWV0ZXIgJWxkXG4iLCBiaS0+YmlZUGl4UGVyTWV0ZXIpOwogICAgcHJpbnRmKCJyZWFkOmJpQ2xyVXNlZDogJWx1XG4iLCBiaS0+YmlDbHJVc2VkKTsKICAgIHByaW50ZigicmVhZDpiaUNsckltcG9yYW50OiAlbHVcbiIsIGJpLT5iaUNsckltcG9ydGFudCk7CiAgfQojZW5kaWYKICBpZiAoYmktPmJpU2l6ZSAhPSA0MCkKICAgIGdvdG8gZXJyb3JfTm90U3VwcG9ydGVkMTsKICBpZiAoYmktPmJpUGxhbmVzICE9IDEpCiAgICBnb3RvIGVycm9yX05vdFN1cHBvcnRlZDI7CiAgaWYgKGJpLT5iaUJpdENvdW50ICE9IDI0ICYmIGJpLT5iaUJpdENvdW50ICE9IDgpCiAgICBnb3RvIGVycm9yX05vdFN1cHBvcnRlZDM7CiAgaWYgKGJpLT5iaUNvbXByZXNzaW9uICE9IDApCiAgICBnb3RvIGVycm9yX05vdFN1cHBvcnRlZDQ7CiAgcmV0dXJuIDE7CgplcnJvcl9Ob3RTdXBwb3J0ZWQxOgogIGZwcmludGYoc3RkZXJyLCAiaW5mbyBoZWFkZXIgc2l6ZTogdGhpcyBmb3JtYXQgaXMgbm90IHN1cHBvcnRlZFxuIik7CiAgcmV0dXJuIDA7CmVycm9yX05vdFN1cHBvcnRlZDI6CiAgZnByaW50ZihzdGRlcnIsICJiaVBsYW5lczogdGhpcyBmb3JtYXQgaXMgbm90IHN1cHBvcnRlZFxuIik7CiAgcmV0dXJuIDA7CmVycm9yX05vdFN1cHBvcnRlZDM6CiAgZnByaW50ZihzdGRlcnIsICJiaUJpdENvdW50OiB0aGlzIGZvcm1hdCBpcyBub3Qgc3VwcG9ydGVkXG4iKTsKICByZXR1cm4gMDsKZXJyb3JfTm90U3VwcG9ydGVkNDoKICBmcHJpbnRmKHN0ZGVyciwgImJpQ29tcHJlc3Npb246IHRoaXMgZm9ybWF0IGlzIG5vdCBzdXBwb3J0ZWRcbiIpOwogIHJldHVybiAwOwplcnJvcl9Ob3RSZWFkOgogIGZwcmludGYoc3RkZXJyLCAiY2Fubm90IHJlYWQgYm1wIGluZm8gaGVhZGVyXG4iKTsKICByZXR1cm4gMDsKfQoKaW50IGlzRnRlbGxHb29kKEZJTEUgKmZwLCB1bnNpZ25lZCBsb25nIHBvcykgewogIHJldHVybiAodW5zaWduZWQgbG9uZylmdGVsbChmcCkgPT0gcG9zOwp9Cgpsb25nIGlhYnMobG9uZyBuKSB7CiAgcmV0dXJuIChuID4gMCkgPyBuIDogLW47Cn0KCgp2b2lkIHRhc2tfcmVhZDI0KEZJTEUgKmZwLCBCaXRtYXBGaWxlSGVhZGVyICpiaGVhZGVyLCBCaXRtYXBJbmZvSGVhZGVyICpiaW5mbywKICAgICAgICAgICAgICAgdW5zaWduZWQgY2hhciAqKmRhdGFSLCB1bnNpZ25lZCBjaGFyICoqZGF0YUcsCiAgICAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgKipkYXRhQikKewogIGxvbmcgeCwgeSwgbjsKICB1bnNpZ25lZCBjaGFyIGR1bW15OwogIGludCBjOwogIGlmICghaXNGdGVsbEdvb2QoZnAsIGJoZWFkZXItPmJmT2ZmQml0cykpIHsKICAgIGZwcmludGYoc3RkZXJyLCAiSGVhZGVyIG9yIEltYWdlIERhdGEgaXMgY29ycnVwdGVkLlxuIik7CiAgICByZXR1cm47CiAgfQogICpkYXRhUiA9IHhtYWxsb2Moc2l6ZW9mKGNoYXIpICogaWFicyhiaW5mby0+YmlXaWR0aCkgKiBpYWJzKGJpbmZvLT5iaUhlaWdodCksIElEUkdCKTsKICAqZGF0YUcgPSB4bWFsbG9jKHNpemVvZihjaGFyKSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICogaWFicyhiaW5mby0+YmlIZWlnaHQpLCBJRFJHQik7CiAgKmRhdGFCID0geG1hbGxvYyhzaXplb2YoY2hhcikgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSAqIGlhYnMoYmluZm8tPmJpSGVpZ2h0KSwgSURSR0IpOyAgCiAgaWYgKCpkYXRhUiA9PSBOVUxMIHx8ICpkYXRhRyA9PSBOVUxMIHx8ICpkYXRhQiA9PSBOVUxMKSB7CiAgICBmcHJpbnRmKHN0ZGVyciwgImNhbm5vdCBhbGxvYy4gZW5vdWdoIG1lbW9yeS5cbiIpOwogICAgcmV0dXJuOwogIH0KICBmb3IgKHkgPSAwOyB5IDwgaWFicyhiaW5mby0+YmlIZWlnaHQpOyB5KyspIHsKICAgIGMgPSAwOwogICAgZm9yICh4ID0gMDsgeCA8IGlhYnMoYmluZm8tPmJpV2lkdGgpOyB4KyspIHsKICAgICAgZnJlYWQoKCpkYXRhQiArIHkgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSArIHgpLCAxLCAxLCBmcCk7CiAgICAgIGZyZWFkKCgqZGF0YUcgKyB5ICogaWFicyhiaW5mby0+YmlXaWR0aCkgKyB4KSwgMSwgMSwgZnApOwogICAgICBmcmVhZCgoKmRhdGFSICsgeSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICsgeCksIDEsIDEsIGZwKTsKICAgICAgYyArPSAzOwogICAgfQogICAgd2hpbGUgKGMgJSA0ICE9IDApIHsKICAgICAgZnJlYWQoJmR1bW15LCAxLCAxLCBmcCk7CiAgICAgIGMrKzsKICAgIH0KICB9CiAgbiA9IGlhYnMoYmluZm8tPmJpV2lkdGgpICogMzsKICBpZiAobiAlIDQgPiAwKQogICAgbiArPSA0IC0gKG4gJSA0KTsKICBiaW5mby0+YmlTaXplSW1hZ2UgPSBuICogaWFicyhiaW5mby0+YmlIZWlnaHQpOwogIGJoZWFkZXItPmJmU2l6ZSA9IGJpbmZvLT5iaVNpemVJbWFnZSArIGJpbmZvLT5iaVNpemUgKyAxNDsKfQoKdm9pZCB0YXNrX3JlYWRfcGFsZXR0ZShGSUxFICpmcCwgQml0bWFwRmlsZUhlYWRlciAqYmgsIEJpdG1hcEluZm9IZWFkZXIgKmJpLAogICAgICAgICAgICAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgKipkYXRhUGFsZXR0ZSkKewogIGludCBpLCBtYXg7CiAgdW5zaWduZWQgY2hhciBkdW1teTsKICBpZiAoKG1heCA9IGJpLT5iaUNsclVzZWQpID09IDApCiAgICBtYXggPSAyNTY7CiAgKmRhdGFQYWxldHRlID0geG1hbGxvYyhzaXplb2YoY2hhcikgKiAzICogbWF4LCBJRFBBTEVUVEUpOwogIGlmICgqZGF0YVBhbGV0dGUgPT0gTlVMTCkgewogICAgZnByaW50ZihzdGRlcnIsICJjYW5ub3QgYWxsb2MuIGVub3VnaCBtZW1vcnkuXG4iKTsKICAgIHJldHVybjsKICB9CiAgZm9yIChpID0gMDsgaSA8IG1heDsgaSsrKSB7CiAgICBmcmVhZCgoKmRhdGFQYWxldHRlICsgMyAqIGkgKyAwKSwgMSwgMSwgZnApOwogICAgZnJlYWQoKCpkYXRhUGFsZXR0ZSArIDMgKiBpICsgMSksIDEsIDEsIGZwKTsKICAgIGZyZWFkKCgqZGF0YVBhbGV0dGUgKyAzICogaSArIDIpLCAxLCAxLCBmcCk7CiAgICBmcmVhZCgmZHVtbXksIDEsIDEsIGZwKTsgICAgCiAgfQp9Cgp2b2lkIHRhc2tfcmVhZDgoRklMRSAqZnAsIEJpdG1hcEZpbGVIZWFkZXIgKmJoZWFkZXIsIEJpdG1hcEluZm9IZWFkZXIgKmJpbmZvLAogICAgICAgICAgICAgICB1bnNpZ25lZCBjaGFyICoqZGF0YVIsIHVuc2lnbmVkIGNoYXIgKipkYXRhRywKICAgICAgICAgICAgICAgdW5zaWduZWQgY2hhciAqKmRhdGFCLCB1bnNpZ25lZCBjaGFyICpkYXRhUGFsZXR0ZSkKewogIGxvbmcgeCwgeSwgbjsKICB1bnNpZ25lZCBjaGFyIGRhdGE7CiAgaW50IGM7CgogIGlmICghaXNGdGVsbEdvb2QoZnAsIGJoZWFkZXItPmJmT2ZmQml0cykpIHsKICAgIGZwcmludGYoc3RkZXJyLCAiSGVhZGVyIG9yIEltYWdlIERhdGEgaXMgY29ycnVwdGVkLlxuIik7CiAgICByZXR1cm47CiAgfQogICpkYXRhUiA9IHhtYWxsb2Moc2l6ZW9mKGNoYXIpICogaWFicyhiaW5mby0+YmlXaWR0aCkgKiBpYWJzKGJpbmZvLT5iaUhlaWdodCksIElEUkdCKTsKICAqZGF0YUcgPSB4bWFsbG9jKHNpemVvZihjaGFyKSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICogaWFicyhiaW5mby0+YmlIZWlnaHQpLCBJRFJHQik7CiAgKmRhdGFCID0geG1hbGxvYyhzaXplb2YoY2hhcikgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSAqIGlhYnMoYmluZm8tPmJpSGVpZ2h0KSwgSURSR0IpOyAgCiAgaWYgKCpkYXRhUiA9PSBOVUxMIHx8ICpkYXRhRyA9PSBOVUxMIHx8ICpkYXRhQiA9PSBOVUxMKSB7CiAgICBmcHJpbnRmKHN0ZGVyciwgImNhbm5vdCBhbGxvYy4gZW5vdWdoIG1lbW9yeS5cbiIpOwogICAgcmV0dXJuOwogIH0KICBmb3IgKHkgPSAwOyB5IDwgaWFicyhiaW5mby0+YmlIZWlnaHQpOyB5KyspIHsKICAgIGMgPSAwOwogICAgZm9yICh4ID0gMDsgeCA8IGlhYnMoYmluZm8tPmJpV2lkdGgpOyB4KyspIHsKICAgICAgZnJlYWQoJmRhdGEsIDEsIDEsIGZwKTsKICAgICAgKigqZGF0YUIgKyB5ICogaWFicyhiaW5mby0+YmlXaWR0aCkgKyB4KSA9IGRhdGFQYWxldHRlWzMgKiBkYXRhICsgMF07CiAgICAgICooKmRhdGFHICsgeSAqIGlhYnMoYmluZm8tPmJpV2lkdGgpICsgeCkgPSBkYXRhUGFsZXR0ZVszICogZGF0YSArIDFdOwogICAgICAqKCpkYXRhUiArIHkgKiBpYWJzKGJpbmZvLT5iaVdpZHRoKSArIHgpID0gZGF0YVBhbGV0dGVbMyAqIGRhdGEgKyAyXTsKICAgICAgYysrOwogICAgfQogICAgd2hpbGUgKGMgJSA0ICE9IDApIHsKICAgICAgZnJlYWQoJmRhdGEsIDEsIDEsIGZwKTsKICAgICAgYysrOwogICAgfQogIH0KICBuID0gaWFicyhiaW5mby0+YmlXaWR0aCkgKiAzOwogIGlmIChuICUgNCA+IDApCiAgICBuICs9IDQgLSAobiAlIDQpOwogIGJpbmZvLT5iaVNpemVJbWFnZSA9IG4gKiBpYWJzKGJpbmZvLT5iaUhlaWdodCk7CiAgYmhlYWRlci0+YmZTaXplID0gYmluZm8tPmJpU2l6ZUltYWdlICsgYmluZm8tPmJpU2l6ZSArIDE0OwogIGJoZWFkZXItPmJmT2ZmQml0cyA9IDU0OwogIGJpbmZvLT5iaUJpdENvdW50ID0gMjQ7CiAgYmluZm8tPmJpQ2xyVXNlZCA9IDA7CiAgYmluZm8tPmJpQ2xySW1wb3J0YW50ID0gMDsKfQoKdm9pZCB0YXNrX3dyaXRlX2hlYWRlcihGSUxFICpmcCwgQml0bWFwRmlsZUhlYWRlciAqYmgpIHsKICBhc3NlcnQoc2l6ZW9mKHVuc2lnbmVkIHNob3J0KSA9PSAyKTsKICBhc3NlcnQoc2l6ZW9mKHVuc2lnbmVkIGxvbmcpID09IDQpOwogIGZ3cml0ZSgmKGJoLT5iZlR5cGUxKSwgc2l6ZW9mKHVuc2lnbmVkIGNoYXIpLCAxLCBmcCk7CiAgZndyaXRlKCYoYmgtPmJmVHlwZTIpLCBzaXplb2YodW5zaWduZWQgY2hhciksIDEsIGZwKTsKICBmd3JpdGUoJihiaC0+YmZTaXplKSwgc2l6ZW9mKHVuc2lnbmVkIGxvbmcpLCAxLCBmcCk7CiAgZndyaXRlKCYoYmgtPmJmUmVzZXJ2ZWQxKSwgc2l6ZW9mKHVuc2lnbmVkIHNob3J0KSwgMSwgZnApOwogIGZ3cml0ZSgmKGJoLT5iZlJlc2VydmVkMiksIHNpemVvZih1bnNpZ25lZCBzaG9ydCksIDEsIGZwKTsKICBmd3JpdGUoJihiaC0+YmZPZmZCaXRzKSwgc2l6ZW9mKHVuc2lnbmVkIGxvbmcpLCAxLCBmcCk7CiNpZiAwCiAgcHJpbnRmKCJ3cml0ZTpiZlR5cGUxOiAlY1xuIiwgYmgtPmJmVHlwZTEpOwogIHByaW50Zigid3JpdGU6YmZUeXBlMjogJWNcbiIsIGJoLT5iZlR5cGUyKTsKICBwcmludGYoIndyaXRlOmJmU2l6ZTogJWx1XG4iLCBiaC0+YmZTaXplKTsKICBwcmludGYoIndyaXRlOmJmUmVzZXJ2ZWQxOiAldVxuIiwgYmgtPmJmUmVzZXJ2ZWQxKTsKICBwcmludGYoIndyaXRlOmJmUmVzZXJ2ZWQyOiAldVxuIiwgYmgtPmJmUmVzZXJ2ZWQyKTsKICBwcmludGYoIndyaXRlOmJmT2ZmQml0czogJWx1XG4iLCBiaC0+YmZPZmZCaXRzKTsKI2VuZGlmCn0KCnZvaWQgdGFza193cml0ZV9pbmZvKEZJTEUgKmZwLCBCaXRtYXBJbmZvSGVhZGVyICpiaSkgewogIGFzc2VydChzaXplb2YodW5zaWduZWQgc2hvcnQpID09IDIpOwogIGFzc2VydChzaXplb2YodW5zaWduZWQgbG9uZykgPT0gNCk7CiAgYXNzZXJ0KHNpemVvZihsb25nKSA9PSA0KTsKICBmd3JpdGUoJihiaS0+YmlTaXplKSwgc2l6ZW9mKHVuc2lnbmVkIGxvbmcpLCAxLCBmcCk7CiAgZndyaXRlKCYoYmktPmJpV2lkdGgpLCBzaXplb2YobG9uZyksIDEsIGZwKTsKICBmd3JpdGUoJihiaS0+YmlIZWlnaHQpLCBzaXplb2YobG9uZyksIDEsIGZwKTsKICBmd3JpdGUoJihiaS0+YmlQbGFuZXMpLCBzaXplb2YodW5zaWduZWQgc2hvcnQpLCAxLCBmcCk7CiAgZndyaXRlKCYoYmktPmJpQml0Q291bnQpLCBzaXplb2YodW5zaWduZWQgc2hvcnQpLCAxLCBmcCk7CiAgZndyaXRlKCYoYmktPmJpQ29tcHJlc3Npb24pLCBzaXplb2YodW5zaWduZWQgbG9uZyksIDEsIGZwKTsKICBmd3JpdGUoJihiaS0+YmlTaXplSW1hZ2UpLCBzaXplb2YodW5zaWduZWQgbG9uZyksIDEsIGZwKTsKICBmd3JpdGUoJihiaS0+YmlYUGl4UGVyTWV0ZXIpLCBzaXplb2YobG9uZyksIDEsIGZwKTsKICBmd3JpdGUoJihiaS0+YmlZUGl4UGVyTWV0ZXIpLCBzaXplb2YobG9uZyksIDEsIGZwKTsKICBmd3JpdGUoJihiaS0+YmlDbHJVc2VkKSwgc2l6ZW9mKHVuc2lnbmVkIGxvbmcpLCAxLCBmcCk7CiAgZndyaXRlKCYoYmktPmJpQ2xySW1wb3J0YW50KSwgc2l6ZW9mKHVuc2lnbmVkIGxvbmcpLCAxLCBmcCk7CiNpZiAwCiAgcHJpbnRmKCJ3cml0ZTpiaVNpemU6ICVsdVxuIiwgYmktPmJpU2l6ZSk7CiAgcHJpbnRmKCJ3cml0ZTpiaVdpZHRoOiAlbGRcbiIsIGJpLT5iaVdpZHRoKTsKICBwcmludGYoIndyaXRlOmJpSGVpZ2h0OiAlbGRcbiIsIGJpLT5iaUhlaWdodCk7CiAgcHJpbnRmKCJ3cml0ZTpiaVBsYW5lczogJXVcbiIsIGJpLT5iaVBsYW5lcyk7CiAgcHJpbnRmKCJ3cml0ZTpiaUJpdGNvdW50OiAldVxuIiwgYmktPmJpQml0Q291bnQpOwogIHByaW50Zigid3JpdGU6YmlDb21wcmVzc2lvbjogJWx1XG4iLCBiaS0+YmlDb21wcmVzc2lvbik7CiAgcHJpbnRmKCJ3cml0ZTpiaVNpemVJbWFnZTogJWx1XG4iLCBiaS0+YmlTaXplSW1hZ2UpOwogIHByaW50Zigid3JpdGU6YmlYUGl4UGVyTWV0ZXIgJWxkXG4iLCBiaS0+YmlYUGl4UGVyTWV0ZXIpOwogIHByaW50Zigid3JpdGU6YmlZUGl4UGVyTWV0ZXIgJWxkXG4iLCBiaS0+YmlZUGl4UGVyTWV0ZXIpOwogIHByaW50Zigid3JpdGU6YmlDbHJVc2VkOiAlbHVcbiIsIGJpLT5iaUNsclVzZWQpOwogIHByaW50Zigid3JpdGU6YmlDbHJJbXBvcmFudDogJWx1XG4iLCBiaS0+YmlDbHJJbXBvcnRhbnQpOwojZW5kaWYKfQoKdm9pZCB0YXNrX3dyaXRlMjQoRklMRSAqZnAsCiAgICAgICAgICAgICAgICAgIEJpdG1hcEZpbGVIZWFkZXIgKmJoLCBCaXRtYXBJbmZvSGVhZGVyICpiaSwKICAgICAgICAgICAgICAgICAgdW5zaWduZWQgY2hhciAqZGF0YVIsCiAgICAgICAgICAgICAgICAgIHVuc2lnbmVkIGNoYXIgKmRhdGFHLAogICAgICAgICAgICAgICAgICB1bnNpZ25lZCBjaGFyICpkYXRhQikgewogIGludCB4LCB5OwogIGludCBjOwogIHVuc2lnbmVkIGNoYXIgZHVtbXkgPSAnXDAnOwogIHRhc2tfd3JpdGVfaGVhZGVyKGZwLCBiaCk7CiAgdGFza193cml0ZV9pbmZvKGZwLCBiaSk7CiAgZm9yICh5ID0gMDsgeSA8IGlhYnMoYmktPmJpSGVpZ2h0KTsgeSsrKSB7CiAgICBjID0gMDsKICAgIGZvciAoeCA9IDA7IHggPCBpYWJzKGJpLT5iaVdpZHRoKTsgeCsrKSB7CiAgICAgIGZ3cml0ZSgmZGF0YUJbeSAqIGlhYnMoYmktPmJpV2lkdGgpICsgeF0sIDEsIDEsIGZwKTsKICAgICAgZndyaXRlKCZkYXRhR1t5ICogaWFicyhiaS0+YmlXaWR0aCkgKyB4XSwgMSwgMSwgZnApOwogICAgICBmd3JpdGUoJmRhdGFSW3kgKiBpYWJzKGJpLT5iaVdpZHRoKSArIHhdLCAxLCAxLCBmcCk7CiAgICAgIGMgKz0gMzsKICAgIH0KICAgIHdoaWxlIChjICUgNCAhPSAwKSB7CiAgICAgIGZ3cml0ZSgmZHVtbXksIDEsIDEsIGZwKTsKICAgICAgYysrOwogICAgfQogIH0KfQoKLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwpzdHJ1Y3QgQk1QMjQgewogIEJpdG1hcEZpbGVIZWFkZXIgYmg7CiAgQml0bWFwSW5mb0hlYWRlciBiaTsKICB1bnNpZ25lZCBjaGFyICpkYXRhUjsKICB1bnNpZ25lZCBjaGFyICpkYXRhRzsKICB1bnNpZ25lZCBjaGFyICpkYXRhQjsKICB1bnNpZ25lZCBjaGFyICpkYXRhUGFsZXR0ZTsKfTsKCmludCBCTVAyNF9yZWFkKEZJTEUgKmZwLCBzdHJ1Y3QgQk1QMjQgKmJtcCkgewogIGlmICghYm1IZWFkZXJDaGVjayhmcCwgJihibXAtPmJoKSkpCiAgICByZXR1cm4gMDsKICBpZiAoIWJtSW5mb0hlYWRlckNoZWNrKGZwLCAmKGJtcC0+YmkpKSkKICAgIHJldHVybiAwOwogIGJtcC0+ZGF0YVIgPSBibXAtPmRhdGFHID0gYm1wLT5kYXRhQiA9IGJtcC0+ZGF0YVBhbGV0dGUgPSBOVUxMOwogIGlmICgoYm1wLT5iaSkuYmlCaXRDb3VudCA9PSAyNCkgewogICAgdGFza19yZWFkMjQoZnAsICYoYm1wLT5iaCksICYoYm1wLT5iaSksCiAgICAgICAgICAgICAgICAmKGJtcC0+ZGF0YVIpLCAmKGJtcC0+ZGF0YUcpLCAmKGJtcC0+ZGF0YUIpKTsKICB9IGVsc2UgaWYgKChibXAtPmJpKS5iaUJpdENvdW50ID09IDgpIHsKICAgIHRhc2tfcmVhZF9wYWxldHRlKGZwLCAmYm1wLT5iaCwgJmJtcC0+YmksICZibXAtPmRhdGFQYWxldHRlKTsKICAgIHRhc2tfcmVhZDgoZnAsICZibXAtPmJoLCAmYm1wLT5iaSwKICAgICAgICAgICAgICAgJmJtcC0+ZGF0YVIsICZibXAtPmRhdGFHLCAmYm1wLT5kYXRhQiwgYm1wLT5kYXRhUGFsZXR0ZSk7CiAgICB4ZnJlZShibXAtPmRhdGFQYWxldHRlLCBJRFBBTEVUVEUpOwogICAgYm1wLT5kYXRhUGFsZXR0ZSA9IE5VTEw7CiAgfQogIGlmICghKGJtcC0+ZGF0YVIgJiYgYm1wLT5kYXRhRyAmJiBibXAtPmRhdGFCKSkgewogICAgeGZyZWUoYm1wLT5kYXRhUiwgSURSR0IpOwogICAgeGZyZWUoYm1wLT5kYXRhRywgSURSR0IpOwogICAgeGZyZWUoYm1wLT5kYXRhQiwgSURSR0IpOwogICAgcmV0dXJuIDA7CiAgfQogIHJldHVybiAxOwp9Cgp2b2lkIEJNUDI0X3dyaXRlKEZJTEUgKmZwLCBzdHJ1Y3QgQk1QMjQgKmJtcCkgewogIHRhc2tfd3JpdGUyNChmcCwgJmJtcC0+YmgsICZibXAtPmJpLAogICAgICAgICAgICAgICBibXAtPmRhdGFSLCBibXAtPmRhdGFHLCBibXAtPmRhdGFCKTsKfQoKdm9pZCBfQk1QMjRfYWxsb2NhdGlvbihzdHJ1Y3QgQk1QMjQgKip3X2JtcCwgbG9uZyB3aWR0aCwgbG9uZyBoZWlnaHQpIHsKICBpbnQgbjsKICAqd19ibXAgPSB4bWFsbG9jKHNpemVvZihzdHJ1Y3QgQk1QMjQpLCBJREJNUCk7CiAgaWYgKCp3X2JtcCA9PSBOVUxMKSB7CiAgICBmcHJpbnRmKHN0ZGVyciwgImVycm9yKGJtcDI0KVxuIik7CiAgICByZXR1cm47CiAgfQogIG4gPSB3aWR0aCAqIDM7CiAgaWYgKG4gJSA0ID4gMCkKICAgIG4gKz0gNCAtIChuICUgNCk7CiAgKCp3X2JtcCktPmJpLmJpU2l6ZUltYWdlID0gbiAqIGhlaWdodDsKICAoKndfYm1wKS0+YmkuYmlTaXplID0gNDA7CiAgKCp3X2JtcCktPmJoLmJmU2l6ZSA9ICgqd19ibXApLT5iaS5iaVNpemVJbWFnZSArICgqd19ibXApLT5iaS5iaVNpemUgKyAxNDsKCiAgKCp3X2JtcCktPmJoLmJmVHlwZTEgPSAnQic7CiAgKCp3X2JtcCktPmJoLmJmVHlwZTIgPSAnTSc7CiAgKCp3X2JtcCktPmJoLmJmUmVzZXJ2ZWQxID0gMDsKICAoKndfYm1wKS0+YmguYmZSZXNlcnZlZDIgPSAwOwogICgqd19ibXApLT5iaC5iZk9mZkJpdHMgPSA1NDsKCiAgKCp3X2JtcCktPmJpLmJpUGxhbmVzID0gMTsKICAoKndfYm1wKS0+YmkuYmlCaXRDb3VudCA9IDI0OwogICgqd19ibXApLT5iaS5iaUNvbXByZXNzaW9uID0gMDsKICAoKndfYm1wKS0+YmkuYmlIZWlnaHQgPSBoZWlnaHQ7CiAgKCp3X2JtcCktPmJpLmJpV2lkdGggPSB3aWR0aDsgIAogICgqd19ibXApLT5iaS5iaUNsclVzZWQgPSAwOwogICgqd19ibXApLT5iaS5iaUNsckltcG9ydGFudCA9IDA7CiAgKCp3X2JtcCktPmJpLmJpWFBpeFBlck1ldGVyID0gMzA7CiAgKCp3X2JtcCktPmJpLmJpWVBpeFBlck1ldGVyID0gMzA7CiAgKCp3X2JtcCktPmRhdGFSID0gKCp3X2JtcCktPmRhdGFHID0gKCp3X2JtcCktPmRhdGFCID0gTlVMTDsKICAoKndfYm1wKS0+ZGF0YVBhbGV0dGUgPSBOVUxMOwogIGZvciAoOzspIHsKICAgIGlmICgoKCp3X2JtcCktPmRhdGFSID0geG1hbGxvYyh3aWR0aCAqIGhlaWdodCwgSURSR0IpKSA9PSAwKQogICAgICBicmVhazsKICAgIGlmICgoKCp3X2JtcCktPmRhdGFHID0geG1hbGxvYyh3aWR0aCAqIGhlaWdodCwgSURSR0IpKSA9PSAwKQogICAgICBicmVhazsKICAgIGlmICgoKCp3X2JtcCktPmRhdGFCID0geG1hbGxvYyh3aWR0aCAqIGhlaWdodCwgSURSR0IpKSA9PSAwKQogICAgICBicmVhazsKICAgIC8qIE9LIGZpbmlzaGVkICovCiAgICByZXR1cm47CiAgfQogIC8qIGV4Y2VwdGlvbiAqLwogIHhmcmVlKCgqd19ibXApLT5kYXRhUiwgSURSR0IpOwogIHhmcmVlKCgqd19ibXApLT5kYXRhRywgSURSR0IpOyAgCiAgeGZyZWUoKCp3X2JtcCktPmRhdGFCLCBJRFJHQik7CiAgeGZyZWUoKndfYm1wLCBJREJNUCk7CiAgKndfYm1wID0gMDsKICByZXR1cm47Cn0KCnZvaWQgQk1QMjRfcmVsZWFzZShzdHJ1Y3QgQk1QMjQgKmJtcCkgewogIGlmIChibXAtPmRhdGFSKSB4ZnJlZShibXAtPmRhdGFSLCBJRFJHQik7CiAgaWYgKGJtcC0+ZGF0YUcpIHhmcmVlKGJtcC0+ZGF0YUcsIElEUkdCKTsKICBpZiAoYm1wLT5kYXRhQikgeGZyZWUoYm1wLT5kYXRhQiwgSURSR0IpOwogIGlmIChibXAtPmRhdGFQYWxldHRlKSB4ZnJlZShibXAtPmRhdGFQYWxldHRlLCBJRFBBTEVUVEUpOwp9CgovKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCiNkZWZpbmUgQlVGRlNJWkUgMyAvKiA+PSAyICovCmNoYXIgKm15Z2V0bGluZShGSUxFICpmcCkgewogIHN0YXRpYyBjaGFyIGluYnVmZltCVUZGU0laRV07CiAgY2hhciAqb3V0YnVmZl9tYWxsb2MsICp0bXBidWZmOwogIGNoYXIgKnAsICpyOwogIGludCBmRU9MOwoKICBpZiAoKG91dGJ1ZmZfbWFsbG9jID0geG1hbGxvYygxLCBJRF9HRVRMSU5FKSkgPT0gTlVMTCkgewogICAgcmV0dXJuIE5VTEw7CiAgfQogICpvdXRidWZmX21hbGxvYyA9ICdcMCc7CiAgZkVPTCA9IDA7CiAgZG8gewogICAgciA9IGZnZXRzKGluYnVmZiwgQlVGRlNJWkUsIGZwKTsKICAgIGlmIChyID09IE5VTEwpCiAgICAgIGJyZWFrOwogICAgZm9yIChwID0gaW5idWZmOyAqcCAhPSAnXDAnOyBwKyspCiAgICAgIDsKICAgIGlmICgqKHAgLSAxKSA9PSAnXG4nKQogICAgICBmRU9MID0gMTsKICAgIGlmICgodG1wYnVmZiA9IHhyZWFsbG9jKG91dGJ1ZmZfbWFsbG9jLCBzdHJsZW4ob3V0YnVmZl9tYWxsb2MpICsgc3RybGVuKGluYnVmZikgKyAxLCBJRF9HRVRMSU5FKSkgPT0gTlVMTCkgewogICAgICB4ZnJlZShvdXRidWZmX21hbGxvYywgSURfR0VUTElORSk7CiAgICAgIHJldHVybiBOVUxMOwogICAgfQogICAgc3RyY2F0KHRtcGJ1ZmYsIGluYnVmZik7CiAgICBvdXRidWZmX21hbGxvYyA9IHRtcGJ1ZmY7CiAgfSB3aGlsZSAoIWZFT0wpOwogIGlmIChzdHJsZW4ob3V0YnVmZl9tYWxsb2MpID4gMCkgewogICAgZm9yIChwID0gb3V0YnVmZl9tYWxsb2M7ICpwICE9ICdcMCc7IHArKykKICAgICAgOwogICAgaWYgKCoocCAtIDEpID09ICdcbicpCiAgICAgICoocCAtIDEpID0gJ1wwJzsKICAgIHJldHVybiBvdXRidWZmX21hbGxvYzsKICB9CiAgeGZyZWUob3V0YnVmZl9tYWxsb2MsIElEX0dFVExJTkUpOwogIHJldHVybiBOVUxMOwp9CgpjaGFyICpjdXRUb2tlbihjaGFyICpwLCBjaGFyICoqcykgewogIGNoYXIgKnQsICpxOwogIGludCBmbGFnOwogIGlmIChwID09IDApCiAgICByZXR1cm4gMDsKICBmbGFnID0gMDsKICBmb3IgKHEgPSBwOyAqcSA9PSAnICcgJiYgKnEgIT0gJ1wwJzsgcSsrKQogICAgOwogIGlmICgqcSA9PSAnXDAnKQogICAgcmV0dXJuIDA7CiAgdCA9IHE7CiAgcSsrOwogIGZvciAoOyAqcSAhPSAnICcgJiYgKnEgIT0gJ1wwJzsgcSsrKQogICAgOwogIGlmICgqcSA9PSAnXDAnKQogICAgZmxhZyA9IDE7CiAgKnEgPSAnXDAnOwogIGlmIChmbGFnKQogICAgKnMgPSAwOwogIGVsc2UKICAgICpzID0gcSArIDE7CiAgcmV0dXJuIHQ7Cn0KCnZvaWQgdGFza19wZ20yYm1wKEZJTEUgKmZwcGdtLCBGSUxFICpmcGJtcCkgewogIHN0cnVjdCBCTVAyNCAqYm1wOwogIGxvbmcgd2lkdGgsIGhlaWdodCwgeSwgeCwgZDsKICBjaGFyICpsaW5lLCAqcCwgKnE7CiAgaW50IGM7CgogIC8qIGhlYWRlciAqLwogIGlmICgobGluZSA9IG15Z2V0bGluZShmcHBnbSkpID09IDApIHsKICAgIGZwcmludGYoc3RkZXJyLCAiY2Fubm90IHJlYWQgcGdtIGZpbGU6IGhlYWRlclxuIik7CiAgICByZXR1cm47CiAgfQogIGlmIChzdHJjbXAobGluZSwgIlAyIikgIT0gMCkgewogICAgZnByaW50ZihzdGRlcnIsICJwZ20gaGVhZGVyICVzOiBub3Qgc3VwcG9ydGVkXG4iLCBsaW5lKTsKICAgIHhmcmVlKGxpbmUsIElEX0dFVExJTkUpOwogICAgcmV0dXJuOwogIH0KICB4ZnJlZShsaW5lLCBJRF9HRVRMSU5FKTsKCiAgLyogd2lkdGgsIGhlaWdodCAqLwogIGlmICgobGluZSA9IG15Z2V0bGluZShmcHBnbSkpID09IDApIHsKICAgIGZwcmludGYoc3RkZXJyLCAiY2Fubm90IHJlYWQgcGdtIGZpbGU6IHdpZHRoL2hlaWdodFxuIik7CiAgICByZXR1cm47CiAgfQogIGlmIChzc2NhbmYobGluZSwgIiVsZCAlbGQiLCAmd2lkdGgsICZoZWlnaHQpICE9IDIpIHsKICAgIGZwcmludGYoc3RkZXJyLCAicGdtIHdpZHRoL2hlaWdodDogYmFkIGZvcm1hdFxuIik7CiAgICB4ZnJlZShsaW5lLCBJRF9HRVRMSU5FKTsKICAgIHJldHVybjsKICB9CiAgeGZyZWUobGluZSwgSURfR0VUTElORSk7CgogIC8qIGRlcHRoICovCiAgaWYgKChsaW5lID0gbXlnZXRsaW5lKGZwcGdtKSkgPT0gMCkgewogICAgZnByaW50ZihzdGRlcnIsICJjYW5ub3QgcmVhZCBwZ20gZmlsZTogZGVwdGhcbiIpOwogICAgcmV0dXJuOwogIH0KICBpZiAoc3NjYW5mKGxpbmUsICIlbGQiLCAmZCkgIT0gMSkgewogICAgZnByaW50ZihzdGRlcnIsICJwZ20gZGVwdGg6IGJhZCBmb3JtYXRcbiIpOwogICAgeGZyZWUobGluZSwgSURfR0VUTElORSk7CiAgICByZXR1cm47CiAgfQogIHhmcmVlKGxpbmUsIElEX0dFVExJTkUpOwoKICBibXAgPSAwOwogIF9CTVAyNF9hbGxvY2F0aW9uKCZibXAsIHdpZHRoLCBoZWlnaHQpOwogIGlmIChibXAgPT0gMCkgewogICAgZnByaW50ZihzdGRlcnIsICJjYW5ub3QgYWxsb2NhdGUgZW5vdWdoIG1lbW9yeShfQk1QMjRfYWxsb2NhdGlvbilcbiIpOwogICAgcmV0dXJuOwogIH0KCiAgZm9yICh5ID0gaGVpZ2h0IC0gMTsgeSA+PSAwOyAtLXkpIHsKICAgIGlmICgobGluZSA9IG15Z2V0bGluZShmcHBnbSkpID09IDApIHsKICAgICAgZnByaW50ZihzdGRlcnIsICJwZ20gYm9keTogYmFkIGZvcm1hdCh0b28gc21hbGwgOiBoZWlnaHQpLlxuIik7CiAgICAgIHhmcmVlKGxpbmUsIElEX0dFVExJTkUpOwogICAgICByZXR1cm47CiAgICB9CiAgICBwID0gbGluZTsKICAgIGZvciAoeCA9IDA7IHggPCB3aWR0aDsgeCsrKSB7CiAgICAgIGlmICgocSA9IGN1dFRva2VuKHAsICZwKSkgPT0gMCkgewogICAgICAgIGZwcmludGYoc3RkZXJyLCAicGdtIGJvZHk6IGJhZCBmb3JtYXQodG9vIHNtYWxsIDogaGVpZ2h0KS5cbiIpOwogICAgICAgIHhmcmVlKGxpbmUsIElEX0dFVExJTkUpOwogICAgICAgIEJNUDI0X3JlbGVhc2UoYm1wKTsKICAgICAgICB4ZnJlZShibXAsIElEQk1QKTsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgYyA9IGF0b2kocSk7CiAgICAgIGJtcC0+ZGF0YVJbeSAqIHdpZHRoICsgeF0gPSBibXAtPmRhdGFHW3kgKiB3aWR0aCArIHhdID0gYm1wLT5kYXRhQlt5ICogd2lkdGggKyB4XSA9ICh1bnNpZ25lZCBjaGFyKSgyNTUgKiBjIC8gZCk7CiAgICB9CiAgICB4ZnJlZShsaW5lLCBJRF9HRVRMSU5FKTsKICB9CiAgQk1QMjRfd3JpdGUoZnBibXAsIGJtcCk7CiAgQk1QMjRfcmVsZWFzZShibXApOwogIHhmcmVlKGJtcCwgSURCTVApOwp9CgppbnQgbWFpbihpbnQgYXJnYywgY2hhciAqKmFyZ3YpIHsKICBGSUxFICpmcGJtcCwgKmZwcGdtOwogIGlmIChhcmdjICE9IDMpIHsKICAgIGZwcmludGYoc3RkZXJyLCAidXNhZ2U6ICVzIDxmaWxlbmFtZTpwZ20+IDxmaWxlbmFtZTpibXA+XG4iLCBhcmd2WzBdKTsKICAgIGV4aXQoLTEpOwogIH0KICBpZiAoKGZwcGdtID0gZm9wZW4oYXJndlsxXSwgInIiKSkgPT0gMCkgewogICAgZnByaW50ZihzdGRlcnIsICJjYW5ub3Qgb3BlbiB0aGUgLnBnbSBmaWxlIGZvciByZWFkaW5nXG4iKTsKICAgIGV4aXQoLTEpOwogIH0KICBpZiAoKGZwYm1wID0gZm9wZW4oYXJndlsyXSwgInciKSkgPT0gMCkgewogICAgZnByaW50ZihzdGRlcnIsICJjYW5ub3Qgb3BlbiB0aGUgLmJtcCBmaWxlIGZvciB3cml0aW5nXG4iKTsKICAgIGZjbG9zZShmcGJtcCk7CiAgICBleGl0KC0xKTsKICB9CiAgdGFza19wZ20yYm1wKGZwcGdtLCBmcGJtcCk7CiAgZmNsb3NlKGZwYm1wKTsKICBmY2xvc2UoZnBwZ20pOwogIHhtYWxsb2NkdW1wKCk7CiAgcmV0dXJuIDA7Cn0KLyogZW5kICovCg==