LyoKICogQ29weXJpZ2h0IDIwMDMgTWljaGFlbCBH/G5uZXdpZwogKgogKiBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yCiAqIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMKICogTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyCiAqIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLgogKgogKiBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwKICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUKICogTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KICoKICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYwogKiBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlCiAqIEZvdW5kYXRpb24sIEluYy4sIDU5IFRlbXBsZSBQbGFjZSwgU3VpdGUgMzMwLCBCb3N0b24sIE1BICAwMjExMS0xMzA3ICBVU0EKICovCgojZGVmaW5lIENPTV9OT19XSU5ET1dTX0gKI2luY2x1ZGUgPGFzc2VydC5oPgojaW5jbHVkZSA8c3RkYXJnLmg+CgojaW5jbHVkZSAid2luZGVmLmgiCiNpbmNsdWRlICJ3aW5iYXNlLmgiCiNpbmNsdWRlICJ3aW5nZGkuaCIKI2luY2x1ZGUgIndpbnVzZXIuaCIKI2luY2x1ZGUgIndpbm5scy5oIgojaW5jbHVkZSAid2luZXJyb3IuaCIKI2luY2x1ZGUgIm1tc3lzdGVtLmgiCiNpbmNsdWRlICJ2ZncuaCIKCiNpbmNsdWRlICJhdmlmaWxlX3ByaXZhdGUuaCIKI2luY2x1ZGUgImV4dHJhY2h1bmsuaCIKCiNpbmNsdWRlICJ3aW5lL2RlYnVnLmgiCgpXSU5FX0RFRkFVTFRfREVCVUdfQ0hBTk5FTChhdmlmaWxlKTsKCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCnN0YXRpYyBIUkVTVUxUIFdJTkFQSSBJVG1wRmlsZV9mblF1ZXJ5SW50ZXJmYWNlKElBVklGaWxlKiBpZmFjZSxSRUZJSUQgcmVmaWlkLExQVk9JRCAqb2JqKTsKc3RhdGljIFVMT05HICAgV0lOQVBJIElUbXBGaWxlX2ZuQWRkUmVmKElBVklGaWxlKiBpZmFjZSk7CnN0YXRpYyBVTE9ORyAgIFdJTkFQSSBJVG1wRmlsZV9mblJlbGVhc2UoSUFWSUZpbGUqIGlmYWNlKTsKc3RhdGljIEhSRVNVTFQgV0lOQVBJIElUbXBGaWxlX2ZuSW5mbyhJQVZJRmlsZSppZmFjZSxBVklGSUxFSU5GT1cqYWZpLExPTkcgc2l6ZSk7CnN0YXRpYyBIUkVTVUxUIFdJTkFQSSBJVG1wRmlsZV9mbkdldFN0cmVhbShJQVZJRmlsZSppZmFjZSxQQVZJU1RSRUFNKmF2aXMsRFdPUkQgZmNjVHlwZSxMT05HIGxQYXJhbSk7CnN0YXRpYyBIUkVTVUxUIFdJTkFQSSBJVG1wRmlsZV9mbkNyZWF0ZVN0cmVhbShJQVZJRmlsZSppZmFjZSxQQVZJU1RSRUFNKmF2aXMsQVZJU1RSRUFNSU5GT1cqYXNpKTsKc3RhdGljIEhSRVNVTFQgV0lOQVBJIElUbXBGaWxlX2ZuV3JpdGVEYXRhKElBVklGaWxlKmlmYWNlLERXT1JEIGNraWQsTFBWT0lEIGxwRGF0YSxMT05HIHNpemUpOwpzdGF0aWMgSFJFU1VMVCBXSU5BUEkgSVRtcEZpbGVfZm5SZWFkRGF0YShJQVZJRmlsZSppZmFjZSxEV09SRCBja2lkLExQVk9JRCBscERhdGEsTE9ORyAqc2l6ZSk7CnN0YXRpYyBIUkVTVUxUIFdJTkFQSSBJVG1wRmlsZV9mbkVuZFJlY29yZChJQVZJRmlsZSppZmFjZSk7CnN0YXRpYyBIUkVTVUxUIFdJTkFQSSBJVG1wRmlsZV9mbkRlbGV0ZVN0cmVhbShJQVZJRmlsZSppZmFjZSxEV09SRCBmY2NUeXBlLExPTkcgbFBhcmFtKTsKCnN0YXRpYyBjb25zdCBzdHJ1Y3QgSUFWSUZpbGVWdGJsIGl0bXBmdCA9IHsKICBJVG1wRmlsZV9mblF1ZXJ5SW50ZXJmYWNlLAogIElUbXBGaWxlX2ZuQWRkUmVmLAogIElUbXBGaWxlX2ZuUmVsZWFzZSwKICBJVG1wRmlsZV9mbkluZm8sCiAgSVRtcEZpbGVfZm5HZXRTdHJlYW0sCiAgSVRtcEZpbGVfZm5DcmVhdGVTdHJlYW0sCiAgSVRtcEZpbGVfZm5Xcml0ZURhdGEsCiAgSVRtcEZpbGVfZm5SZWFkRGF0YSwKICBJVG1wRmlsZV9mbkVuZFJlY29yZCwKICBJVG1wRmlsZV9mbkRlbGV0ZVN0cmVhbQp9OwoKdHlwZWRlZiBzdHJ1Y3QgX0lUbXBGaWxlSW1wbCB7CiAgLyogSVVua25vd24gc3R1ZmYgKi8KICBjb25zdCBJQVZJRmlsZVZ0YmwgKmxwVnRibDsKICBMT05HICAgICAgICAgcmVmOwoKICAvKiBJQVZJRmlsZSBzdHVmZiAqLwogIEFWSUZJTEVJTkZPVyAgZkluZm87CiAgUEFWSVNUUkVBTSAgICpwcFN0cmVhbXM7Cn0gSVRtcEZpbGVJbXBsOwoKUEFWSUZJTEUgQVZJRklMRV9DcmVhdGVBVklUZW1wRmlsZShpbnQgblN0cmVhbXMsIFBBVklTVFJFQU0gKnBwU3RyZWFtcykgewogIElUbXBGaWxlSW1wbCAqdG1wRmlsZTsKICBpbnQgICAgICAgICAgIGk7CgogIHRtcEZpbGUgPSBIZWFwQWxsb2MoR2V0UHJvY2Vzc0hlYXAoKSwgSEVBUF9aRVJPX01FTU9SWSwgc2l6ZW9mKElUbXBGaWxlSW1wbCkpOwogIGlmICh0bXBGaWxlID09IE5VTEwpCiAgICByZXR1cm4gTlVMTDsKCiAgdG1wRmlsZS0+bHBWdGJsID0gJml0bXBmdDsKICB0bXBGaWxlLT5yZWYgICAgPSAxOwogIG1lbXNldCgmdG1wRmlsZS0+ZkluZm8sIDAsIHNpemVvZih0bXBGaWxlLT5mSW5mbykpOwoKICB0bXBGaWxlLT5mSW5mby5kd1N0cmVhbXMgPSBuU3RyZWFtczsKICB0bXBGaWxlLT5wcFN0cmVhbXMgPSBIZWFwQWxsb2MoR2V0UHJvY2Vzc0hlYXAoKSwgMCwgblN0cmVhbXMgKiBzaXplb2YoUEFWSVNUUkVBTSkpOwogIGlmICh0bXBGaWxlLT5wcFN0cmVhbXMgPT0gTlVMTCkgewogICAgSGVhcEZyZWUoR2V0UHJvY2Vzc0hlYXAoKSwgMCwgdG1wRmlsZSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIGZvciAoaSA9IDA7IGkgPCBuU3RyZWFtczsgaSsrKSB7CiAgICBBVklTVFJFQU1JTkZPVyBzSW5mbzsKCiAgICB0bXBGaWxlLT5wcFN0cmVhbXNbaV0gPSBwcFN0cmVhbXNbaV07CgogICAgQVZJU3RyZWFtQWRkUmVmKHBwU3RyZWFtc1tpXSk7CiAgICBBVklTdHJlYW1JbmZvVyhwcFN0cmVhbXNbaV0sICZzSW5mbywgc2l6ZW9mKHNJbmZvKSk7CiAgICBpZiAoaSA9PSAwKSB7CiAgICAgIHRtcEZpbGUtPmZJbmZvLmR3U2NhbGUgPSBzSW5mby5kd1NjYWxlOwogICAgICB0bXBGaWxlLT5mSW5mby5kd1JhdGUgID0gc0luZm8uZHdSYXRlOwogICAgICBpZiAoIXNJbmZvLmR3U2NhbGUgfHwgIXNJbmZvLmR3UmF0ZSkgewoJdG1wRmlsZS0+ZkluZm8uZHdTY2FsZSA9IDE7Cgl0bXBGaWxlLT5mSW5mby5kd1JhdGUgID0gMTAwOwogICAgICB9CiAgICB9CgogICAgaWYgKHRtcEZpbGUtPmZJbmZvLmR3U3VnZ2VzdGVkQnVmZmVyU2l6ZSA8IHNJbmZvLmR3U3VnZ2VzdGVkQnVmZmVyU2l6ZSkKICAgICAgdG1wRmlsZS0+ZkluZm8uZHdTdWdnZXN0ZWRCdWZmZXJTaXplID0gc0luZm8uZHdTdWdnZXN0ZWRCdWZmZXJTaXplOwoKICAgIHsKICAgICAgcmVnaXN0ZXIgRFdPUkQgdG1wOwoKICAgICAgdG1wID0gTXVsRGl2KEFWSVN0cmVhbVNhbXBsZVRvVGltZShwcFN0cmVhbXNbaV0sIHNJbmZvLmR3TGVuZ3RoKSwgXAoJCSAgIHRtcEZpbGUtPmZJbmZvLmR3U2NhbGUsIHRtcEZpbGUtPmZJbmZvLmR3UmF0ZSAqIDEwMDApOwogICAgICBpZiAodG1wRmlsZS0+ZkluZm8uZHdMZW5ndGggPCB0bXApCgl0bXBGaWxlLT5mSW5mby5kd0xlbmd0aCA9IHRtcDsKCiAgICAgIHRtcCA9IHNJbmZvLnJjRnJhbWUucmlnaHQgLSBzSW5mby5yY0ZyYW1lLmxlZnQ7CiAgICAgIGlmICh0bXBGaWxlLT5mSW5mby5kd1dpZHRoIDwgdG1wKQoJdG1wRmlsZS0+ZkluZm8uZHdXaWR0aCA9IHRtcDsKICAgICAgdG1wID0gc0luZm8ucmNGcmFtZS5ib3R0b20gLSBzSW5mby5yY0ZyYW1lLnRvcDsKICAgICAgaWYgKHRtcEZpbGUtPmZJbmZvLmR3SGVpZ2h0IDwgdG1wKQoJdG1wRmlsZS0+ZkluZm8uZHdIZWlnaHQgPSB0bXA7CiAgICB9CiAgfQoKICByZXR1cm4gKFBBVklGSUxFKXRtcEZpbGU7Cn0KCnN0YXRpYyBIUkVTVUxUIFdJTkFQSSBJVG1wRmlsZV9mblF1ZXJ5SW50ZXJmYWNlKElBVklGaWxlICppZmFjZSwgUkVGSUlEIHJlZmlpZCwKCQkJCQkJTFBWT0lEICpvYmopCnsKICBJVG1wRmlsZUltcGwgKlRoaXMgPSAoSVRtcEZpbGVJbXBsICopaWZhY2U7CgogIFRSQUNFKCIoJXAsJXMsJXApXG4iLCBUaGlzLCBkZWJ1Z3N0cl9ndWlkKHJlZmlpZCksIG9iaik7CgogIGlmIChJc0VxdWFsR1VJRCgmSUlEX0lVbmtub3duLCByZWZpaWQpIHx8CiAgICAgIElzRXF1YWxHVUlEKCZJSURfSUFWSUZpbGUsIHJlZmlpZCkpIHsKICAgICpvYmogPSBpZmFjZTsKICAgIElBVklGaWxlX0FkZFJlZihpZmFjZSk7CgogICAgcmV0dXJuIFNfT0s7CiAgfQoKICByZXR1cm4gT0xFX0VfRU5VTV9OT01PUkU7Cn0KCnN0YXRpYyBVTE9ORyAgIFdJTkFQSSBJVG1wRmlsZV9mbkFkZFJlZihJQVZJRmlsZSAqaWZhY2UpCnsKICBJVG1wRmlsZUltcGwgKlRoaXMgPSAoSVRtcEZpbGVJbXBsICopaWZhY2U7CiAgVUxPTkcgcmVmID0gSW50ZXJsb2NrZWRJbmNyZW1lbnQoJlRoaXMtPnJlZik7CgogIFRSQUNFKCIoJXApIC0+ICVsZFxuIiwgaWZhY2UsIHJlZik7CgogIHJldHVybiByZWY7Cn0KCnN0YXRpYyBVTE9ORyAgIFdJTkFQSSBJVG1wRmlsZV9mblJlbGVhc2UoSUFWSUZpbGUgKmlmYWNlKQp7CiAgSVRtcEZpbGVJbXBsICpUaGlzID0gKElUbXBGaWxlSW1wbCAqKWlmYWNlOwogIFVMT05HIHJlZiA9IEludGVybG9ja2VkRGVjcmVtZW50KCZUaGlzLT5yZWYpOwoKICBUUkFDRSgiKCVwKSAtPiAlbGRcbiIsIGlmYWNlLCByZWYpOwoKICBpZiAoIXJlZikgewogICAgdW5zaWduZWQgaW50IGk7CgogICAgZm9yIChpID0gMDsgaSA8IFRoaXMtPmZJbmZvLmR3U3RyZWFtczsgaSsrKSB7CiAgICAgIGlmIChUaGlzLT5wcFN0cmVhbXNbaV0gIT0gTlVMTCkgewoJQVZJU3RyZWFtUmVsZWFzZShUaGlzLT5wcFN0cmVhbXNbaV0pOwoKCVRoaXMtPnBwU3RyZWFtc1tpXSA9IE5VTEw7CiAgICAgIH0KICAgIH0KCiAgICBIZWFwRnJlZShHZXRQcm9jZXNzSGVhcCgpLCAwLCBUaGlzKTsKICAgIHJldHVybiAwOwogIH0KCiAgcmV0dXJuIHJlZjsKfQoKc3RhdGljIEhSRVNVTFQgV0lOQVBJIElUbXBGaWxlX2ZuSW5mbyhJQVZJRmlsZSAqaWZhY2UsCgkJCQkgICAgICBBVklGSUxFSU5GT1cgKmFmaSwgTE9ORyBzaXplKQp7CiAgSVRtcEZpbGVJbXBsICpUaGlzID0gKElUbXBGaWxlSW1wbCAqKWlmYWNlOwoKICBUUkFDRSgiKCVwLCVwLCVsZClcbiIsaWZhY2UsYWZpLHNpemUpOwoKICBpZiAoYWZpID09IE5VTEwpCiAgICByZXR1cm4gQVZJRVJSX0JBRFBBUkFNOwogIGlmIChzaXplIDwgMCkKICAgIHJldHVybiBBVklFUlJfQkFEU0laRTsKCiAgbWVtY3B5KGFmaSwgJlRoaXMtPmZJbmZvLCBtaW4oKERXT1JEKXNpemUsIHNpemVvZihUaGlzLT5mSW5mbykpKTsKCiAgaWYgKChEV09SRClzaXplIDwgc2l6ZW9mKFRoaXMtPmZJbmZvKSkKICAgIHJldHVybiBBVklFUlJfQlVGRkVSVE9PU01BTEw7CiAgcmV0dXJuIEFWSUVSUl9PSzsKfQoKc3RhdGljIEhSRVNVTFQgV0lOQVBJIElUbXBGaWxlX2ZuR2V0U3RyZWFtKElBVklGaWxlICppZmFjZSwgUEFWSVNUUkVBTSAqYXZpcywKCQkJCQkgICBEV09SRCBmY2NUeXBlLCBMT05HIGxQYXJhbSkKewogIElUbXBGaWxlSW1wbCAqVGhpcyA9IChJVG1wRmlsZUltcGwgKilpZmFjZTsKCiAgVUxPTkcgblN0cmVhbSA9IChVTE9ORyktMTsKCiAgVFJBQ0UoIiglcCwlcCwweCUwOGxYLCVsZClcbiIsIGlmYWNlLCBhdmlzLCBmY2NUeXBlLCBsUGFyYW0pOwoKICBpZiAoYXZpcyA9PSBOVUxMIHx8IGxQYXJhbSA8IDApCiAgICByZXR1cm4gQVZJRVJSX0JBRFBBUkFNOwoKICBpZiAoZmNjVHlwZSAhPSBzdHJlYW10eXBlQU5ZKSB7CiAgICAvKiBzZWFyY2ggdGhlIG51bWJlciBvZiB0aGUgc3BlY2lmaWVkIHN0cmVhbSAqLwogICAgVUxPTkcgaTsKCiAgICBmb3IgKGkgPSAwOyBpIDwgVGhpcy0+ZkluZm8uZHdTdHJlYW1zOyBpKyspIHsKICAgICAgQVZJU1RSRUFNSU5GT1cgc0luZm87CiAgICAgIEhSRVNVTFQgICAgICAgIGhyOwoKICAgICAgaHIgPSBBVklTdHJlYW1JbmZvVyhUaGlzLT5wcFN0cmVhbXNbaV0sICZzSW5mbywgc2l6ZW9mKHNJbmZvKSk7CiAgICAgIGlmIChGQUlMRUQoaHIpKQoJcmV0dXJuIGhyOwoKICAgICAgaWYgKHNJbmZvLmZjY1R5cGUgPT0gZmNjVHlwZSkgewoJaWYgKGxQYXJhbSA9PSAwKSB7CgkgIG5TdHJlYW0gPSBpOwoJICBicmVhazsKCX0gZWxzZQoJICBsUGFyYW0tLTsKICAgICAgfQogICAgfQogIH0gZWxzZQogICAgblN0cmVhbSA9IGxQYXJhbTsKCiAgLyogRG9lcyB0aGUgcmVxdWVzdGVkIHN0cmVhbSBleGlzdCA/ICovCiAgaWYgKG5TdHJlYW0gPCBUaGlzLT5mSW5mby5kd1N0cmVhbXMgJiYgVGhpcy0+cHBTdHJlYW1zW25TdHJlYW1dICE9IE5VTEwpIHsKICAgICphdmlzID0gVGhpcy0+cHBTdHJlYW1zW25TdHJlYW1dOwogICAgQVZJU3RyZWFtQWRkUmVmKCphdmlzKTsKCiAgICByZXR1cm4gQVZJRVJSX09LOwogIH0KCiAgLyogU29ycnksIGJ1dCB0aGUgc3BlY2lmaWVkIHN0cmVhbSBkb2Vzbid0IGV4aXN0ICovCiAgcmV0dXJuIEFWSUVSUl9OT0RBVEE7Cn0KCnN0YXRpYyBIUkVTVUxUIFdJTkFQSSBJVG1wRmlsZV9mbkNyZWF0ZVN0cmVhbShJQVZJRmlsZSAqaWZhY2UsUEFWSVNUUkVBTSAqYXZpcywKCQkJCQkgICAgICBBVklTVFJFQU1JTkZPVyAqYXNpKQp7CiAgVFJBQ0UoIiglcCwlcCwlcClcbiIsaWZhY2UsYXZpcyxhc2kpOwoKICByZXR1cm4gQVZJRVJSX1VOU1VQUE9SVEVEOwp9CgpzdGF0aWMgSFJFU1VMVCBXSU5BUEkgSVRtcEZpbGVfZm5Xcml0ZURhdGEoSUFWSUZpbGUgKmlmYWNlLCBEV09SRCBja2lkLAoJCQkJCSAgIExQVk9JRCBscERhdGEsIExPTkcgc2l6ZSkKewogIFRSQUNFKCIoJXAsMHglMDhsWCwlcCwlbGQpXG4iLCBpZmFjZSwgY2tpZCwgbHBEYXRhLCBzaXplKTsKCiAgcmV0dXJuIEFWSUVSUl9VTlNVUFBPUlRFRDsKfQoKc3RhdGljIEhSRVNVTFQgV0lOQVBJIElUbXBGaWxlX2ZuUmVhZERhdGEoSUFWSUZpbGUgKmlmYWNlLCBEV09SRCBja2lkLAoJCQkJCSAgTFBWT0lEIGxwRGF0YSwgTE9ORyAqc2l6ZSkKewogIFRSQUNFKCIoJXAsMHglMDhsWCwlcCwlcClcbiIsIGlmYWNlLCBja2lkLCBscERhdGEsIHNpemUpOwoKICByZXR1cm4gQVZJRVJSX1VOU1VQUE9SVEVEOwp9CgpzdGF0aWMgSFJFU1VMVCBXSU5BUEkgSVRtcEZpbGVfZm5FbmRSZWNvcmQoSUFWSUZpbGUgKmlmYWNlKQp7CiAgVFJBQ0UoIiglcClcbiIsaWZhY2UpOwoKICByZXR1cm4gQVZJRVJSX09LOwp9CgpzdGF0aWMgSFJFU1VMVCBXSU5BUEkgSVRtcEZpbGVfZm5EZWxldGVTdHJlYW0oSUFWSUZpbGUgKmlmYWNlLCBEV09SRCBmY2NUeXBlLAoJCQkJCSAgICAgIExPTkcgbFBhcmFtKQp7CiAgVFJBQ0UoIiglcCwweCUwOGxYLCVsZClcbiIsIGlmYWNlLCBmY2NUeXBlLCBsUGFyYW0pOwoKICByZXR1cm4gQVZJRVJSX1VOU1VQUE9SVEVEOwp9Cg==