LyoKICogRE9TIGludGVycnVwdCAwOWggaGFuZGxlciAoSVJRMSAtIEtFWUJPQVJEKQogKgogKiBDb3B5cmlnaHQgMTk5OSBPdmUgS+V2ZW4KICoKICogVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vcgogKiBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljCiAqIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlcgogKiB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4KICoKICogVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VCiAqIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCiAqCiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMKICogTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQogKiBGb3VuZGF0aW9uLCBJbmMuLCA1OSBUZW1wbGUgUGxhY2UsIFN1aXRlIDMzMCwgQm9zdG9uLCBNQSAgMDIxMTEtMTMwNyAgVVNBCiAqLwoKI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CgojaW5jbHVkZSAid2luZGVmLmgiCiNpbmNsdWRlICJ3aW5iYXNlLmgiCiNpbmNsdWRlICJ3aW5nZGkuaCIKI2luY2x1ZGUgIndpbnVzZXIuaCIKI2luY2x1ZGUgIm1pc2NlbXUuaCIKI2luY2x1ZGUgIndpbmUvZGVidWcuaCIKI2luY2x1ZGUgImRvc2V4ZS5oIgoKV0lORV9ERUZBVUxUX0RFQlVHX0NIQU5ORUwoaW50KTsKCiNkZWZpbmUgUVVFVUVMRU4gMzEKCnN0YXRpYyBzdHJ1Y3QKewogIEJZVEUgcXVldWVsZW4scXVldWVbUVVFVUVMRU5dLGFzY2lpW1FVRVVFTEVOXTsKfSBrYmRpbmZvOwoKCi8qCiAqIFVwZGF0ZSB0aGUgQklPUyBkYXRhIHNlZ21lbnQncyBrZXlib2FyZCBzdGF0dXMgZmxhZ3MgKG1lbSAweDQwOjB4MTcvMHgxOCkKICogaWYgbW9kaWZpZXIvc3BlY2lhbCBrZXlzIGhhdmUgYmVlbiBwcmVzc2VkLgogKiBGSVhNRTogd2UgbWVyZWx5IHRvZ2dsZSBrZXkgc3RhdHVzIGFuZCBkb24ndCBhY3RpdmVseSBzZXQgaXQgaW5zdGVhZCwKICogc28gd2UgbWlnaHQgYmUgb3V0IG9mIHN5bmMgd2l0aCB0aGUgcmVhbCBjdXJyZW50IHN5c3RlbSBzdGF0dXMgb2YgdGhlc2Uga2V5cy4KICogUHJvYmFibHkgZG9lc24ndCBtYXR0ZXIgdG9vIG11Y2gsIHRob3VnaC4KICovCnZvaWQgRE9TVk1fSW50MDlVcGRhdGVLYmRTdGF0dXNGbGFncyhCWVRFIHNjYW4sIEJPT0wgZXh0ZW5kZWQsIEJJT1NEQVRBICpkYXRhLCBCT09MICptb2RpZmllcikKewogICAgQllURSByZWFsc2NhbiA9IHNjYW4gJiAweDdmOyAvKiByZW1vdmUgMHg4MCBtYWtlL2JyZWFrIGZsYWcgKi8KICAgIEJZVEUgYml0MSA9IDI1NSwgYml0MiA9IDI1NTsKICAgIElOUFVUX1JFQ09SRCBtc2c7CiAgICBEV09SRCByZXM7CgogICAgKm1vZGlmaWVyID0gVFJVRTsKCiAgICBzd2l0Y2ggKHJlYWxzY2FuKQogICAgewogICAgICBjYXNlIDB4MzY6IC8qIHIgc2hpZnQgKi8KCSAgICAgIGJpdDEgPSAwOwoJICAgICAgYnJlYWs7CiAgICAgIGNhc2UgMHgyYTogLyogbCBzaGlmdCAqLwoJICAgICAgYml0MSA9IDE7CgkgICAgICBicmVhazsKICAgICAgY2FzZSAweDFkOiAvKiBsL3IgY29udHJvbCAqLwoJICAgICAgYml0MSA9IDI7CgkgICAgICBpZiAoIWV4dGVuZGVkKSAvKiBsZWZ0IGNvbnRyb2wgb25seSAqLwoJCSAgYml0MiA9IDA7CgkgICAgICBicmVhazsKICAgICAgY2FzZSAweDM3OiAvKiBTeXNScSBpbm5lciBwYXJ0cyAqLwoJICAgICAgLyogU3lzUnEgc2NhbiBjb2RlIHNlcXVlbmNlOiAzOCwgZTAsIDM3LCBlMCwgYjcsIGI4ICovCgkgICAgICBGSVhNRSgiU3lzUnEgbm90IGhhbmRsZWQgeWV0LlxuIik7CgkgICAgICBicmVhazsKICAgICAgY2FzZSAweDM4OiAvKiBsL3IgbWVudS9hbHQsIFN5c1JxIG91dGVyIHBhcnRzICovCgkgICAgICBiaXQxID0gMzsKCSAgICAgIGlmICghZXh0ZW5kZWQpIC8qIGxlZnQgYWx0IG9ubHkgKi8KCSAgICAgICAgICBiaXQyID0gMTsKCSAgICAgIGJyZWFrOwogICAgICBjYXNlIDB4NDY6IC8qIHNjcm9sbCBsb2NrICovCgkgICAgICBiaXQxID0gNDsKCSAgICAgIGlmICghZXh0ZW5kZWQpIC8qIGxlZnQgY3RybCBvbmx5ICovCgkgICAgICAgICAgYml0MiA9IDQ7CgkgICAgICBicmVhazsKICAgICAgY2FzZSAweDQ1OiAvKiBudW0gbG9jaywgcGF1c2UgKi8KCSAgICAgIGlmIChleHRlbmRlZCkgLyogZGlzdGluZ3Vpc2ggZnJvbSBub24tZXh0ZW5kZWQgUGF1c2Uga2V5ICovCiAgICAgICAgICAgICAgeyAvKiBudW0gbG9jayAqLwoJICAgICAgICAgIGJpdDEgPSA1OwoJICAgICAgICAgIGJpdDIgPSA1OwogICAgICAgICAgICAgIH0KCSAgICAgIGVsc2UKICAgICAgICAgICAgICB7IC8qIHBhdXNlICovCiAgICAgICAgICAgICAgICAgIGlmICghKHNjYW4gJiAweDgwKSkgLyogIm1ha2UiIGNvZGUgKi8KICAgICAgICAgICAgICAgICAgICAgIGJpdDIgPSAzOwogICAgICAgICAgICAgIH0KCSAgICAgIGJyZWFrOwogICAgICBjYXNlIDB4M2E6IC8qIGNhcHMgbG9jayAqLwoJICAgICAgYml0MSA9IDY7CgkgICAgICBiaXQyID0gNjsKCSAgICAgIGJyZWFrOwogICAgICBjYXNlIDB4NTI6IC8qIGluc2VydCAqLwoJICAgICAgYml0MSA9IDc7CgkgICAgICBiaXQyID0gNzsKCSAgICAgICptb2RpZmllciA9IEZBTFNFOyAvKiBpbnNlcnQgaXMgbm8gbW9kaWZpZXI6IHRodXMgcGFzcyB0byBpbnQxNiAqLwoJICAgICAgYnJlYWs7CiAgICB9CiAgICAvKiBub3cgdGhhdCB3ZSBrbm93IHdoaWNoIGJpdHMgdG8gc2V0LCB1cGRhdGUgdGhlbSAqLwogICAgaWYgKCEoc2NhbiAmIDB4ODApKSAvKiAibWFrZSIgY29kZSAoa2V5cHJlc3MpICovCiAgICB7CiAgICAgICAgaWYgKGJpdDIgIT0gMjU1KQogICAgICAgIHsKCSAgICBpZiAoYml0MiA9PSAzKQoJICAgIHsKICAgICAgICAgICAgICAgIGRhdGEtPktiZEZsYWdzMiB8PSAxIDw8IGJpdDI7IC8qIHNldCAiUGF1c2UiIGZsYWcgKi8KICAgICAgICAgICAgICAgIFRSQUNFKCJQQVVTRSBrZXksIHNsZWVwaW5nICFcbiIpOwogICAgICAgICAgICAgICAgLyogd2FpdCBmb3Iga2V5cHJlc3MgdG8gdW5sb2NrIHBhdXNlICovCgkJZG8gewogICAgICAgICAgICAgICAgICAgIFNsZWVwKDU1KTsKCQl9IHdoaWxlICghKFJlYWRDb25zb2xlSW5wdXRBKEdldFN0ZEhhbmRsZShTVERfSU5QVVRfSEFORExFKSwmbXNnLDEsJnJlcykgJiYgKG1zZy5FdmVudFR5cGUgPT0gS0VZX0VWRU5UKSkpOwogICAgICAgICAgICAgICAgZGF0YS0+S2JkRmxhZ3MyICY9IH4oMSA8PCBiaXQyKTsgLyogcmVsZWFzZSAiUGF1c2UiIGZsYWcgKi8KICAgICAgICAgICAgfQoJICAgIGVsc2UKICAgICAgICAgICAgICAgIGRhdGEtPktiZEZsYWdzMiB8PSAxIDw8IGJpdDI7CiAgICAgICAgfQogICAgICAgIGlmIChiaXQxICE9IDI1NSkKICAgICAgICB7CiAgICAgICAgICAgIGlmIChiaXQxIDwgNCkgLyoga2V5ICJwcmVzc2VkIiBmbGFnICovCgkgICAgICAgIGRhdGEtPktiZEZsYWdzMSB8PSAxIDw8IGJpdDE7CiAgICAgICAgICAgIGVsc2UgLyoga2V5ICJhY3RpdmUiIGZsYWcgKi8KICAgICAgICAgICAgICAgIGRhdGEtPktiZEZsYWdzMSBePSAxIDw8IGJpdDE7CiAgICAgICAgfQogICAgfQogICAgZWxzZSAvKiAiYnJlYWsiIC8gcmVsZWFzZSAqLwogICAgewogICAgICAgIGlmIChiaXQyICE9IDI1NSkKICAgICAgICAgICAgZGF0YS0+S2JkRmxhZ3MyICY9IH4oMSA8PCBiaXQyKTsKICAgICAgICBpZiAoYml0MSA8IDQpIC8qIGlzIGl0IGEga2V5ICJwcmVzc2VkIiBiaXQgPyAqLwoJICAgIGRhdGEtPktiZEZsYWdzMSAmPSB+KDEgPDwgYml0MSk7CiAgICB9CiAgICBUUkFDRSgiZXh0LiAlZCwgYml0cyAlZC8lZCwgS2JkRmxhZ3MgJTAyeC8lMDJ4XG4iLCBleHRlbmRlZCwgYml0MSwgYml0MiwgZGF0YS0+S2JkRmxhZ3MxLCBkYXRhLT5LYmRGbGFnczIpOwp9CgovKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKgkgICAgRE9TVk1fSW50MDlIYW5kbGVyIChXSU5FRE9TMTYuMTA5KQogKgogKiBIYW5kbGVyIGZvciBpbnQgMDloLgogKiBTZWUgaHR0cDovL3d3dy5leGVjcGMuY29tL35nZWV6ZXIvb3NkL2tiZC8gZm9yIGEgdmVyeSBnb29kIGRlc2NyaXB0aW9uCiAqIG9mIGtleWJvYXJkIG1hcHBpbmcgbW9kZXMuCiAqLwp2b2lkIFdJTkFQSSBET1NWTV9JbnQwOUhhbmRsZXIoIENPTlRFWFQ4NiAqY29udGV4dCApCnsKICBCSU9TREFUQSAqZGF0YSA9IEJJT1NfREFUQTsKICBCWVRFIGFzY2lpLCBzY2FuID0gRE9TVk1fSW50MDlSZWFkU2NhbigmYXNjaWkpOwogIEJZVEUgcmVhbHNjYW4gPSBzY2FuICYgMHg3ZjsgLyogcmVtb3ZlIDB4ODAgbWFrZS9icmVhayBmbGFnICovCiAgQk9PTCBtb2RpZmllciA9IEZBTFNFOwogIHN0YXRpYyBCT09MIGV4dGVuZGVkID0gRkFMU0U7IC8qIGluZGljYXRlcyBzdGFydCBvZiBleHRlbmRlZCBrZXkgc2VxdWVuY2UgKi8KICBCWVRFIGNoWzJdOwogIGludCBjbnQsIGMyOwoKICBUUkFDRSgic2Nhbj0lMDJ4LCBhc2NpaT0lMDJ4WyVjXVxuIixzY2FuLCBhc2NpaSwgYXNjaWkgPyBhc2NpaSA6ICcgJyk7CgogIGlmIChzY2FuID09IDB4ZTApIC8qIGV4dGVuZGVkIGtleWNvZGUgKi8KICAgICAgZXh0ZW5kZWQgPSBUUlVFOwogIAogIC8qIGNoZWNrIGZvciBrZXlzIGNvbmNlcm5pbmcga2V5Ym9hcmQgc3RhdHVzIGZsYWdzICovCiAgaWYgKChyZWFsc2NhbiA9PSAweDUyIC8qIGluc2VydCAqLykKICB8fCAgKHJlYWxzY2FuID09IDB4M2EgLyogY2FwcyBsb2NrICovKQogIHx8ICAocmVhbHNjYW4gPT0gMHg0NSAvKiBudW0gbG9jayAoZXh0ZW5kZWQpIG9yIHBhdXNlL2JyZWFrICovKQogIHx8ICAocmVhbHNjYW4gPT0gMHg0NiAvKiBzY3JvbGwgbG9jayAqLykKICB8fCAgKHJlYWxzY2FuID09IDB4MmEgLyogbCBzaGlmdCAqLykKICB8fCAgKHJlYWxzY2FuID09IDB4MzYgLyogciBzaGlmdCAqLykKICB8fCAgKHJlYWxzY2FuID09IDB4MzcgLyogU3lzUnEgKi8pCiAgfHwgIChyZWFsc2NhbiA9PSAweDM4IC8qIGwvciBtZW51L2FsdCwgU3lzUnEgKi8pCiAgfHwgIChyZWFsc2NhbiA9PSAweDFkIC8qIGwvciBjb250cm9sICovKSkKICAgICAgRE9TVk1fSW50MDlVcGRhdGVLYmRTdGF0dXNGbGFncyhzY2FuLCBleHRlbmRlZCwgZGF0YSwgJm1vZGlmaWVyKTsKCiAgaWYgKHNjYW4gIT0gMHhlMCkKICAgICAgZXh0ZW5kZWQgPSBGQUxTRTsgLyogcmVzZXQgZXh0ZW5kZWQgZmxhZyBub3cgKi8KCiAgLyogb25seSBpbnRlcmVzdGVkIGluICJtYWtlIiAocHJlc3MpIGNvZGVzLCBub3QgImJyZWFrIiAocmVsZWFzZSksCiAgICogYW5kIGFsc28gbm90IGluICJtb2RpZmllciBrZXkgb25seSIgKHcvbyBhc2NpaSkgbm90aWZpY2F0aW9ucyAqLwogIGlmICghKHNjYW4gJiAweDgwKSAmJiAhKG1vZGlmaWVyICYmICFhc2NpaSkpCiAgewogICAgaWYgKGFzY2lpKSB7CiAgICAgIC8qIHdlIGFscmVhZHkgaGF2ZSBhbiBBU0NJSSBjb2RlLCBubyB0cmFuc2xhdGlvbiBuZWNlc3NhcnkgKi8KICAgICAgaWYgKGRhdGEtPktiZEZsYWdzMSAmIDgpIC8qIEFsdCBrZXkgPyAqLwoJY2hbMF0gPSAwOyAvKiBBU0NJSSBjb2RlIG5lZWRzIHRvIGJlIDAgaWYgQWx0IGFsc28gcHJlc3NlZCAqLwogICAgICBlbHNlCiAgICAgICAgY2hbMF0gPSBhc2NpaTsKICAgICAgLyogRklYTUU6IG5lZWQgdG8gaGFuZGxlIHRoaW5ncyBzdWNoIGFzIFNoaWZ0LUYxIGV0Yy4gKi8KICAgICAgY250ID0gMTsKICAgIH0gZWxzZSB7CiAgICAgIC8qIHRyYW5zbGF0ZSAqLwogICAgICBVSU5UIHZrZXkgPSBNYXBWaXJ0dWFsS2V5QShzY2FuJjB4N2YsIDEpOwogICAgICBCWVRFIGtleXN0YXRlWzI1Nl07CiAgICAgIEdldEtleWJvYXJkU3RhdGUoa2V5c3RhdGUpOwogICAgICBjbnQgPSBUb0FzY2lpKHZrZXksIHNjYW4sIGtleXN0YXRlLCAoTFBXT1JEKWNoLCAwKTsKICAgIH0KICAgIGlmIChjbnQ+MCkgewogICAgICBmb3IgKGMyPTA7IGMyPGNudDsgYzIrKykKICAgICAgICBET1NWTV9JbnQxNkFkZENoYXIoY2hbYzJdLCBzY2FuKTsKICAgIH0gZWxzZQogICAgaWYgKGNudD09MCkgewogICAgICAvKiBGSVhNRTogbmVlZCB0byBoYW5kbGUgdGhpbmdzIGxpa2Ugc2hpZnQtRi1rZXlzLAogICAgICAgKiAweEUwIGV4dGVuZGVkIGtleXMsIGV0YyAqLwogICAgICBET1NWTV9JbnQxNkFkZENoYXIoMCwgc2Nhbik7CiAgICB9CiAgfQoKICBET1NWTV9BY2tub3dsZWRnZUlSUSggY29udGV4dCApOwp9CgpzdGF0aWMgdm9pZCBLYmRSZWxheSggQ09OVEVYVDg2ICpjb250ZXh0LCB2b2lkICpkYXRhICkKewogIGlmIChrYmRpbmZvLnF1ZXVlbGVuKSB7CiAgICAvKiBjbGVhbnVwIG9wZXJhdGlvbiwgY2FsbGVkIGZyb20gRE9TVk1fUElDX2lvcG9ydF9vdXQ6CiAgICAgKiB3ZSdsbCByZW1vdmUgY3VycmVudCBzY2FuY29kZSBmcm9tIGtleWJvYXJkIGJ1ZmZlciBoZXJlLAogICAgICogcmF0aGVyIHRoYW4gaW4gUmVhZFNjYW4sIGJlY2F1c2Ugc29tZSBET1MgYXBwcyBkZXBlbmQgb24KICAgICAqIHRoZSBzY2FuY29kZSBiZWluZyBhdmFpbGFibGUgZm9yIHJlYWRpbmcgbXVsdGlwbGUgdGltZXMuLi4gKi8KICAgIGlmICgtLWtiZGluZm8ucXVldWVsZW4pIHsKICAgICAgbWVtbW92ZShrYmRpbmZvLnF1ZXVlLGtiZGluZm8ucXVldWUrMSxrYmRpbmZvLnF1ZXVlbGVuKTsKICAgICAgbWVtbW92ZShrYmRpbmZvLmFzY2lpLGtiZGluZm8uYXNjaWkrMSxrYmRpbmZvLnF1ZXVlbGVuKTsKICAgIH0KICB9Cn0KCnZvaWQgV0lOQVBJIERPU1ZNX0ludDA5U2VuZFNjYW4oIEJZVEUgc2NhbiwgQllURSBhc2NpaSApCnsKICBpZiAoa2JkaW5mby5xdWV1ZWxlbiA9PSBRVUVVRUxFTikgewogICAgRVJSKCJrZXlib2FyZCBxdWV1ZSBvdmVyZmxvd1xuIik7CiAgICByZXR1cm47CiAgfQogIC8qIGFkZCBzY2FuY29kZSB0byBxdWV1ZSAqLwogIGtiZGluZm8ucXVldWVba2JkaW5mby5xdWV1ZWxlbl0gPSBzY2FuOwogIGtiZGluZm8uYXNjaWlba2JkaW5mby5xdWV1ZWxlbisrXSA9IGFzY2lpOwogIC8qIHRlbGwgYXBwIHRvIHJlYWQgaXQgYnkgdHJpZ2dlcmluZyBJUlEgMSAoaW50IDA5KSAqLwogIERPU1ZNX1F1ZXVlRXZlbnQoMSxET1NfUFJJT1JJVFlfS0VZQk9BUkQsS2JkUmVsYXksTlVMTCk7Cn0KCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqCSAgICBLYmRSZWFkU2NhbiAoV0lORURPUy5AKQogKi8KQllURSBXSU5BUEkgRE9TVk1fSW50MDlSZWFkU2NhbiggQllURSphc2NpaSApCnsKICAgIGlmIChhc2NpaSkgKmFzY2lpID0ga2JkaW5mby5hc2NpaVswXTsKICAgIHJldHVybiBrYmRpbmZvLnF1ZXVlWzBdOwp9Cg==