/**
* PyAudio: Python Bindings for PortAudio.
*
* Copyright (c) 2006-2012 Hubert Pham
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include "Python.h"
#include "portaudio.h"
#include "_portaudiomodule.h"
#ifdef MACOSX
#include "pa_mac_core.h"
#endif
#define DEFAULT_FRAMES_PER_BUFFER 1024
/* #define VERBOSE */
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
/************************************************************
*
* Table of Contents
*
* I. Exportable PortAudio Method Definitions
* II. Python Object Wrappers
* - PaDeviceInfo
* - PaHostInfo
* - PaStream
* III. PortAudio Method Implementations
* - Initialization/Termination
* - HostAPI
* - DeviceAPI
* - Stream Open/Close
* - Stream Start/Stop/Info
* - Stream Read/Write
* IV. Python Module Init
* - PaHostApiTypeId enum constants
*
************************************************************/
/************************************************************
*
* I. Exportable Python Methods
*
************************************************************/
static PyMethodDef paMethods[] = {
/* version */
{"get_version", pa_get_version, METH_VARARGS, "get version"},
{"get_version_text", pa_get_version_text, METH_VARARGS,
"get version text"},
/* inits */
{"initialize", pa_initialize, METH_VARARGS, "initialize portaudio"},
{"terminate", pa_terminate, METH_VARARGS, "terminate portaudio"},
/* host api */
{"get_host_api_count", pa_get_host_api_count, METH_VARARGS,
"get host API count"},
{"get_default_host_api", pa_get_default_host_api, METH_VARARGS,
"get default host API index"},
{"host_api_type_id_to_host_api_index",
pa_host_api_type_id_to_host_api_index, METH_VARARGS,
"get default host API index"},
{"host_api_device_index_to_device_index",
pa_host_api_device_index_to_device_index,
METH_VARARGS,
"get default host API index"},
{"get_host_api_info", pa_get_host_api_info, METH_VARARGS,
"get host api information"},
/* device api */
{"get_device_count", pa_get_device_count, METH_VARARGS,
"get host API count"},
{"get_default_input_device", pa_get_default_input_device, METH_VARARGS,
"get default input device index"},
{"get_default_output_device", pa_get_default_output_device, METH_VARARGS,
"get default output device index"},
{"get_device_info", pa_get_device_info, METH_VARARGS,
"get device information"},
/* stream open/close */
{"open", (PyCFunction) pa_open, METH_VARARGS | METH_KEYWORDS,
"open port audio stream"},
{"close", pa_close, METH_VARARGS, "close port audio stream"},
{"get_sample_size", pa_get_sample_size, METH_VARARGS,
"get sample size of a format in bytes"},
{"is_format_supported", (PyCFunction) pa_is_format_supported,
METH_VARARGS | METH_KEYWORDS,
"returns whether specified format is supported"},
/* stream start/stop */
{"start_stream", pa_start_stream, METH_VARARGS, "starts port audio stream"},
{"stop_stream", pa_stop_stream, METH_VARARGS, "stops port audio stream"},
{"abort_stream", pa_abort_stream, METH_VARARGS, "aborts port audio stream"},
{"is_stream_stopped", pa_is_stream_stopped, METH_VARARGS,
"returns whether stream is stopped"},
{"is_stream_active", pa_is_stream_active, METH_VARARGS,
"returns whether stream is active"},
{"get_stream_time", pa_get_stream_time, METH_VARARGS,
"returns stream time"},
{"get_stream_cpu_load", pa_get_stream_cpu_load, METH_VARARGS,
"returns stream CPU load -- always 0 for blocking mode"},
/* stream read/write */
{"write_stream", pa_write_stream, METH_VARARGS, "write to stream"},
{"read_stream", pa_read_stream, METH_VARARGS, "read from stream"},
{"get_stream_write_available",
pa_get_stream_write_available, METH_VARARGS,
"get buffer available for writing"},
{"get_stream_read_available",
pa_get_stream_read_available, METH_VARARGS,
"get buffer available for reading"},
{NULL, NULL, 0, NULL}
};
/************************************************************
*
* II. Python Object Wrappers
*
************************************************************/
/*************************************************************
* PaDeviceInfo Type : Python object wrapper for PaDeviceInfo
*************************************************************/
typedef struct {
PyObject_HEAD
PaDeviceInfo *devInfo;
} _pyAudio_paDeviceInfo;
/* sepcific getters into the PaDeviceInfo struct */
static PyObject *
_pyAudio_paDeviceInfo_get_structVersion(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyLong_FromLong(self->devInfo->structVersion);
}
static PyObject *
_pyAudio_paDeviceInfo_get_name(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if ((!self->devInfo) || (self->devInfo->name == NULL)) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyBytes_FromString(self->devInfo->name);
}
static PyObject *
_pyAudio_paDeviceInfo_get_hostApi(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyLong_FromLong(self->devInfo->hostApi);
}
static PyObject *
_pyAudio_paDeviceInfo_get_maxInputChannels(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyLong_FromLong(self->devInfo->maxInputChannels);
}
static PyObject *
_pyAudio_paDeviceInfo_get_maxOutputChannels(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyLong_FromLong(self->devInfo->maxOutputChannels);
}
static PyObject *
_pyAudio_paDeviceInfo_get_defaultLowInputLatency(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyFloat_FromDouble(self->devInfo->defaultLowInputLatency);
}
static PyObject *
_pyAudio_paDeviceInfo_get_defaultLowOutputLatency(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyFloat_FromDouble(self->devInfo->defaultLowOutputLatency);
}
static PyObject *
_pyAudio_paDeviceInfo_get_defaultHighInputLatency(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyFloat_FromDouble(self->devInfo->defaultHighInputLatency);
}
static PyObject *
_pyAudio_paDeviceInfo_get_defaultHighOutputLatency(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyFloat_FromDouble(self->devInfo->defaultHighOutputLatency);
}
static PyObject *
_pyAudio_paDeviceInfo_get_defaultSampleRate(_pyAudio_paDeviceInfo *self,
void *closure)
{
/* sanity check */
if (!self->devInfo) {
PyErr_SetString(PyExc_AttributeError,
"No Device Info available");
return NULL;
}
return PyFloat_FromDouble(self->devInfo->defaultSampleRate);
}
static int
_pyAudio_paDeviceInfo_antiset(_pyAudio_paDeviceInfo *self,
PyObject *value,
void *closure)
{
/* read-only: do not allow users to change values */
PyErr_SetString(PyExc_AttributeError,
"Fields read-only: cannot modify values");
return -1;
}
static PyGetSetDef _pyAudio_paDeviceInfo_getseters[] = {
{"name",
(getter) _pyAudio_paDeviceInfo_get_name,
(setter) _pyAudio_paDeviceInfo_antiset,
"device name",
NULL},
{"structVersion",
(getter) _pyAudio_paDeviceInfo_get_structVersion,
(setter) _pyAudio_paDeviceInfo_antiset,
"struct version",
NULL},
{"hostApi",
(getter) _pyAudio_paDeviceInfo_get_hostApi,
(setter) _pyAudio_paDeviceInfo_antiset,
"host api index",
NULL},
{"maxInputChannels",
(getter) _pyAudio_paDeviceInfo_get_maxInputChannels,
(setter) _pyAudio_paDeviceInfo_antiset,
"max input channels",
NULL},
{"maxOutputChannels",
(getter) _pyAudio_paDeviceInfo_get_maxOutputChannels,
(setter) _pyAudio_paDeviceInfo_antiset,
"max output channels",
NULL},
{"defaultLowInputLatency",
(getter) _pyAudio_paDeviceInfo_get_defaultLowInputLatency,
(setter) _pyAudio_paDeviceInfo_antiset,
"default low input latency",
NULL},
{"defaultLowOutputLatency",
(getter) _pyAudio_paDeviceInfo_get_defaultLowOutputLatency,
(setter) _pyAudio_paDeviceInfo_antiset,
"default low output latency",
NULL},
{"defaultHighInputLatency",
(getter) _pyAudio_paDeviceInfo_get_defaultHighInputLatency,
(setter) _pyAudio_paDeviceInfo_antiset,
"default high input latency",
NULL},
{"defaultHighOutputLatency",
(getter) _pyAudio_paDeviceInfo_get_defaultHighOutputLatency,
(setter) _pyAudio_paDeviceInfo_antiset,
"default high output latency",
NULL},
{"defaultSampleRate",
(getter) _pyAudio_paDeviceInfo_get_defaultSampleRate,
(setter) _pyAudio_paDeviceInfo_antiset,
"default sample rate",
NULL},
{NULL}
};
static void
_pyAudio_paDeviceInfo_dealloc(_pyAudio_paDeviceInfo* self)
{
/* reset the pointer */
self->devInfo = NULL;
/* free the object */
Py_TYPE(self)->tp_free((PyObject*) self);
}
static PyTypeObject _pyAudio_paDeviceInfoType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_portaudio.paDeviceInfo", /*tp_name*/
sizeof(_pyAudio_paDeviceInfo), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor) _pyAudio_paDeviceInfo_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Port Audio Device Info", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
_pyAudio_paDeviceInfo_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
static _pyAudio_paDeviceInfo *
_create_paDeviceInfo_object(void)
{
_pyAudio_paDeviceInfo *obj;
/* don't allow subclassing? */
obj = (_pyAudio_paDeviceInfo *) PyObject_New(_pyAudio_paDeviceInfo,
&_pyAudio_paDeviceInfoType);
/* obj = (_pyAudio_Stream*)
_pyAudio_StreamType.tp_alloc(&_pyAudio_StreamType, 0); */
return obj;
}
/*************************************************************
* PaHostApi Info Python Object
*************************************************************/
typedef struct {
PyObject_HEAD
PaHostApiInfo *apiInfo;
} _pyAudio_paHostApiInfo;
/* sepcific getters into the PaDeviceInfo struct */
static PyObject *
_pyAudio_paHostApiInfo_get_structVersion(_pyAudio_paHostApiInfo *self,
void *closure)
{
/* sanity check */
if ((!self->apiInfo)) {
PyErr_SetString(PyExc_AttributeError,
"No HostApi Info available");
return NULL;
}
return PyLong_FromLong(self->apiInfo->structVersion);
}
static PyObject *
_pyAudio_paHostApiInfo_get_type(_pyAudio_paHostApiInfo *self,
void *closure)
{
/* sanity check */
if ((!self->apiInfo)) {
PyErr_SetString(PyExc_AttributeError,
"No HostApi Info available");
return NULL;
}
return PyLong_FromLong((long) self->apiInfo->type);
}
static PyObject *
_pyAudio_paHostApiInfo_get_name(_pyAudio_paHostApiInfo *self,
void *closure)
{
/* sanity check */
if ((!self->apiInfo) || (self->apiInfo->name == NULL)) {
PyErr_SetString(PyExc_AttributeError,
"No HostApi Info available");
return NULL;
}
return PyUnicode_FromString(self->apiInfo->name);
}
static PyObject *
_pyAudio_paHostApiInfo_get_deviceCount(_pyAudio_paHostApiInfo *self,
void *closure)
{
/* sanity check */
if ((!self->apiInfo)) {
PyErr_SetString(PyExc_AttributeError,
"No HostApi Info available");
return NULL;
}
return PyLong_FromLong(self->apiInfo->deviceCount);
}
static PyObject *
_pyAudio_paHostApiInfo_get_defaultInputDevice(_pyAudio_paHostApiInfo *self,
void *closure)
{
/* sanity check */
if ((!self->apiInfo)) {
PyErr_SetString(PyExc_AttributeError,
"No HostApi Info available");
return NULL;
}
return PyLong_FromLong(self->apiInfo->defaultInputDevice);
}
static PyObject *
_pyAudio_paHostApiInfo_get_defaultOutputDevice(_pyAudio_paHostApiInfo *self,
void *closure)
{
/* sanity check */
if ((!self->apiInfo)) {
PyErr_SetString(PyExc_AttributeError,
"No HostApi Info available");
return NULL;
}
return PyLong_FromLong(self->apiInfo->defaultOutputDevice);
}
static int
_pyAudio_paHostApiInfo_antiset(_pyAudio_paDeviceInfo *self,
PyObject *value,
void *closure)
{
/* read-only: do not allow users to change values */
PyErr_SetString(PyExc_AttributeError,
"Fields read-only: cannot modify values");
return -1;
}
static void
_pyAudio_paHostApiInfo_dealloc(_pyAudio_paHostApiInfo* self)
{
/* reset the pointer */
self->apiInfo = NULL;
/* free the object */
Py_TYPE(self)->tp_free((PyObject*) self);
}
static PyGetSetDef _pyAudio_paHostApiInfo_getseters[] = {
{"name",
(getter) _pyAudio_paHostApiInfo_get_name,
(setter) _pyAudio_paHostApiInfo_antiset,
"host api name",
NULL},
{"structVersion",
(getter) _pyAudio_paHostApiInfo_get_structVersion,
(setter) _pyAudio_paHostApiInfo_antiset,
"struct version",
NULL},
{"type",
(getter) _pyAudio_paHostApiInfo_get_type,
(setter) _pyAudio_paHostApiInfo_antiset,
"host api type",
NULL},
{"deviceCount",
(getter) _pyAudio_paHostApiInfo_get_deviceCount,
(setter) _pyAudio_paHostApiInfo_antiset,
"number of devices",
NULL},
{"defaultInputDevice",
(getter) _pyAudio_paHostApiInfo_get_defaultInputDevice,
(setter) _pyAudio_paHostApiInfo_antiset,
"default input device index",
NULL},
{"defaultOutputDevice",
(getter) _pyAudio_paHostApiInfo_get_defaultOutputDevice,
(setter) _pyAudio_paDeviceInfo_antiset,
"default output device index",
NULL},
{NULL}
};
static PyTypeObject _pyAudio_paHostApiInfoType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_portaudio.paHostApiInfo", /*tp_name*/
sizeof(_pyAudio_paHostApiInfo), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor) _pyAudio_paHostApiInfo_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Port Audio HostApi Info", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
_pyAudio_paHostApiInfo_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
static _pyAudio_paHostApiInfo *
_create_paHostApiInfo_object(void)
{
_pyAudio_paHostApiInfo *obj;
/* don't allow subclassing? */
obj = (_pyAudio_paHostApiInfo *) PyObject_New(_pyAudio_paHostApiInfo,
&_pyAudio_paHostApiInfoType);
return obj;
}
/*************************************************************
* Host-Specific Objects
*************************************************************/
/*************************************************************
* --> Mac OS X
*************************************************************/
#ifdef MACOSX
typedef struct {
PyObject_HEAD
PaMacCoreStreamInfo *paMacCoreStreamInfo;
int flags;
SInt32 *channelMap;
int channelMapSize;
} _pyAudio_MacOSX_hostApiSpecificStreamInfo;
typedef _pyAudio_MacOSX_hostApiSpecificStreamInfo _pyAudio_Mac_HASSI;
static void
_pyAudio_MacOSX_hostApiSpecificStreamInfo_cleanup(_pyAudio_Mac_HASSI *self)
{
if (self->paMacCoreStreamInfo != NULL) {
free(self
->paMacCoreStreamInfo
); self->paMacCoreStreamInfo = NULL;
}
if (self->channelMap != NULL) {
self->channelMap = NULL;
}
self->flags = paMacCorePlayNice;
self->channelMapSize = 0;
}
static void
_pyAudio_MacOSX_hostApiSpecificStreamInfo_dealloc(_pyAudio_Mac_HASSI *self)
{
_pyAudio_MacOSX_hostApiSpecificStreamInfo_cleanup(self);
Py_TYPE(self)->tp_free((PyObject *) self);
}
static int
_pyAudio_MacOSX_hostApiSpecificStreamInfo_init(PyObject *_self,
PyObject *args,
PyObject *kwargs)
{
_pyAudio_Mac_HASSI *self = (_pyAudio_Mac_HASSI *) _self;
PyObject *channel_map = NULL;
int flags = paMacCorePlayNice;
static char *kwlist[] = {"flags", "channel_map", NULL};
if (! PyArg_ParseTupleAndKeywords(args, kwargs, "|iO", kwlist,
&flags, &channel_map)) {
return -1;
}
// cleanup (just in case)
_pyAudio_MacOSX_hostApiSpecificStreamInfo_cleanup(self);
if (channel_map != NULL) {
// ensure channel_map is an array
if (! PyTuple_Check(channel_map)) {
PyErr_SetString(PyExc_ValueError, "Channel map must be a tuple");
return -1;
}
// generate SInt32 channelMap
self->channelMapSize = (int) PyTuple_Size(channel_map);
self
->channelMap
= (SInt32
*) malloc(sizeof(SInt32
) * self
->channelMapSize
);
if (self->channelMap == NULL) {
PyErr_SetString(PyExc_SystemError, "Out of memory");
_pyAudio_MacOSX_hostApiSpecificStreamInfo_cleanup(self);
return -1;
}
PyObject *element;
int i;
for (i = 0; i < self->channelMapSize; ++i) {
element = PyTuple_GetItem(channel_map, i);
if (element == NULL) {
// error condition
PyErr_SetString(PyExc_ValueError,
"Internal error: out of bounds index");
_pyAudio_MacOSX_hostApiSpecificStreamInfo_cleanup(self);
return -1;
}
// make sure element is an integer
if (!PyNumber_Check(element)) {
PyErr_SetString(PyExc_ValueError,
"Channel Map must consist of integer elements");
_pyAudio_MacOSX_hostApiSpecificStreamInfo_cleanup(self);
return -1;
}
PyObject *long_element = PyNumber_Long(element);
// OK, looks good
self->channelMap[i] = (SInt32) PyLong_AsLong(long_element);
Py_DECREF(long_element);
}
}
// malloc self->paMacCoreStreamInfo
self->paMacCoreStreamInfo =
(PaMacCoreStreamInfo
*) malloc(sizeof(PaMacCoreStreamInfo
));
if (self->paMacCoreStreamInfo == NULL) {
PyErr_SetString(PyExc_SystemError, "Out of memeory");
_pyAudio_MacOSX_hostApiSpecificStreamInfo_cleanup(self);
return -1;
}
PaMacCore_SetupStreamInfo(self->paMacCoreStreamInfo, flags);
if (self->channelMap) {
PaMacCore_SetupChannelMap(self->paMacCoreStreamInfo,
self->channelMap,
self->channelMapSize);
}
self->flags = flags;
return 0;
}
static PyObject *
_pyAudio_MacOSX_hostApiSpecificStreamInfo_get_flags(_pyAudio_Mac_HASSI *self,
void *closure)
{
return PyLong_FromLong(self->flags);
}
static PyObject *
_pyAudio_MacOSX_hostApiSpecificStreamInfo_get_channel_map(
_pyAudio_Mac_HASSI *self,
void *closure)
{
if (self->channelMap == NULL || self->channelMapSize == 0) {
Py_INCREF(Py_None);
return Py_None;
}
int i;
PyObject *channelMapTuple = PyTuple_New(self->channelMapSize);
for (i = 0; i < self->channelMapSize; ++i) {
PyObject *element = PyLong_FromLong(self->channelMap[i]);
if (!element) {
PyErr_SetString(PyExc_SystemError, "Invalid channel map");
return NULL;
}
if (PyTuple_SetItem(channelMapTuple,
i,
PyLong_FromLong(self->channelMap[i]))) {
// non-zero on error
PyErr_SetString(PyExc_SystemError, "Can't create channel map.");
return NULL;
}
}
return channelMapTuple;
}
static int
_pyAudio_MacOSX_hostApiSpecificStreamInfo_antiset(_pyAudio_Mac_HASSI *self,
PyObject *value,
void *closure)
{
/* read-only: do not allow users to change values */
PyErr_SetString(PyExc_AttributeError,
"Fields read-only: cannot modify values");
return -1;
}
static PyGetSetDef _pyAudio_MacOSX_hostApiSpecificStreamInfo_getseters[] = {
{"flags",
(getter) _pyAudio_MacOSX_hostApiSpecificStreamInfo_get_flags,
(setter) _pyAudio_MacOSX_hostApiSpecificStreamInfo_antiset,
"flags",
NULL},
{"channel_map",
(getter) _pyAudio_MacOSX_hostApiSpecificStreamInfo_get_channel_map,
(setter) _pyAudio_MacOSX_hostApiSpecificStreamInfo_antiset,
"channel map",
NULL},
{NULL}
};
static PyTypeObject _pyAudio_MacOSX_hostApiSpecificStreamInfoType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_portaudio.PaMacCoreStreamInfo", /*tp_name*/
sizeof(_pyAudio_MacOSX_hostApiSpecificStreamInfo), /*tp_basicsize*/
0, /*tp_itemsize*/
/*tp_dealloc*/
(destructor) _pyAudio_MacOSX_hostApiSpecificStreamInfo_dealloc,
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Mac OS X Specific HostAPI configuration", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
_pyAudio_MacOSX_hostApiSpecificStreamInfo_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(int (*)(PyObject*, PyObject*, PyObject*))_pyAudio_MacOSX_hostApiSpecificStreamInfo_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
#endif
/*************************************************************
* Stream Wrapper Python Object
*************************************************************/
typedef struct {
PyObject *callback;
long main_thread_id;
unsigned int frame_size;
} PyAudioCallbackContext;
typedef struct {
PyObject_HEAD
PaStream *stream;
PaStreamParameters *inputParameters;
PaStreamParameters *outputParameters;
/* include PaStreamInfo too! */
PaStreamInfo *streamInfo;
/* context for callback */
PyAudioCallbackContext *callbackContext;
int is_open;
} _pyAudio_Stream;
static int
_is_open(_pyAudio_Stream *obj) {
return (obj) && (obj->is_open);
}
static void
_cleanup_Stream_object(_pyAudio_Stream *streamObject)
{
if (streamObject->stream != NULL) {
Py_BEGIN_ALLOW_THREADS
Pa_CloseStream(streamObject->stream);
Py_END_ALLOW_THREADS
streamObject->stream = NULL;
}
if (streamObject->streamInfo)
streamObject->streamInfo = NULL;
if (streamObject->inputParameters != NULL) {
free(streamObject
->inputParameters
); streamObject->inputParameters = NULL;
}
if (streamObject->outputParameters != NULL) {
free(streamObject
->outputParameters
); streamObject->outputParameters = NULL;
}
if (streamObject->callbackContext != NULL) {
Py_XDECREF(streamObject->callbackContext->callback);
free(streamObject
->callbackContext
); streamObject->callbackContext = NULL;
}
/* designate the stream as closed */
streamObject->is_open = 0;
}
static void
_pyAudio_Stream_dealloc(_pyAudio_Stream* self)
{
/* deallocate memory if necessary */
_cleanup_Stream_object(self);
/* free the object */
Py_TYPE(self)->tp_free((PyObject*) self);
}
static PyObject *
_pyAudio_Stream_get_structVersion(_pyAudio_Stream *self,
void *closure)
{
/* sanity check */
if (!_is_open(self)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
if ((!self->streamInfo)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"No StreamInfo available",
paBadStreamPtr));
return NULL;
}
return PyLong_FromLong(self->streamInfo->structVersion);
}
static PyObject *
_pyAudio_Stream_get_inputLatency(_pyAudio_Stream *self,
void *closure)
{
/* sanity check */
if (!_is_open(self)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
/* sanity check */
if ((!self->streamInfo)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"No StreamInfo available",
paBadStreamPtr));
return NULL;
}
return PyFloat_FromDouble(self->streamInfo->inputLatency);
}
static PyObject *
_pyAudio_Stream_get_outputLatency(_pyAudio_Stream *self,
void *closure)
{
/* sanity check */
if (!_is_open(self)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
/* sanity check */
if ((!self->streamInfo)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"No StreamInfo available",
paBadStreamPtr));
return NULL;
}
return PyFloat_FromDouble(self->streamInfo->outputLatency);
}
static PyObject *
_pyAudio_Stream_get_sampleRate(_pyAudio_Stream *self,
void *closure)
{
/* sanity check */
if (!_is_open(self)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
/* sanity check */
if ((!self->streamInfo)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"No StreamInfo available",
paBadStreamPtr));
return NULL;
}
return PyFloat_FromDouble(self->streamInfo->sampleRate);
}
static int
_pyAudio_Stream_antiset(_pyAudio_Stream *self,
PyObject *value,
void *closure)
{
/* read-only: do not allow users to change values */
PyErr_SetString(PyExc_AttributeError,
"Fields read-only: cannot modify values");
return -1;
}
static PyGetSetDef _pyAudio_Stream_getseters[] = {
{"structVersion",
(getter) _pyAudio_Stream_get_structVersion,
(setter) _pyAudio_Stream_antiset,
"struct version",
NULL},
{"inputLatency",
(getter) _pyAudio_Stream_get_inputLatency,
(setter) _pyAudio_Stream_antiset,
"input latency",
NULL},
{"outputLatency",
(getter) _pyAudio_Stream_get_outputLatency,
(setter) _pyAudio_Stream_antiset,
"output latency",
NULL},
{"sampleRate",
(getter) _pyAudio_Stream_get_sampleRate,
(setter) _pyAudio_Stream_antiset,
"sample rate",
NULL},
{NULL}
};
static PyTypeObject _pyAudio_StreamType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_portaudio.Stream", /*tp_name*/
sizeof(_pyAudio_Stream), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor) _pyAudio_Stream_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Port Audio Stream", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
_pyAudio_Stream_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
static _pyAudio_Stream *
_create_Stream_object(void)
{
_pyAudio_Stream *obj;
/* don't allow subclassing? */
obj = (_pyAudio_Stream *) PyObject_New(_pyAudio_Stream,
&_pyAudio_StreamType);
return obj;
}
/************************************************************
*
* III. PortAudio Method Implementations
*
************************************************************/
/*************************************************************
* Version Info
*************************************************************/
static PyObject *
pa_get_version(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
return PyLong_FromLong(Pa_GetVersion());
}
static PyObject *
pa_get_version_text(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
return PyUnicode_FromString(Pa_GetVersionText());
}
/*************************************************************
* Initialization/Termination
*************************************************************/
static PyObject *
pa_initialize(PyObject *self, PyObject *args)
{
int err;
err = Pa_Initialize();
if (err != paNoError) {
Pa_Terminate();
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", err
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(err
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err), err));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pa_terminate(PyObject *self, PyObject *args)
{
Pa_Terminate();
Py_INCREF(Py_None);
return Py_None;
}
/*************************************************************
* HostAPI
*************************************************************/
static PyObject *
pa_get_host_api_count(PyObject *self, PyObject *args)
{
PaHostApiIndex count;
if (!PyArg_ParseTuple(args, ""))
return NULL;
count = Pa_GetHostApiCount();
if (count < 0) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", count
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(count
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(count), count));
return NULL;
}
return PyLong_FromLong(count);
}
static PyObject *
pa_get_default_host_api(PyObject *self, PyObject *args)
{
PaHostApiIndex index;
if (!PyArg_ParseTuple(args, ""))
return NULL;
index = Pa_GetDefaultHostApi();
if (index < 0) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", index
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(index
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(index), index));
return NULL;
}
return PyLong_FromLong(index);
}
static PyObject *
pa_host_api_type_id_to_host_api_index(PyObject *self, PyObject *args)
{
PaHostApiTypeId typeid;
PaHostApiIndex index;
if (!PyArg_ParseTuple(args, "i", &typeid))
return NULL;
index = Pa_HostApiTypeIdToHostApiIndex(typeid);
if (index < 0) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", index
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(index
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(index), index));
return NULL;
}
return PyLong_FromLong(index);
}
static PyObject *
pa_host_api_device_index_to_device_index(PyObject *self, PyObject *args)
{
PaHostApiIndex apiIndex;
int hostApiDeviceindex;
PaDeviceIndex devIndex;
if (!PyArg_ParseTuple(args, "ii", &apiIndex, &hostApiDeviceindex))
return NULL;
devIndex = Pa_HostApiDeviceIndexToDeviceIndex(apiIndex, hostApiDeviceindex);
if (devIndex < 0) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", devIndex
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(devIndex
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(devIndex), devIndex));
return NULL;
}
return PyLong_FromLong(devIndex);
}
static PyObject *
pa_get_host_api_info(PyObject *self, PyObject *args)
{
PaHostApiIndex index;
PaHostApiInfo* _info;
_pyAudio_paHostApiInfo* py_info;
if (!PyArg_ParseTuple(args, "i", &index))
return NULL;
_info = (PaHostApiInfo *) Pa_GetHostApiInfo(index);
if (!_info) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Invalid host api info",
paInvalidHostApi));
return NULL;
}
py_info = _create_paHostApiInfo_object();
py_info->apiInfo = _info;
return (PyObject *) py_info;
}
/*************************************************************
* Device API
*************************************************************/
static PyObject *
pa_get_device_count(PyObject *self, PyObject *args)
{
PaDeviceIndex count;
if (!PyArg_ParseTuple(args, ""))
return NULL;
count = Pa_GetDeviceCount();
if (count < 0) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", count
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(count
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(count), count));
return NULL;
}
return PyLong_FromLong(count);
}
static PyObject *
pa_get_default_input_device(PyObject *self, PyObject *args)
{
PaDeviceIndex index;
if (!PyArg_ParseTuple(args, ""))
return NULL;
index = Pa_GetDefaultInputDevice();
if (index == paNoDevice) {
PyErr_SetString(PyExc_IOError, "No Default Input Device Available");
return NULL;
} else if (index < 0) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", index
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(index
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(index), index));
return NULL;
}
return PyLong_FromLong(index);
}
static PyObject *
pa_get_default_output_device(PyObject *self, PyObject *args)
{
PaDeviceIndex index;
if (!PyArg_ParseTuple(args, ""))
return NULL;
index = Pa_GetDefaultOutputDevice();
if (index == paNoDevice) {
PyErr_SetString(PyExc_IOError, "No Default Output Device Available");
return NULL;
} else if (index < 0) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", index
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(index
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(index), index));
return NULL;
}
return PyLong_FromLong(index);
}
static PyObject *
pa_get_device_info(PyObject *self, PyObject *args)
{
PaDeviceIndex index;
PaDeviceInfo* _info;
_pyAudio_paDeviceInfo* py_info;
if (!PyArg_ParseTuple(args, "i", &index))
return NULL;
_info = (PaDeviceInfo *) Pa_GetDeviceInfo(index);
if (!_info) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Invalid device info", paInvalidDevice));
return NULL;
}
py_info = _create_paDeviceInfo_object();
py_info->devInfo = _info;
return (PyObject *) py_info;
}
/*************************************************************
* Stream Open / Close / Supported
*************************************************************/
int
_stream_callback_cfunction(const void *input,
void *output,
unsigned long frameCount,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
int return_val = paAbort;
PyGILState_STATE _state = PyGILState_Ensure();
#ifdef VERBOSE
if (statusFlags != 0) {
if (statusFlags & paInputUnderflow) {
}
if (statusFlags & paInputOverflow) {
}
if (statusFlags & paOutputUnderflow) {
printf("output underflow!\n"); }
if (statusFlags & paOutputUnderflow) {
}
if (statusFlags & paPrimingOutput) {
}
}
#endif
PyAudioCallbackContext *context = (PyAudioCallbackContext *)userData;
PyObject *py_callback = context->callback;
unsigned int bytes_per_frame = context->frame_size;
long main_thread_id = context->main_thread_id;
PyObject *py_frame_count = PyLong_FromUnsignedLong(frameCount);
PyObject *py_time_info = Py_BuildValue("{s:d,s:d,s:d}",
"input_buffer_adc_time",
timeInfo->inputBufferAdcTime,
"current_time",
timeInfo->currentTime,
"output_buffer_dac_time",
timeInfo->outputBufferDacTime);
PyObject *py_status_flags = PyLong_FromUnsignedLong(statusFlags);
PyObject *py_input_data = Py_None;
const char *pData;
int output_len;
PyObject *py_result;
if (input) {
py_input_data = PyBytes_FromStringAndSize(input,
bytes_per_frame * frameCount);
}
py_result = PyObject_CallFunctionObjArgs(py_callback,
py_input_data,
py_frame_count,
py_time_info,
py_status_flags,
NULL);
if (py_result == NULL) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error message: Could not call callback function\n"); #endif
PyObject *err = PyErr_Occurred();
if (err) {
PyThreadState_SetAsyncExc(main_thread_id, err);
// Print out a stack trace to help debugging.
// TODO: make VERBOSE a runtime flag so users can control
// the amount of logging.
PyErr_Print();
}
goto end;
}
if (!PyArg_ParseTuple(py_result,
"z#i",
&pData,
&output_len,
&return_val)) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error message: Could not parse callback return value\n"); #endif
PyObject *err = PyErr_Occurred();
if (err) {
PyThreadState_SetAsyncExc(main_thread_id, err);
// Print out a stack trace to help debugging.
// TODO: make VERBOSE a runtime flag so users can control
// the amount of logging.
PyErr_Print();
}
Py_XDECREF(py_result);
return_val = paAbort;
goto end;
}
Py_DECREF(py_result);
if ((return_val != paComplete) &&
(return_val != paAbort) &&
(return_val != paContinue)) {
PyErr_SetString(PyExc_ValueError,
"Invalid PaStreamCallbackResult from callback");
PyThreadState_SetAsyncExc(main_thread_id, PyErr_Occurred());
PyErr_Print();
// Quit the callback loop
return_val = paAbort;
goto end;
}
// Copy bytes for playback only if this is an output stream:
if (output) {
char *output_data = (char*)output;
memcpy(output_data
, pData
, min
(output_len
, bytes_per_frame
* frameCount
));
// Pad out the rest of the buffer with 0s if callback returned
// too few frames (and assume paComplete).
if (output_len < (frameCount * bytes_per_frame)) {
memset(output_data
+ output_len
, 0,
(frameCount * bytes_per_frame) - output_len);
return_val = paComplete;
}
}
end:
if (input) {
// Decrement this at the end, after memcpy, in case the user
// returns py_input_data back for playback.
Py_DECREF(py_input_data);
}
Py_XDECREF(py_frame_count);
Py_XDECREF(py_time_info);
Py_XDECREF(py_status_flags);
PyGILState_Release(_state);
return return_val;
}
static PyObject *
pa_open(PyObject *self, PyObject *args, PyObject *kwargs)
{
int rate, channels;
int input, output, frames_per_buffer;
int input_device_index = -1;
int output_device_index = -1;
PyObject *input_device_index_arg = NULL;
PyObject *output_device_index_arg = NULL;
PyObject *stream_callback = NULL;
PaSampleFormat format;
PaError err;
PyObject *input_device_index_long;
PyObject *output_device_index_long;
PaStreamParameters *outputParameters = NULL;
PaStreamParameters *inputParameters = NULL;
PaStream *stream = NULL;
PaStreamInfo *streamInfo = NULL;
PyAudioCallbackContext *context = NULL;
_pyAudio_Stream *streamObject;
/* pass in rate, channel, width */
static char *kwlist[] = {"rate",
"channels",
"format",
"input",
"output",
"input_device_index",
"output_device_index",
"frames_per_buffer",
"input_host_api_specific_stream_info",
"output_host_api_specific_stream_info",
"stream_callback",
NULL};
#ifdef MACOSX
_pyAudio_MacOSX_hostApiSpecificStreamInfo *inputHostSpecificStreamInfo =
NULL;
_pyAudio_MacOSX_hostApiSpecificStreamInfo *outputHostSpecificStreamInfo =
NULL;
#else
/* mostly ignored...*/
PyObject *inputHostSpecificStreamInfo = NULL;
PyObject *outputHostSpecificStreamInfo = NULL;
#endif
/* default to neither output nor input */
input = 0;
output = 0;
frames_per_buffer = DEFAULT_FRAMES_PER_BUFFER;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
#ifdef MACOSX
"iik|iiOOiO!O!O",
#else
"iik|iiOOiOOO",
#endif
kwlist,
&rate, &channels, &format,
&input, &output,
&input_device_index_arg,
&output_device_index_arg,
&frames_per_buffer,
#ifdef MACOSX
&_pyAudio_MacOSX_hostApiSpecificStreamInfoType,
#endif
&inputHostSpecificStreamInfo,
#ifdef MACOSX
&_pyAudio_MacOSX_hostApiSpecificStreamInfoType,
#endif
&outputHostSpecificStreamInfo,
&stream_callback))
return NULL;
if (stream_callback && (PyCallable_Check(stream_callback) == 0)) {
PyErr_SetString(PyExc_TypeError, "stream_callback must be callable");
return NULL;
}
/* check to see if device indices were specified */
if ((input_device_index_arg == NULL) ||
(input_device_index_arg == Py_None)) {
#ifdef VERBOSE
printf("Using default input device\n"); #endif
input_device_index = -1;
} else {
// Support both Python 2 and Python 3 by using PyNumber_Check
if (!PyNumber_Check(input_device_index_arg)) {
PyErr_SetString(PyExc_ValueError,
"input_device_index must be integer (or None)");
return NULL;
}
input_device_index_long =
PyNumber_Long(input_device_index_arg);
input_device_index = (int) PyLong_AsLong(input_device_index_long);
Py_DECREF(input_device_index_long);
#ifdef VERBOSE
printf("Using input device index number: %d\n", input_device_index
); #endif
}
if ((output_device_index_arg == NULL) ||
(output_device_index_arg == Py_None)) {
#ifdef VERBOSE
printf("Using default output device\n"); #endif
output_device_index = -1;
} else {
// Support both Python 2 and Python 3 by using PyNumber_Check
if (!PyNumber_Check(output_device_index_arg)) {
PyErr_SetString(PyExc_ValueError,
"output_device_index must be integer (or None)");
return NULL;
}
output_device_index_long =
PyNumber_Long(output_device_index_arg);
output_device_index = (int) PyLong_AsLong(output_device_index_long);
Py_DECREF(output_device_index_long);
#ifdef VERBOSE
printf("Using output device index number: %d\n", output_device_index
); #endif
}
/* sanity checks */
if (input == 0 && output == 0) {
PyErr_SetString(PyExc_ValueError, "Must specify either input or output");
return NULL;
}
if (channels < 1) {
PyErr_SetString(PyExc_ValueError, "Invalid audio channels");
return NULL;
}
if (output) {
outputParameters =
(PaStreamParameters
*) malloc(sizeof(PaStreamParameters
));
if (output_device_index < 0)
/* default output device */
outputParameters->device = Pa_GetDefaultOutputDevice();
else
outputParameters->device = output_device_index;
/* final check -- ensure that there is a default device */
if (outputParameters->device < 0 ||
outputParameters->device >= Pa_GetDeviceCount()) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Invalid output device "
"(no default output device)",
paInvalidDevice));
return NULL;
}
outputParameters->channelCount = channels;
outputParameters->sampleFormat = format;
outputParameters->suggestedLatency =
Pa_GetDeviceInfo(outputParameters->device)->defaultLowOutputLatency;
outputParameters->hostApiSpecificStreamInfo = NULL;
#ifdef MACOSX
if (outputHostSpecificStreamInfo) {
outputParameters->hostApiSpecificStreamInfo =
outputHostSpecificStreamInfo->paMacCoreStreamInfo;
}
#endif
}
if (input) {
inputParameters =
(PaStreamParameters
*) malloc(sizeof(PaStreamParameters
));
if (input_device_index < 0) {
/* default output device */
inputParameters->device = Pa_GetDefaultInputDevice();
} else {
inputParameters->device = input_device_index;
}
/* final check -- ensure that there is a default device */
if (inputParameters->device < 0) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Invalid input device "
"(no default output device)",
paInvalidDevice));
return NULL;
}
inputParameters->channelCount = channels;
inputParameters->sampleFormat = format;
inputParameters->suggestedLatency =
Pa_GetDeviceInfo(inputParameters->device)->defaultLowInputLatency;
inputParameters->hostApiSpecificStreamInfo = NULL;
#ifdef MACOSX
if (inputHostSpecificStreamInfo) {
inputParameters->hostApiSpecificStreamInfo =
inputHostSpecificStreamInfo->paMacCoreStreamInfo;
}
#endif
}
// Handle callback mode:
if (stream_callback) {
Py_INCREF(stream_callback);
context
= (PyAudioCallbackContext
*) malloc(sizeof(PyAudioCallbackContext
)); context->callback = (PyObject *) stream_callback;
context->main_thread_id = PyThreadState_Get()->thread_id;
context->frame_size = Pa_GetSampleSize(format) * channels;
}
err = Pa_OpenStream(&stream,
/* input/output parameters */
/* NULL values are ignored */
inputParameters,
outputParameters,
/* Samples Per Second */
rate,
/* allocate frames in the buffer */
frames_per_buffer,
/* we won't output out of range samples
so don't bother clipping them */
paClipOff,
/* callback, if specified */
(stream_callback)?(_stream_callback_cfunction):(NULL),
/* callback userData, if applicable */
context);
if (err != paNoError) {
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", err
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(err
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err), err));
return NULL;
}
streamInfo = (PaStreamInfo *) Pa_GetStreamInfo(stream);
if (!streamInfo) {
/* Pa_Terminate(); */
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Could not get stream information",
paInternalError));
return NULL;
}
streamObject = _create_Stream_object();
streamObject->stream = stream;
streamObject->inputParameters = inputParameters;
streamObject->outputParameters = outputParameters;
streamObject->is_open = 1;
streamObject->streamInfo = streamInfo;
streamObject->callbackContext = context;
return (PyObject *) streamObject;
}
static PyObject *
pa_close(PyObject *self, PyObject *args)
{
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
_cleanup_Stream_object(streamObject);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pa_get_sample_size(PyObject *self, PyObject *args)
{
PaSampleFormat format;
int size_in_bytes;
if (!PyArg_ParseTuple(args, "k", &format))
return NULL;
size_in_bytes = Pa_GetSampleSize(format);
if (size_in_bytes < 0) {
PyErr_SetObject(PyExc_ValueError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(size_in_bytes),
size_in_bytes));
return NULL;
}
return PyLong_FromLong(size_in_bytes);
}
static PyObject *
pa_is_format_supported(PyObject *self, PyObject *args,
PyObject *kwargs)
{
/* pass in rate, channel, width */
static char *kwlist[] = {
"sample_rate",
"input_device",
"input_channels",
"input_format",
"output_device",
"output_channels",
"output_format",
NULL
};
int input_device, input_channels;
int output_device, output_channels;
float sample_rate;
PaStreamParameters inputParams;
PaStreamParameters outputParams;
PaSampleFormat input_format, output_format;
PaError error;
input_device = input_channels =
output_device = output_channels = -1;
input_format = output_format = -1;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "f|iikiik", kwlist,
&sample_rate,
&input_device,
&input_channels,
&input_format,
&output_device,
&output_channels,
&output_format))
return NULL;
if (!(input_device < 0)) {
inputParams.device = input_device;
inputParams.channelCount = input_channels;
inputParams.sampleFormat = input_format;
inputParams.suggestedLatency = 0;
inputParams.hostApiSpecificStreamInfo = NULL;
}
if (!(output_device < 0)) {
outputParams.device = output_device;
outputParams.channelCount = output_channels;
outputParams.sampleFormat = output_format;
outputParams.suggestedLatency = 0;
outputParams.hostApiSpecificStreamInfo = NULL;
}
error = Pa_IsFormatSupported((input_device < 0) ? NULL : &inputParams,
(output_device < 0) ? NULL : &outputParams,
sample_rate);
if (error == paFormatIsSupported) {
Py_INCREF(Py_True);
return Py_True;
} else {
PyErr_SetObject(PyExc_ValueError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(error),
error));
return NULL;
}
}
/*************************************************************
* Stream Start / Stop / Info
*************************************************************/
static PyObject *
pa_start_stream(PyObject *self, PyObject *args)
{
int err;
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
stream = streamObject->stream;
if ( ((err = Pa_StartStream(stream)) != paNoError) &&
(err != paStreamIsNotStopped)) {
_cleanup_Stream_object(streamObject);
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", err
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(err
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err),
err));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pa_stop_stream(PyObject *self, PyObject *args)
{
int err;
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetString(PyExc_IOError, "Stream not open");
return NULL;
}
stream = streamObject->stream;
Py_BEGIN_ALLOW_THREADS
err = Pa_StopStream(stream);
Py_END_ALLOW_THREADS
if ((err != paNoError) && (err != paStreamIsStopped)) {
_cleanup_Stream_object(streamObject);
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", err
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(err
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err),
err));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pa_abort_stream(PyObject *self, PyObject *args)
{
int err;
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetString(PyExc_IOError, "Stream not open");
return NULL;
}
stream = streamObject->stream;
Py_BEGIN_ALLOW_THREADS
err = Pa_AbortStream(stream);
Py_END_ALLOW_THREADS
if ((err != paNoError) && (err != paStreamIsStopped)) {
_cleanup_Stream_object(streamObject);
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", err
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(err
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err),
err));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pa_is_stream_stopped(PyObject *self, PyObject *args)
{
int err;
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
stream = streamObject->stream;
if ((err = Pa_IsStreamStopped(stream)) < 0) {
_cleanup_Stream_object(streamObject);
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", err
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(err
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err),
err));
return NULL;
}
if (err) {
Py_INCREF(Py_True);
return Py_True;
}
Py_INCREF(Py_False);
return Py_False;
}
static PyObject *
pa_is_stream_active(PyObject *self, PyObject *args)
{
int err;
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetString(PyExc_IOError, "Stream not open");
return NULL;
}
stream = streamObject->stream;
if ((err = Pa_IsStreamActive(stream)) < 0) {
_cleanup_Stream_object(streamObject);
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", err
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(err
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err),
err));
return NULL;
}
if (err) {
Py_INCREF(Py_True);
return Py_True;
}
Py_INCREF(Py_False);
return Py_False;
}
static PyObject *
pa_get_stream_time(PyObject *self, PyObject *args)
{
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
stream = streamObject->stream;
if ((time = Pa_GetStreamTime
(stream
)) == 0) { _cleanup_Stream_object(streamObject);
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Internal Error",
paInternalError));
return NULL;
}
return PyFloat_FromDouble
(time); }
static PyObject *
pa_get_stream_cpu_load(PyObject *self, PyObject *args)
{
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
stream = streamObject->stream;
return PyFloat_FromDouble(Pa_GetStreamCpuLoad(stream));
}
/*************************************************************
* Stream Read/Write
*************************************************************/
static PyObject *
pa_write_stream(PyObject *self, PyObject *args)
{
const char *data;
int total_size;
int total_frames;
int err;
int should_throw_exception = 0;
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!s#i|i",
&_pyAudio_StreamType,
&stream_arg,
&data,
&total_size,
&total_frames,
&should_throw_exception))
return NULL;
/* make sure total frames is larger than 0 */
if (total_frames < 0) {
PyErr_SetString(PyExc_ValueError,
"Invalid number of frames");
return NULL;
}
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
stream = streamObject->stream;
Py_BEGIN_ALLOW_THREADS
err = Pa_WriteStream(stream, data, total_frames);
Py_END_ALLOW_THREADS
if (err != paNoError) {
if (err == paOutputUnderflowed) {
if (should_throw_exception)
goto error;
} else
goto error;
}
Py_INCREF(Py_None);
return Py_None;
error:
/* cleanup */
_cleanup_Stream_object(streamObject);
#ifdef VERBOSE
fprintf(stderr
, "An error occured while using the portaudio stream\n"); fprintf(stderr
, "Error number: %d\n", err
); fprintf(stderr
, "Error message: %s\n", Pa_GetErrorText
(err
)); #endif
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err),
err));
return NULL;
}
static PyObject *
pa_read_stream(PyObject *self, PyObject *args)
{
int err;
int total_frames;
short *sampleBlock;
int num_bytes;
PyObject *rv;
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
PaStreamParameters *inputParameters;
if (!PyArg_ParseTuple(args, "O!i",
&_pyAudio_StreamType,
&stream_arg,
&total_frames))
return NULL;
/* make sure value is positive! */
if (total_frames < 0) {
PyErr_SetString(PyExc_ValueError, "Invalid number of frames");
return NULL;
}
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
stream = streamObject->stream;
inputParameters = streamObject->inputParameters;
num_bytes = (total_frames) * (inputParameters->channelCount) *
(Pa_GetSampleSize(inputParameters->sampleFormat));
#ifdef VERBOSE
fprintf(stderr
, "Allocating %d bytes\n", num_bytes
); #endif
rv = PyBytes_FromStringAndSize(NULL, num_bytes);
sampleBlock = (short *) PyBytes_AsString(rv);
if (sampleBlock == NULL) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Out of memory",
paInsufficientMemory));
return NULL;
}
Py_BEGIN_ALLOW_THREADS
err = Pa_ReadStream(stream, sampleBlock, total_frames);
Py_END_ALLOW_THREADS
if (err != paNoError) {
/* ignore input overflow and output underflow */
if (err & paInputOverflowed) {
#ifdef VERBOSE
fprintf(stderr
, "Input Overflow.\n"); #endif
} else if (err & paOutputUnderflowed) {
#ifdef VERBOSE
fprintf(stderr
, "Output Underflow.\n"); #endif
} else {
/* clean up */
_cleanup_Stream_object(streamObject);
}
/* free the string buffer */
Py_XDECREF(rv);
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
Pa_GetErrorText(err), err));
return NULL;
}
return rv;
}
static PyObject *
pa_get_stream_write_available(PyObject *self, PyObject *args)
{
signed long frames;
PyObject *stream_arg;
_pyAudio_Stream *streamObject;
PaStream *stream;
if (!PyArg_ParseTuple(args, "O!", &_pyAudio_StreamType, &stream_arg))
return NULL;
streamObject = (_pyAudio_Stream *) stream_arg;
if (!_is_open(streamObject)) {
PyErr_SetObject(PyExc_IOError,
Py_BuildValue("(s,i)",
"Stream closed",
paBadStreamPtr));
return NULL;
}
stream = streamObject->stream;
frames = Pa_GetStreamWriteAvailable(stream);
return PyLong_FromLong(frames);
}
static PyObject *
pa_get_stream_read_available(PyObject *self, PyObject *args)
{
signed long frames;
LyoqCiAqIFB5QXVkaW86IFB5dGhvbiBCaW5kaW5ncyBmb3IgUG9ydEF1ZGlvLgogKgogKiBDb3B5cmlnaHQgKGMpIDIwMDYtMjAxMiBIdWJlcnQgUGhhbQogKgogKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbgogKiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbgogKiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0CiAqIHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LAogKiBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMKICogb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMKICogZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKICoKICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUKICogaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCiAqCiAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELAogKiBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YKICogTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQKICogTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUwogKiBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4KICogQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4KICogQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRQogKiBTT0ZUV0FSRS4KICovCgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgIlB5dGhvbi5oIgojaW5jbHVkZSAicG9ydGF1ZGlvLmgiCiNpbmNsdWRlICJfcG9ydGF1ZGlvbW9kdWxlLmgiCgoKI2lmZGVmIE1BQ09TWAojaW5jbHVkZSAicGFfbWFjX2NvcmUuaCIKI2VuZGlmCgojZGVmaW5lIERFRkFVTFRfRlJBTUVTX1BFUl9CVUZGRVIgMTAyNAovKiAjZGVmaW5lIFZFUkJPU0UgKi8KCiNkZWZpbmUgbWluKGEsYikgXAogICAoeyBfX3R5cGVvZl9fIChhKSBfYSA9IChhKTsgXAogICAgICAgX190eXBlb2ZfXyAoYikgX2IgPSAoYik7IFwKICAgICBfYSA8IF9iID8gX2EgOiBfYjsgfSkKCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICoKICogVGFibGUgb2YgQ29udGVudHMKICoKICogSS4gRXhwb3J0YWJsZSBQb3J0QXVkaW8gTWV0aG9kIERlZmluaXRpb25zCiAqIElJLiBQeXRob24gT2JqZWN0IFdyYXBwZXJzCiAqICAgICAtIFBhRGV2aWNlSW5mbwogKiAgICAgLSBQYUhvc3RJbmZvCiAqICAgICAtIFBhU3RyZWFtCiAqIElJSS4gUG9ydEF1ZGlvIE1ldGhvZCBJbXBsZW1lbnRhdGlvbnMKICogICAgIC0gSW5pdGlhbGl6YXRpb24vVGVybWluYXRpb24KICogICAgIC0gSG9zdEFQSQogKiAgICAgLSBEZXZpY2VBUEkKICogICAgIC0gU3RyZWFtIE9wZW4vQ2xvc2UKICogICAgIC0gU3RyZWFtIFN0YXJ0L1N0b3AvSW5mbwogKiAgICAgLSBTdHJlYW0gUmVhZC9Xcml0ZQogKiBJVi4gUHl0aG9uIE1vZHVsZSBJbml0CiAqICAgICAtIFBhSG9zdEFwaVR5cGVJZCBlbnVtIGNvbnN0YW50cwogKgogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICoKICogSS4gRXhwb3J0YWJsZSBQeXRob24gTWV0aG9kcwogKgogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKc3RhdGljIFB5TWV0aG9kRGVmIHBhTWV0aG9kc1tdID0gewoKICAvKiB2ZXJzaW9uICovCiAgeyJnZXRfdmVyc2lvbiIsIHBhX2dldF92ZXJzaW9uLCBNRVRIX1ZBUkFSR1MsICJnZXQgdmVyc2lvbiJ9LAogIHsiZ2V0X3ZlcnNpb25fdGV4dCIsIHBhX2dldF92ZXJzaW9uX3RleHQsIE1FVEhfVkFSQVJHUywKICAgImdldCB2ZXJzaW9uIHRleHQifSwKCiAgLyogaW5pdHMgKi8KICB7ImluaXRpYWxpemUiLCBwYV9pbml0aWFsaXplLCBNRVRIX1ZBUkFSR1MsICJpbml0aWFsaXplIHBvcnRhdWRpbyJ9LAogIHsidGVybWluYXRlIiwgcGFfdGVybWluYXRlLCBNRVRIX1ZBUkFSR1MsICJ0ZXJtaW5hdGUgcG9ydGF1ZGlvIn0sCgogIC8qIGhvc3QgYXBpICovCiAgeyJnZXRfaG9zdF9hcGlfY291bnQiLCBwYV9nZXRfaG9zdF9hcGlfY291bnQsIE1FVEhfVkFSQVJHUywKICAgImdldCBob3N0IEFQSSBjb3VudCJ9LAoKICB7ImdldF9kZWZhdWx0X2hvc3RfYXBpIiwgcGFfZ2V0X2RlZmF1bHRfaG9zdF9hcGksIE1FVEhfVkFSQVJHUywKICAgImdldCBkZWZhdWx0IGhvc3QgQVBJIGluZGV4In0sCgogIHsiaG9zdF9hcGlfdHlwZV9pZF90b19ob3N0X2FwaV9pbmRleCIsCiAgIHBhX2hvc3RfYXBpX3R5cGVfaWRfdG9faG9zdF9hcGlfaW5kZXgsIE1FVEhfVkFSQVJHUywKICAgImdldCBkZWZhdWx0IGhvc3QgQVBJIGluZGV4In0sCgogIHsiaG9zdF9hcGlfZGV2aWNlX2luZGV4X3RvX2RldmljZV9pbmRleCIsCiAgIHBhX2hvc3RfYXBpX2RldmljZV9pbmRleF90b19kZXZpY2VfaW5kZXgsCiAgIE1FVEhfVkFSQVJHUywKICAgImdldCBkZWZhdWx0IGhvc3QgQVBJIGluZGV4In0sCgogIHsiZ2V0X2hvc3RfYXBpX2luZm8iLCBwYV9nZXRfaG9zdF9hcGlfaW5mbywgTUVUSF9WQVJBUkdTLAogICAiZ2V0IGhvc3QgYXBpIGluZm9ybWF0aW9uIn0sCgogIC8qIGRldmljZSBhcGkgKi8KICB7ImdldF9kZXZpY2VfY291bnQiLCBwYV9nZXRfZGV2aWNlX2NvdW50LCBNRVRIX1ZBUkFSR1MsCiAgICJnZXQgaG9zdCBBUEkgY291bnQifSwKCiAgeyJnZXRfZGVmYXVsdF9pbnB1dF9kZXZpY2UiLCBwYV9nZXRfZGVmYXVsdF9pbnB1dF9kZXZpY2UsIE1FVEhfVkFSQVJHUywKICAgImdldCBkZWZhdWx0IGlucHV0IGRldmljZSBpbmRleCJ9LAoKICB7ImdldF9kZWZhdWx0X291dHB1dF9kZXZpY2UiLCBwYV9nZXRfZGVmYXVsdF9vdXRwdXRfZGV2aWNlLCBNRVRIX1ZBUkFSR1MsCiAgICJnZXQgZGVmYXVsdCBvdXRwdXQgZGV2aWNlIGluZGV4In0sCgogIHsiZ2V0X2RldmljZV9pbmZvIiwgcGFfZ2V0X2RldmljZV9pbmZvLCBNRVRIX1ZBUkFSR1MsCiAgICJnZXQgZGV2aWNlIGluZm9ybWF0aW9uIn0sCgogIC8qIHN0cmVhbSBvcGVuL2Nsb3NlICovCiAgeyJvcGVuIiwgKFB5Q0Z1bmN0aW9uKSBwYV9vcGVuLCBNRVRIX1ZBUkFSR1MgfCBNRVRIX0tFWVdPUkRTLAogICAib3BlbiBwb3J0IGF1ZGlvIHN0cmVhbSJ9LAogIHsiY2xvc2UiLCBwYV9jbG9zZSwgTUVUSF9WQVJBUkdTLCAiY2xvc2UgcG9ydCBhdWRpbyBzdHJlYW0ifSwKICB7ImdldF9zYW1wbGVfc2l6ZSIsIHBhX2dldF9zYW1wbGVfc2l6ZSwgTUVUSF9WQVJBUkdTLAogICAiZ2V0IHNhbXBsZSBzaXplIG9mIGEgZm9ybWF0IGluIGJ5dGVzIn0sCiAgeyJpc19mb3JtYXRfc3VwcG9ydGVkIiwgKFB5Q0Z1bmN0aW9uKSBwYV9pc19mb3JtYXRfc3VwcG9ydGVkLAogICBNRVRIX1ZBUkFSR1MgfCBNRVRIX0tFWVdPUkRTLAogICAicmV0dXJucyB3aGV0aGVyIHNwZWNpZmllZCBmb3JtYXQgaXMgc3VwcG9ydGVkIn0sCgogIC8qIHN0cmVhbSBzdGFydC9zdG9wICovCiAgeyJzdGFydF9zdHJlYW0iLCBwYV9zdGFydF9zdHJlYW0sIE1FVEhfVkFSQVJHUywgInN0YXJ0cyBwb3J0IGF1ZGlvIHN0cmVhbSJ9LAogIHsic3RvcF9zdHJlYW0iLCBwYV9zdG9wX3N0cmVhbSwgTUVUSF9WQVJBUkdTLCAic3RvcHMgIHBvcnQgYXVkaW8gc3RyZWFtIn0sCiAgeyJhYm9ydF9zdHJlYW0iLCBwYV9hYm9ydF9zdHJlYW0sIE1FVEhfVkFSQVJHUywgImFib3J0cyBwb3J0IGF1ZGlvIHN0cmVhbSJ9LAogIHsiaXNfc3RyZWFtX3N0b3BwZWQiLCBwYV9pc19zdHJlYW1fc3RvcHBlZCwgTUVUSF9WQVJBUkdTLAogICAicmV0dXJucyB3aGV0aGVyIHN0cmVhbSBpcyBzdG9wcGVkIn0sCiAgeyJpc19zdHJlYW1fYWN0aXZlIiwgcGFfaXNfc3RyZWFtX2FjdGl2ZSwgTUVUSF9WQVJBUkdTLAogICAicmV0dXJucyB3aGV0aGVyIHN0cmVhbSBpcyBhY3RpdmUifSwKICB7ImdldF9zdHJlYW1fdGltZSIsIHBhX2dldF9zdHJlYW1fdGltZSwgTUVUSF9WQVJBUkdTLAogICAicmV0dXJucyBzdHJlYW0gdGltZSJ9LAogIHsiZ2V0X3N0cmVhbV9jcHVfbG9hZCIsIHBhX2dldF9zdHJlYW1fY3B1X2xvYWQsIE1FVEhfVkFSQVJHUywKICAgInJldHVybnMgc3RyZWFtIENQVSBsb2FkIC0tIGFsd2F5cyAwIGZvciBibG9ja2luZyBtb2RlIn0sCgogIC8qIHN0cmVhbSByZWFkL3dyaXRlICovCiAgeyJ3cml0ZV9zdHJlYW0iLCBwYV93cml0ZV9zdHJlYW0sIE1FVEhfVkFSQVJHUywgIndyaXRlIHRvIHN0cmVhbSJ9LAogIHsicmVhZF9zdHJlYW0iLCBwYV9yZWFkX3N0cmVhbSwgTUVUSF9WQVJBUkdTLCAicmVhZCBmcm9tIHN0cmVhbSJ9LAoKICB7ImdldF9zdHJlYW1fd3JpdGVfYXZhaWxhYmxlIiwKICAgcGFfZ2V0X3N0cmVhbV93cml0ZV9hdmFpbGFibGUsIE1FVEhfVkFSQVJHUywKICAgImdldCBidWZmZXIgYXZhaWxhYmxlIGZvciB3cml0aW5nIn0sCgogIHsiZ2V0X3N0cmVhbV9yZWFkX2F2YWlsYWJsZSIsCiAgIHBhX2dldF9zdHJlYW1fcmVhZF9hdmFpbGFibGUsIE1FVEhfVkFSQVJHUywKICAgImdldCBidWZmZXIgYXZhaWxhYmxlIGZvciByZWFkaW5nIn0sCgogIHtOVUxMLCBOVUxMLCAwLCBOVUxMfQp9OwoKCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICoKICogSUkuIFB5dGhvbiBPYmplY3QgV3JhcHBlcnMKICoKICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgovKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKiBQYURldmljZUluZm8gVHlwZSA6IFB5dGhvbiBvYmplY3Qgd3JhcHBlciBmb3IgUGFEZXZpY2VJbmZvCiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKdHlwZWRlZiBzdHJ1Y3QgewogIFB5T2JqZWN0X0hFQUQKICBQYURldmljZUluZm8gKmRldkluZm87Cn0gX3B5QXVkaW9fcGFEZXZpY2VJbmZvOwoKCi8qIHNlcGNpZmljIGdldHRlcnMgaW50byB0aGUgUGFEZXZpY2VJbmZvIHN0cnVjdCAqLwoKc3RhdGljIFB5T2JqZWN0ICoKX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2dldF9zdHJ1Y3RWZXJzaW9uKF9weUF1ZGlvX3BhRGV2aWNlSW5mbyAqc2VsZiwKCQkJCQl2b2lkICpjbG9zdXJlKQp7CiAgLyogc2FuaXR5IGNoZWNrICovCiAgaWYgKCFzZWxmLT5kZXZJbmZvKSB7CiAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfQXR0cmlidXRlRXJyb3IsCgkJICAgICJObyBEZXZpY2UgSW5mbyBhdmFpbGFibGUiKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5TG9uZ19Gcm9tTG9uZyhzZWxmLT5kZXZJbmZvLT5zdHJ1Y3RWZXJzaW9uKTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2dldF9uYW1lKF9weUF1ZGlvX3BhRGV2aWNlSW5mbyAqc2VsZiwKCQkJICAgICAgIHZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoKCFzZWxmLT5kZXZJbmZvKSB8fCAoc2VsZi0+ZGV2SW5mby0+bmFtZSA9PSBOVUxMKSkgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0F0dHJpYnV0ZUVycm9yLAoJCSAgICAiTm8gRGV2aWNlIEluZm8gYXZhaWxhYmxlIik7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHJldHVybiBQeUJ5dGVzX0Zyb21TdHJpbmcoc2VsZi0+ZGV2SW5mby0+bmFtZSk7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCl9weUF1ZGlvX3BhRGV2aWNlSW5mb19nZXRfaG9zdEFwaShfcHlBdWRpb19wYURldmljZUluZm8gKnNlbGYsCgkJCQkgIHZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoIXNlbGYtPmRldkluZm8pIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICAgIk5vIERldmljZSBJbmZvIGF2YWlsYWJsZSIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlMb25nX0Zyb21Mb25nKHNlbGYtPmRldkluZm8tPmhvc3RBcGkpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19wYURldmljZUluZm9fZ2V0X21heElucHV0Q2hhbm5lbHMoX3B5QXVkaW9fcGFEZXZpY2VJbmZvICpzZWxmLAoJCQkJCSAgIHZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoIXNlbGYtPmRldkluZm8pIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICAgIk5vIERldmljZSBJbmZvIGF2YWlsYWJsZSIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlMb25nX0Zyb21Mb25nKHNlbGYtPmRldkluZm8tPm1heElucHV0Q2hhbm5lbHMpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19wYURldmljZUluZm9fZ2V0X21heE91dHB1dENoYW5uZWxzKF9weUF1ZGlvX3BhRGV2aWNlSW5mbyAqc2VsZiwKCQkJCQkgICAgdm9pZCAqY2xvc3VyZSkKewogIC8qIHNhbml0eSBjaGVjayAqLwogIGlmICghc2VsZi0+ZGV2SW5mbykgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0F0dHJpYnV0ZUVycm9yLAoJCSAgICAiTm8gRGV2aWNlIEluZm8gYXZhaWxhYmxlIik7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHJldHVybiBQeUxvbmdfRnJvbUxvbmcoc2VsZi0+ZGV2SW5mby0+bWF4T3V0cHV0Q2hhbm5lbHMpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19wYURldmljZUluZm9fZ2V0X2RlZmF1bHRMb3dJbnB1dExhdGVuY3koX3B5QXVkaW9fcGFEZXZpY2VJbmZvICpzZWxmLAoJCQkJCQkgdm9pZCAqY2xvc3VyZSkKewogIC8qIHNhbml0eSBjaGVjayAqLwogIGlmICghc2VsZi0+ZGV2SW5mbykgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0F0dHJpYnV0ZUVycm9yLAoJCSAgICAiTm8gRGV2aWNlIEluZm8gYXZhaWxhYmxlIik7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHJldHVybiBQeUZsb2F0X0Zyb21Eb3VibGUoc2VsZi0+ZGV2SW5mby0+ZGVmYXVsdExvd0lucHV0TGF0ZW5jeSk7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCl9weUF1ZGlvX3BhRGV2aWNlSW5mb19nZXRfZGVmYXVsdExvd091dHB1dExhdGVuY3koX3B5QXVkaW9fcGFEZXZpY2VJbmZvICpzZWxmLAoJCQkJCQkgIHZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoIXNlbGYtPmRldkluZm8pIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICAgIk5vIERldmljZSBJbmZvIGF2YWlsYWJsZSIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlGbG9hdF9Gcm9tRG91YmxlKHNlbGYtPmRldkluZm8tPmRlZmF1bHRMb3dPdXRwdXRMYXRlbmN5KTsKfQoKCnN0YXRpYyBQeU9iamVjdCAqCl9weUF1ZGlvX3BhRGV2aWNlSW5mb19nZXRfZGVmYXVsdEhpZ2hJbnB1dExhdGVuY3koX3B5QXVkaW9fcGFEZXZpY2VJbmZvICpzZWxmLAoJCQkJCQkgIHZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoIXNlbGYtPmRldkluZm8pIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICAgIk5vIERldmljZSBJbmZvIGF2YWlsYWJsZSIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlGbG9hdF9Gcm9tRG91YmxlKHNlbGYtPmRldkluZm8tPmRlZmF1bHRIaWdoSW5wdXRMYXRlbmN5KTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2dldF9kZWZhdWx0SGlnaE91dHB1dExhdGVuY3koX3B5QXVkaW9fcGFEZXZpY2VJbmZvICpzZWxmLAoJCQkJCQkgICB2b2lkICpjbG9zdXJlKQp7CiAgLyogc2FuaXR5IGNoZWNrICovCiAgaWYgKCFzZWxmLT5kZXZJbmZvKSB7CiAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfQXR0cmlidXRlRXJyb3IsCgkJICAgICJObyBEZXZpY2UgSW5mbyBhdmFpbGFibGUiKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5RmxvYXRfRnJvbURvdWJsZShzZWxmLT5kZXZJbmZvLT5kZWZhdWx0SGlnaE91dHB1dExhdGVuY3kpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19wYURldmljZUluZm9fZ2V0X2RlZmF1bHRTYW1wbGVSYXRlKF9weUF1ZGlvX3BhRGV2aWNlSW5mbyAqc2VsZiwKCQkJCQkgICAgdm9pZCAqY2xvc3VyZSkKewogIC8qIHNhbml0eSBjaGVjayAqLwogIGlmICghc2VsZi0+ZGV2SW5mbykgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0F0dHJpYnV0ZUVycm9yLAoJCSAgICAiTm8gRGV2aWNlIEluZm8gYXZhaWxhYmxlIik7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHJldHVybiBQeUZsb2F0X0Zyb21Eb3VibGUoc2VsZi0+ZGV2SW5mby0+ZGVmYXVsdFNhbXBsZVJhdGUpOwp9CgoKCnN0YXRpYyBpbnQKX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2FudGlzZXQoX3B5QXVkaW9fcGFEZXZpY2VJbmZvICpzZWxmLAoJCQkgIFB5T2JqZWN0ICp2YWx1ZSwKCQkJICB2b2lkICpjbG9zdXJlKQp7CiAgLyogcmVhZC1vbmx5OiBkbyBub3QgYWxsb3cgdXNlcnMgdG8gY2hhbmdlIHZhbHVlcyAqLwogIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICJGaWVsZHMgcmVhZC1vbmx5OiBjYW5ub3QgbW9kaWZ5IHZhbHVlcyIpOwogIHJldHVybiAtMTsKfQoKc3RhdGljIFB5R2V0U2V0RGVmIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19nZXRzZXRlcnNbXSA9IHsKICB7Im5hbWUiLAogICAoZ2V0dGVyKSBfcHlBdWRpb19wYURldmljZUluZm9fZ2V0X25hbWUsCiAgIChzZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19hbnRpc2V0LAogICAiZGV2aWNlIG5hbWUiLAogICBOVUxMfSwKCiAgeyJzdHJ1Y3RWZXJzaW9uIiwKICAgKGdldHRlcikgX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2dldF9zdHJ1Y3RWZXJzaW9uLAogICAoc2V0dGVyKSBfcHlBdWRpb19wYURldmljZUluZm9fYW50aXNldCwKICAgInN0cnVjdCB2ZXJzaW9uIiwKICAgTlVMTH0sCgogIHsiaG9zdEFwaSIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19nZXRfaG9zdEFwaSwKICAgKHNldHRlcikgX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2FudGlzZXQsCiAgICJob3N0IGFwaSBpbmRleCIsCiAgIE5VTEx9LAoKICB7Im1heElucHV0Q2hhbm5lbHMiLAogICAoZ2V0dGVyKSBfcHlBdWRpb19wYURldmljZUluZm9fZ2V0X21heElucHV0Q2hhbm5lbHMsCiAgIChzZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19hbnRpc2V0LAogICAibWF4IGlucHV0IGNoYW5uZWxzIiwKICAgTlVMTH0sCgogIHsibWF4T3V0cHV0Q2hhbm5lbHMiLAogICAoZ2V0dGVyKSBfcHlBdWRpb19wYURldmljZUluZm9fZ2V0X21heE91dHB1dENoYW5uZWxzLAogICAoc2V0dGVyKSBfcHlBdWRpb19wYURldmljZUluZm9fYW50aXNldCwKICAgIm1heCBvdXRwdXQgY2hhbm5lbHMiLAogICBOVUxMfSwKCiAgeyJkZWZhdWx0TG93SW5wdXRMYXRlbmN5IiwKICAgKGdldHRlcikgX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2dldF9kZWZhdWx0TG93SW5wdXRMYXRlbmN5LAogICAoc2V0dGVyKSBfcHlBdWRpb19wYURldmljZUluZm9fYW50aXNldCwKICAgImRlZmF1bHQgbG93IGlucHV0IGxhdGVuY3kiLAogICBOVUxMfSwKCiAgeyJkZWZhdWx0TG93T3V0cHV0TGF0ZW5jeSIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19nZXRfZGVmYXVsdExvd091dHB1dExhdGVuY3ksCiAgIChzZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19hbnRpc2V0LAogICAiZGVmYXVsdCBsb3cgb3V0cHV0IGxhdGVuY3kiLAogICBOVUxMfSwKCiAgeyJkZWZhdWx0SGlnaElucHV0TGF0ZW5jeSIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19nZXRfZGVmYXVsdEhpZ2hJbnB1dExhdGVuY3ksCiAgIChzZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19hbnRpc2V0LAogICAiZGVmYXVsdCBoaWdoIGlucHV0IGxhdGVuY3kiLAogICBOVUxMfSwKCiAgeyJkZWZhdWx0SGlnaE91dHB1dExhdGVuY3kiLAogICAoZ2V0dGVyKSBfcHlBdWRpb19wYURldmljZUluZm9fZ2V0X2RlZmF1bHRIaWdoT3V0cHV0TGF0ZW5jeSwKICAgKHNldHRlcikgX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2FudGlzZXQsCiAgICJkZWZhdWx0IGhpZ2ggb3V0cHV0IGxhdGVuY3kiLAogICBOVUxMfSwKCiAgeyJkZWZhdWx0U2FtcGxlUmF0ZSIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19nZXRfZGVmYXVsdFNhbXBsZVJhdGUsCiAgIChzZXR0ZXIpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19hbnRpc2V0LAogICAiZGVmYXVsdCBzYW1wbGUgcmF0ZSIsCiAgIE5VTEx9LAoKICB7TlVMTH0KfTsKCnN0YXRpYyB2b2lkCl9weUF1ZGlvX3BhRGV2aWNlSW5mb19kZWFsbG9jKF9weUF1ZGlvX3BhRGV2aWNlSW5mbyogc2VsZikKewogIC8qIHJlc2V0IHRoZSBwb2ludGVyICovCiAgc2VsZi0+ZGV2SW5mbyA9IE5VTEw7CgogIC8qIGZyZWUgdGhlIG9iamVjdCAqLwogIFB5X1RZUEUoc2VsZiktPnRwX2ZyZWUoKFB5T2JqZWN0Kikgc2VsZik7Cn0KCnN0YXRpYyBQeVR5cGVPYmplY3QgX3B5QXVkaW9fcGFEZXZpY2VJbmZvVHlwZSA9IHsKICAgIFB5VmFyT2JqZWN0X0hFQURfSU5JVChOVUxMLCAwKQogICAgIl9wb3J0YXVkaW8ucGFEZXZpY2VJbmZvIiwgLyp0cF9uYW1lKi8KICAgIHNpemVvZihfcHlBdWRpb19wYURldmljZUluZm8pLCAgIC8qdHBfYmFzaWNzaXplKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfaXRlbXNpemUqLwogICAgKGRlc3RydWN0b3IpIF9weUF1ZGlvX3BhRGV2aWNlSW5mb19kZWFsbG9jLCAvKnRwX2RlYWxsb2MqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9wcmludCovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2dldGF0dHIqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9zZXRhdHRyKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfY29tcGFyZSovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX3JlcHIqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9hc19udW1iZXIqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9hc19zZXF1ZW5jZSovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2FzX21hcHBpbmcqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9oYXNoICovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2NhbGwqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9zdHIqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9nZXRhdHRybyovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX3NldGF0dHJvKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfYXNfYnVmZmVyKi8KICAgIFB5X1RQRkxBR1NfREVGQVVMVCwgICAgICAgIC8qdHBfZmxhZ3MqLwogICAgIlBvcnQgQXVkaW8gRGV2aWNlIEluZm8iLCAgICAgICAvKiB0cF9kb2MgKi8KICAgIDAsICAvKiB0cF90cmF2ZXJzZSAqLwogICAgMCwgIC8qIHRwX2NsZWFyICovCiAgICAwLCAgLyogdHBfcmljaGNvbXBhcmUgKi8KICAgIDAsICAvKiB0cF93ZWFrbGlzdG9mZnNldCAqLwogICAgMCwgIC8qIHRwX2l0ZXIgKi8KICAgIDAsICAvKiB0cF9pdGVybmV4dCAqLwogICAgMCwgIC8qIHRwX21ldGhvZHMgKi8KICAgIDAsICAvKiB0cF9tZW1iZXJzICovCiAgICBfcHlBdWRpb19wYURldmljZUluZm9fZ2V0c2V0ZXJzLCAvKiB0cF9nZXRzZXQgKi8KICAgIDAsICAvKiB0cF9iYXNlICovCiAgICAwLCAgLyogdHBfZGljdCAqLwogICAgMCwgIC8qIHRwX2Rlc2NyX2dldCAqLwogICAgMCwgIC8qIHRwX2Rlc2NyX3NldCAqLwogICAgMCwgIC8qIHRwX2RpY3RvZmZzZXQgKi8KICAgIDAsICAvKiB0cF9pbml0ICovCiAgICAwLCAgLyogdHBfYWxsb2MgKi8KICAgIDAsICAvKiB0cF9uZXcgKi8KfTsKCnN0YXRpYyBfcHlBdWRpb19wYURldmljZUluZm8gKgpfY3JlYXRlX3BhRGV2aWNlSW5mb19vYmplY3Qodm9pZCkKewogIF9weUF1ZGlvX3BhRGV2aWNlSW5mbyAqb2JqOwoKICAvKiBkb24ndCBhbGxvdyBzdWJjbGFzc2luZz8gKi8KICBvYmogPSAoX3B5QXVkaW9fcGFEZXZpY2VJbmZvICopIFB5T2JqZWN0X05ldyhfcHlBdWRpb19wYURldmljZUluZm8sCgkJCQkJICAgICAgICZfcHlBdWRpb19wYURldmljZUluZm9UeXBlKTsKCiAgLyogb2JqID0gKF9weUF1ZGlvX1N0cmVhbSopCiAgICAgX3B5QXVkaW9fU3RyZWFtVHlwZS50cF9hbGxvYygmX3B5QXVkaW9fU3RyZWFtVHlwZSwgMCk7ICovCiAgcmV0dXJuIG9iajsKfQoKCgoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICogUGFIb3N0QXBpIEluZm8gUHl0aG9uIE9iamVjdAogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCnR5cGVkZWYgc3RydWN0IHsKICBQeU9iamVjdF9IRUFECiAgUGFIb3N0QXBpSW5mbyAqYXBpSW5mbzsKfSBfcHlBdWRpb19wYUhvc3RBcGlJbmZvOwoKLyogc2VwY2lmaWMgZ2V0dGVycyBpbnRvIHRoZSBQYURldmljZUluZm8gc3RydWN0ICovCgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2dldF9zdHJ1Y3RWZXJzaW9uKF9weUF1ZGlvX3BhSG9zdEFwaUluZm8gKnNlbGYsCgkJCQkJIHZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoKCFzZWxmLT5hcGlJbmZvKSkgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0F0dHJpYnV0ZUVycm9yLAoJCSAgICAiTm8gSG9zdEFwaSBJbmZvIGF2YWlsYWJsZSIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlMb25nX0Zyb21Mb25nKHNlbGYtPmFwaUluZm8tPnN0cnVjdFZlcnNpb24pOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2dldF90eXBlKF9weUF1ZGlvX3BhSG9zdEFwaUluZm8gKnNlbGYsCgkJCQl2b2lkICpjbG9zdXJlKQp7CiAgLyogc2FuaXR5IGNoZWNrICovCiAgaWYgKCghc2VsZi0+YXBpSW5mbykpIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICAgIk5vIEhvc3RBcGkgSW5mbyBhdmFpbGFibGUiKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5TG9uZ19Gcm9tTG9uZygobG9uZykgc2VsZi0+YXBpSW5mby0+dHlwZSk7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCl9weUF1ZGlvX3BhSG9zdEFwaUluZm9fZ2V0X25hbWUoX3B5QXVkaW9fcGFIb3N0QXBpSW5mbyAqc2VsZiwKCQkJCXZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoKCFzZWxmLT5hcGlJbmZvKSB8fCAoc2VsZi0+YXBpSW5mby0+bmFtZSA9PSBOVUxMKSkgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0F0dHJpYnV0ZUVycm9yLAoJCSAgICAiTm8gSG9zdEFwaSBJbmZvIGF2YWlsYWJsZSIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlVbmljb2RlX0Zyb21TdHJpbmcoc2VsZi0+YXBpSW5mby0+bmFtZSk7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCl9weUF1ZGlvX3BhSG9zdEFwaUluZm9fZ2V0X2RldmljZUNvdW50KF9weUF1ZGlvX3BhSG9zdEFwaUluZm8gKnNlbGYsCgkJCQkgICAgICAgdm9pZCAqY2xvc3VyZSkKewogIC8qIHNhbml0eSBjaGVjayAqLwogIGlmICgoIXNlbGYtPmFwaUluZm8pKSB7CiAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfQXR0cmlidXRlRXJyb3IsCgkJICAgICJObyBIb3N0QXBpIEluZm8gYXZhaWxhYmxlIik7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHJldHVybiBQeUxvbmdfRnJvbUxvbmcoc2VsZi0+YXBpSW5mby0+ZGV2aWNlQ291bnQpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2dldF9kZWZhdWx0SW5wdXREZXZpY2UoX3B5QXVkaW9fcGFIb3N0QXBpSW5mbyAqc2VsZiwKCQkJCQkgICAgICB2b2lkICpjbG9zdXJlKQp7CiAgLyogc2FuaXR5IGNoZWNrICovCiAgaWYgKCghc2VsZi0+YXBpSW5mbykpIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICAgIk5vIEhvc3RBcGkgSW5mbyBhdmFpbGFibGUiKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5TG9uZ19Gcm9tTG9uZyhzZWxmLT5hcGlJbmZvLT5kZWZhdWx0SW5wdXREZXZpY2UpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2dldF9kZWZhdWx0T3V0cHV0RGV2aWNlKF9weUF1ZGlvX3BhSG9zdEFwaUluZm8gKnNlbGYsCgkJCQkJICAgICAgIHZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoKCFzZWxmLT5hcGlJbmZvKSkgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0F0dHJpYnV0ZUVycm9yLAoJCSAgICAiTm8gSG9zdEFwaSBJbmZvIGF2YWlsYWJsZSIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlMb25nX0Zyb21Mb25nKHNlbGYtPmFwaUluZm8tPmRlZmF1bHRPdXRwdXREZXZpY2UpOwp9CgpzdGF0aWMgaW50Cl9weUF1ZGlvX3BhSG9zdEFwaUluZm9fYW50aXNldChfcHlBdWRpb19wYURldmljZUluZm8gKnNlbGYsCgkJCSAgICAgICBQeU9iamVjdCAqdmFsdWUsCgkJCSAgICAgICB2b2lkICpjbG9zdXJlKQp7CiAgLyogcmVhZC1vbmx5OiBkbyBub3QgYWxsb3cgdXNlcnMgdG8gY2hhbmdlIHZhbHVlcyAqLwogIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICJGaWVsZHMgcmVhZC1vbmx5OiBjYW5ub3QgbW9kaWZ5IHZhbHVlcyIpOwogIHJldHVybiAtMTsKfQoKc3RhdGljIHZvaWQKX3B5QXVkaW9fcGFIb3N0QXBpSW5mb19kZWFsbG9jKF9weUF1ZGlvX3BhSG9zdEFwaUluZm8qIHNlbGYpCnsKICAvKiByZXNldCB0aGUgcG9pbnRlciAqLwogIHNlbGYtPmFwaUluZm8gPSBOVUxMOwoKICAvKiBmcmVlIHRoZSBvYmplY3QgKi8KICBQeV9UWVBFKHNlbGYpLT50cF9mcmVlKChQeU9iamVjdCopIHNlbGYpOwp9CgpzdGF0aWMgUHlHZXRTZXREZWYgX3B5QXVkaW9fcGFIb3N0QXBpSW5mb19nZXRzZXRlcnNbXSA9IHsKICB7Im5hbWUiLAogICAoZ2V0dGVyKSBfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2dldF9uYW1lLAogICAoc2V0dGVyKSBfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2FudGlzZXQsCiAgICJob3N0IGFwaSBuYW1lIiwKICAgTlVMTH0sCgogIHsic3RydWN0VmVyc2lvbiIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX3BhSG9zdEFwaUluZm9fZ2V0X3N0cnVjdFZlcnNpb24sCiAgIChzZXR0ZXIpIF9weUF1ZGlvX3BhSG9zdEFwaUluZm9fYW50aXNldCwKICAgInN0cnVjdCB2ZXJzaW9uIiwKICAgTlVMTH0sCgogIHsidHlwZSIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX3BhSG9zdEFwaUluZm9fZ2V0X3R5cGUsCiAgIChzZXR0ZXIpIF9weUF1ZGlvX3BhSG9zdEFwaUluZm9fYW50aXNldCwKICAgImhvc3QgYXBpIHR5cGUiLAogICBOVUxMfSwKCiAgeyJkZXZpY2VDb3VudCIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX3BhSG9zdEFwaUluZm9fZ2V0X2RldmljZUNvdW50LAogICAoc2V0dGVyKSBfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2FudGlzZXQsCiAgICJudW1iZXIgb2YgZGV2aWNlcyIsCiAgIE5VTEx9LAoKICB7ImRlZmF1bHRJbnB1dERldmljZSIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX3BhSG9zdEFwaUluZm9fZ2V0X2RlZmF1bHRJbnB1dERldmljZSwKICAgKHNldHRlcikgX3B5QXVkaW9fcGFIb3N0QXBpSW5mb19hbnRpc2V0LAogICAiZGVmYXVsdCBpbnB1dCBkZXZpY2UgaW5kZXgiLAogICBOVUxMfSwKCiAgeyJkZWZhdWx0T3V0cHV0RGV2aWNlIiwKICAgKGdldHRlcikgX3B5QXVkaW9fcGFIb3N0QXBpSW5mb19nZXRfZGVmYXVsdE91dHB1dERldmljZSwKICAgKHNldHRlcikgX3B5QXVkaW9fcGFEZXZpY2VJbmZvX2FudGlzZXQsCiAgICJkZWZhdWx0IG91dHB1dCBkZXZpY2UgaW5kZXgiLAogICBOVUxMfSwKCiAge05VTEx9Cn07CgpzdGF0aWMgUHlUeXBlT2JqZWN0IF9weUF1ZGlvX3BhSG9zdEFwaUluZm9UeXBlID0gewogICAgUHlWYXJPYmplY3RfSEVBRF9JTklUKE5VTEwsIDApCiAgICAiX3BvcnRhdWRpby5wYUhvc3RBcGlJbmZvIiwgLyp0cF9uYW1lKi8KICAgIHNpemVvZihfcHlBdWRpb19wYUhvc3RBcGlJbmZvKSwgICAvKnRwX2Jhc2ljc2l6ZSovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2l0ZW1zaXplKi8KICAgIChkZXN0cnVjdG9yKSBfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2RlYWxsb2MsIC8qdHBfZGVhbGxvYyovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX3ByaW50Ki8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfZ2V0YXR0ciovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX3NldGF0dHIqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9jb21wYXJlKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfcmVwciovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2FzX251bWJlciovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2FzX3NlcXVlbmNlKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfYXNfbWFwcGluZyovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2hhc2ggKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfY2FsbCovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX3N0ciovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2dldGF0dHJvKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfc2V0YXR0cm8qLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9hc19idWZmZXIqLwogICAgUHlfVFBGTEFHU19ERUZBVUxULCAgICAgICAgLyp0cF9mbGFncyovCiAgICAiUG9ydCBBdWRpbyBIb3N0QXBpIEluZm8iLCAgICAgICAvKiB0cF9kb2MgKi8KICAgIDAsICAvKiB0cF90cmF2ZXJzZSAqLwogICAgMCwgIC8qIHRwX2NsZWFyICovCiAgICAwLCAgLyogdHBfcmljaGNvbXBhcmUgKi8KICAgIDAsICAvKiB0cF93ZWFrbGlzdG9mZnNldCAqLwogICAgMCwgIC8qIHRwX2l0ZXIgKi8KICAgIDAsICAvKiB0cF9pdGVybmV4dCAqLwogICAgMCwgIC8qIHRwX21ldGhvZHMgKi8KICAgIDAsICAvKiB0cF9tZW1iZXJzICovCiAgICBfcHlBdWRpb19wYUhvc3RBcGlJbmZvX2dldHNldGVycywgLyogdHBfZ2V0c2V0ICovCiAgICAwLCAgLyogdHBfYmFzZSAqLwogICAgMCwgIC8qIHRwX2RpY3QgKi8KICAgIDAsICAvKiB0cF9kZXNjcl9nZXQgKi8KICAgIDAsICAvKiB0cF9kZXNjcl9zZXQgKi8KICAgIDAsICAvKiB0cF9kaWN0b2Zmc2V0ICovCiAgICAwLCAgLyogdHBfaW5pdCAqLwogICAgMCwgIC8qIHRwX2FsbG9jICovCiAgICAwLCAgLyogdHBfbmV3ICovCn07CgpzdGF0aWMgX3B5QXVkaW9fcGFIb3N0QXBpSW5mbyAqCl9jcmVhdGVfcGFIb3N0QXBpSW5mb19vYmplY3Qodm9pZCkKewogIF9weUF1ZGlvX3BhSG9zdEFwaUluZm8gKm9iajsKCiAgLyogZG9uJ3QgYWxsb3cgc3ViY2xhc3Npbmc/ICovCiAgb2JqID0gKF9weUF1ZGlvX3BhSG9zdEFwaUluZm8gKikgUHlPYmplY3RfTmV3KF9weUF1ZGlvX3BhSG9zdEFwaUluZm8sCgkJCQkJCSZfcHlBdWRpb19wYUhvc3RBcGlJbmZvVHlwZSk7CiAgcmV0dXJuIG9iajsKfQoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICogSG9zdC1TcGVjaWZpYyBPYmplY3RzCiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICogLS0+IE1hYyBPUyBYCiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKI2lmZGVmIE1BQ09TWAp0eXBlZGVmIHN0cnVjdCB7CiAgUHlPYmplY3RfSEVBRAogIFBhTWFjQ29yZVN0cmVhbUluZm8gKnBhTWFjQ29yZVN0cmVhbUluZm87CiAgaW50IGZsYWdzOwogIFNJbnQzMiAqY2hhbm5lbE1hcDsKICBpbnQgY2hhbm5lbE1hcFNpemU7Cn0gX3B5QXVkaW9fTWFjT1NYX2hvc3RBcGlTcGVjaWZpY1N0cmVhbUluZm87Cgp0eXBlZGVmIF9weUF1ZGlvX01hY09TWF9ob3N0QXBpU3BlY2lmaWNTdHJlYW1JbmZvIF9weUF1ZGlvX01hY19IQVNTSTsKCnN0YXRpYyB2b2lkCl9weUF1ZGlvX01hY09TWF9ob3N0QXBpU3BlY2lmaWNTdHJlYW1JbmZvX2NsZWFudXAoX3B5QXVkaW9fTWFjX0hBU1NJICpzZWxmKQp7CiAgaWYgKHNlbGYtPnBhTWFjQ29yZVN0cmVhbUluZm8gIT0gTlVMTCkgewogICAgZnJlZShzZWxmLT5wYU1hY0NvcmVTdHJlYW1JbmZvKTsKICAgIHNlbGYtPnBhTWFjQ29yZVN0cmVhbUluZm8gPSBOVUxMOwogIH0KCiAgaWYgKHNlbGYtPmNoYW5uZWxNYXAgIT0gTlVMTCkgewogICAgZnJlZShzZWxmLT5jaGFubmVsTWFwKTsKICAgIHNlbGYtPmNoYW5uZWxNYXAgPSBOVUxMOwogIH0KCiAgc2VsZi0+ZmxhZ3MgPSBwYU1hY0NvcmVQbGF5TmljZTsKICBzZWxmLT5jaGFubmVsTWFwU2l6ZSA9IDA7Cn0KCnN0YXRpYyB2b2lkCl9weUF1ZGlvX01hY09TWF9ob3N0QXBpU3BlY2lmaWNTdHJlYW1JbmZvX2RlYWxsb2MoX3B5QXVkaW9fTWFjX0hBU1NJICpzZWxmKQp7CiAgX3B5QXVkaW9fTWFjT1NYX2hvc3RBcGlTcGVjaWZpY1N0cmVhbUluZm9fY2xlYW51cChzZWxmKTsKICBQeV9UWVBFKHNlbGYpLT50cF9mcmVlKChQeU9iamVjdCAqKSBzZWxmKTsKfQoKc3RhdGljIGludApfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19pbml0KFB5T2JqZWN0ICpfc2VsZiwKCQkJCQkgICAgICAgUHlPYmplY3QgKmFyZ3MsCgkJCQkJICAgICAgIFB5T2JqZWN0ICprd2FyZ3MpCnsKICBfcHlBdWRpb19NYWNfSEFTU0kgKnNlbGYgPSAoX3B5QXVkaW9fTWFjX0hBU1NJICopIF9zZWxmOwogIFB5T2JqZWN0ICpjaGFubmVsX21hcCA9IE5VTEw7CiAgaW50IGZsYWdzID0gcGFNYWNDb3JlUGxheU5pY2U7CgogIHN0YXRpYyBjaGFyICprd2xpc3RbXSA9IHsiZmxhZ3MiLCAiY2hhbm5lbF9tYXAiLCBOVUxMfTsKCiAgaWYgKCEgUHlBcmdfUGFyc2VUdXBsZUFuZEtleXdvcmRzKGFyZ3MsIGt3YXJncywgInxpTyIsIGt3bGlzdCwKCQkJCSAgICAmZmxhZ3MsICZjaGFubmVsX21hcCkpIHsKICAgIHJldHVybiAtMTsKICB9CgogIC8vIGNsZWFudXAgKGp1c3QgaW4gY2FzZSkKICBfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19jbGVhbnVwKHNlbGYpOwoKICBpZiAoY2hhbm5lbF9tYXAgIT0gTlVMTCkgewogICAgLy8gZW5zdXJlIGNoYW5uZWxfbWFwIGlzIGFuIGFycmF5CiAgICBpZiAoISBQeVR1cGxlX0NoZWNrKGNoYW5uZWxfbWFwKSkgewogICAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfVmFsdWVFcnJvciwgIkNoYW5uZWwgbWFwIG11c3QgYmUgYSB0dXBsZSIpOwogICAgICByZXR1cm4gLTE7CiAgICB9CgogICAgLy8gZ2VuZXJhdGUgU0ludDMyIGNoYW5uZWxNYXAKICAgIHNlbGYtPmNoYW5uZWxNYXBTaXplID0gKGludCkgUHlUdXBsZV9TaXplKGNoYW5uZWxfbWFwKTsKCiAgICBzZWxmLT5jaGFubmVsTWFwID0gKFNJbnQzMiAqKSBtYWxsb2Moc2l6ZW9mKFNJbnQzMikgKiBzZWxmLT5jaGFubmVsTWFwU2l6ZSk7CgogICAgaWYgKHNlbGYtPmNoYW5uZWxNYXAgPT0gTlVMTCkgewogICAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfU3lzdGVtRXJyb3IsICJPdXQgb2YgbWVtb3J5Iik7CiAgICAgIF9weUF1ZGlvX01hY09TWF9ob3N0QXBpU3BlY2lmaWNTdHJlYW1JbmZvX2NsZWFudXAoc2VsZik7CiAgICAgIHJldHVybiAtMTsKICAgIH0KCiAgICBQeU9iamVjdCAqZWxlbWVudDsKICAgIGludCBpOwogICAgZm9yIChpID0gMDsgaSA8IHNlbGYtPmNoYW5uZWxNYXBTaXplOyArK2kpIHsKICAgICAgZWxlbWVudCA9IFB5VHVwbGVfR2V0SXRlbShjaGFubmVsX21hcCwgaSk7CiAgICAgIGlmIChlbGVtZW50ID09IE5VTEwpIHsKCS8vIGVycm9yIGNvbmRpdGlvbgoJUHlFcnJfU2V0U3RyaW5nKFB5RXhjX1ZhbHVlRXJyb3IsCgkJCSJJbnRlcm5hbCBlcnJvcjogb3V0IG9mIGJvdW5kcyBpbmRleCIpOwoJX3B5QXVkaW9fTWFjT1NYX2hvc3RBcGlTcGVjaWZpY1N0cmVhbUluZm9fY2xlYW51cChzZWxmKTsKCXJldHVybiAtMTsKICAgICAgfQoKICAgICAgLy8gbWFrZSBzdXJlIGVsZW1lbnQgaXMgYW4gaW50ZWdlcgogICAgICBpZiAoIVB5TnVtYmVyX0NoZWNrKGVsZW1lbnQpKSB7CglQeUVycl9TZXRTdHJpbmcoUHlFeGNfVmFsdWVFcnJvciwKCQkJIkNoYW5uZWwgTWFwIG11c3QgY29uc2lzdCBvZiBpbnRlZ2VyIGVsZW1lbnRzIik7CglfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19jbGVhbnVwKHNlbGYpOwoJcmV0dXJuIC0xOwogICAgICB9CgogICAgICBQeU9iamVjdCAqbG9uZ19lbGVtZW50ID0gUHlOdW1iZXJfTG9uZyhlbGVtZW50KTsKCiAgICAgIC8vIE9LLCBsb29rcyBnb29kCiAgICAgIHNlbGYtPmNoYW5uZWxNYXBbaV0gPSAoU0ludDMyKSBQeUxvbmdfQXNMb25nKGxvbmdfZWxlbWVudCk7CiAgICAgIFB5X0RFQ1JFRihsb25nX2VsZW1lbnQpOwogICAgfQogIH0KCiAgLy8gbWFsbG9jIHNlbGYtPnBhTWFjQ29yZVN0cmVhbUluZm8KICBzZWxmLT5wYU1hY0NvcmVTdHJlYW1JbmZvID0KICAgICAgKFBhTWFjQ29yZVN0cmVhbUluZm8gKikgbWFsbG9jKHNpemVvZihQYU1hY0NvcmVTdHJlYW1JbmZvKSk7CgogIGlmIChzZWxmLT5wYU1hY0NvcmVTdHJlYW1JbmZvID09IE5VTEwpIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19TeXN0ZW1FcnJvciwgIk91dCBvZiBtZW1lb3J5Iik7CiAgICBfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19jbGVhbnVwKHNlbGYpOwogICAgcmV0dXJuIC0xOwogIH0KCiAgUGFNYWNDb3JlX1NldHVwU3RyZWFtSW5mbyhzZWxmLT5wYU1hY0NvcmVTdHJlYW1JbmZvLCBmbGFncyk7CgogIGlmIChzZWxmLT5jaGFubmVsTWFwKSB7CiAgICBQYU1hY0NvcmVfU2V0dXBDaGFubmVsTWFwKHNlbGYtPnBhTWFjQ29yZVN0cmVhbUluZm8sCgkJCSAgICAgIHNlbGYtPmNoYW5uZWxNYXAsCgkJCSAgICAgIHNlbGYtPmNoYW5uZWxNYXBTaXplKTsKICB9CgogIHNlbGYtPmZsYWdzID0gZmxhZ3M7CgogIHJldHVybiAwOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19nZXRfZmxhZ3MoX3B5QXVkaW9fTWFjX0hBU1NJICpzZWxmLAoJCQkJCQkgICAgdm9pZCAqY2xvc3VyZSkKewogIHJldHVybiBQeUxvbmdfRnJvbUxvbmcoc2VsZi0+ZmxhZ3MpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19nZXRfY2hhbm5lbF9tYXAoCgkgICAgICAgIF9weUF1ZGlvX01hY19IQVNTSSAqc2VsZiwKCQl2b2lkICpjbG9zdXJlKQp7CiAgaWYgKHNlbGYtPmNoYW5uZWxNYXAgPT0gTlVMTCB8fCBzZWxmLT5jaGFubmVsTWFwU2l6ZSA9PSAwKSB7CiAgICBQeV9JTkNSRUYoUHlfTm9uZSk7CiAgICByZXR1cm4gUHlfTm9uZTsKICB9CgogIGludCBpOwogIFB5T2JqZWN0ICpjaGFubmVsTWFwVHVwbGUgPSBQeVR1cGxlX05ldyhzZWxmLT5jaGFubmVsTWFwU2l6ZSk7CiAgZm9yIChpID0gMDsgaSA8IHNlbGYtPmNoYW5uZWxNYXBTaXplOyArK2kpIHsKICAgIFB5T2JqZWN0ICplbGVtZW50ID0gUHlMb25nX0Zyb21Mb25nKHNlbGYtPmNoYW5uZWxNYXBbaV0pOwogICAgaWYgKCFlbGVtZW50KSB7CiAgICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19TeXN0ZW1FcnJvciwgIkludmFsaWQgY2hhbm5lbCBtYXAiKTsKICAgICAgcmV0dXJuIE5VTEw7CiAgICB9CgogICAgaWYgKFB5VHVwbGVfU2V0SXRlbShjaGFubmVsTWFwVHVwbGUsCgkJCWksCgkJCVB5TG9uZ19Gcm9tTG9uZyhzZWxmLT5jaGFubmVsTWFwW2ldKSkpIHsKICAgICAgLy8gbm9uLXplcm8gb24gZXJyb3IKICAgICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX1N5c3RlbUVycm9yLCAiQ2FuJ3QgY3JlYXRlIGNoYW5uZWwgbWFwLiIpOwogICAgICByZXR1cm4gTlVMTDsKICAgIH0KICB9CiAgcmV0dXJuIGNoYW5uZWxNYXBUdXBsZTsKfQoKc3RhdGljIGludApfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19hbnRpc2V0KF9weUF1ZGlvX01hY19IQVNTSSAqc2VsZiwKCQkJCQkJICBQeU9iamVjdCAqdmFsdWUsCgkJCQkJCSAgdm9pZCAqY2xvc3VyZSkKewogIC8qIHJlYWQtb25seTogZG8gbm90IGFsbG93IHVzZXJzIHRvIGNoYW5nZSB2YWx1ZXMgKi8KICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfQXR0cmlidXRlRXJyb3IsCgkJICAiRmllbGRzIHJlYWQtb25seTogY2Fubm90IG1vZGlmeSB2YWx1ZXMiKTsKICByZXR1cm4gLTE7Cn0KCnN0YXRpYyBQeUdldFNldERlZiBfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19nZXRzZXRlcnNbXSA9IHsKICB7ImZsYWdzIiwKICAgKGdldHRlcikgX3B5QXVkaW9fTWFjT1NYX2hvc3RBcGlTcGVjaWZpY1N0cmVhbUluZm9fZ2V0X2ZsYWdzLAogICAoc2V0dGVyKSBfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19hbnRpc2V0LAogICAiZmxhZ3MiLAogICBOVUxMfSwKCiAgeyJjaGFubmVsX21hcCIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX01hY09TWF9ob3N0QXBpU3BlY2lmaWNTdHJlYW1JbmZvX2dldF9jaGFubmVsX21hcCwKICAgKHNldHRlcikgX3B5QXVkaW9fTWFjT1NYX2hvc3RBcGlTcGVjaWZpY1N0cmVhbUluZm9fYW50aXNldCwKICAgImNoYW5uZWwgbWFwIiwKICAgTlVMTH0sCgogIHtOVUxMfQp9OwoKc3RhdGljIFB5VHlwZU9iamVjdCBfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb1R5cGUgPSB7CiAgICBQeVZhck9iamVjdF9IRUFEX0lOSVQoTlVMTCwgMCkKICAgICJfcG9ydGF1ZGlvLlBhTWFjQ29yZVN0cmVhbUluZm8iLCAvKnRwX25hbWUqLwogICAgc2l6ZW9mKF9weUF1ZGlvX01hY09TWF9ob3N0QXBpU3BlY2lmaWNTdHJlYW1JbmZvKSwgICAvKnRwX2Jhc2ljc2l6ZSovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2l0ZW1zaXplKi8KICAgIC8qdHBfZGVhbGxvYyovCiAgICAoZGVzdHJ1Y3RvcikgX3B5QXVkaW9fTWFjT1NYX2hvc3RBcGlTcGVjaWZpY1N0cmVhbUluZm9fZGVhbGxvYywKICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfcHJpbnQqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9nZXRhdHRyKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfc2V0YXR0ciovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2NvbXBhcmUqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9yZXByKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfYXNfbnVtYmVyKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfYXNfc2VxdWVuY2UqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9hc19tYXBwaW5nKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfaGFzaCAqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9jYWxsKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfc3RyKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfZ2V0YXR0cm8qLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9zZXRhdHRybyovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2FzX2J1ZmZlciovCiAgICBQeV9UUEZMQUdTX0RFRkFVTFQsICAgICAgICAvKnRwX2ZsYWdzKi8KICAgICJNYWMgT1MgWCBTcGVjaWZpYyBIb3N0QVBJIGNvbmZpZ3VyYXRpb24iLCAgICAgICAvKiB0cF9kb2MgKi8KICAgIDAsICAvKiB0cF90cmF2ZXJzZSAqLwogICAgMCwgIC8qIHRwX2NsZWFyICovCiAgICAwLCAgLyogdHBfcmljaGNvbXBhcmUgKi8KICAgIDAsICAvKiB0cF93ZWFrbGlzdG9mZnNldCAqLwogICAgMCwgIC8qIHRwX2l0ZXIgKi8KICAgIDAsICAvKiB0cF9pdGVybmV4dCAqLwogICAgMCwgIC8qIHRwX21ldGhvZHMgKi8KICAgIDAsICAvKiB0cF9tZW1iZXJzICovCiAgICBfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb19nZXRzZXRlcnMsICAvKiB0cF9nZXRzZXQgKi8KICAgIDAsICAvKiB0cF9iYXNlICovCiAgICAwLCAgLyogdHBfZGljdCAqLwogICAgMCwgIC8qIHRwX2Rlc2NyX2dldCAqLwogICAgMCwgIC8qIHRwX2Rlc2NyX3NldCAqLwogICAgMCwgIC8qIHRwX2RpY3RvZmZzZXQgKi8KICAgIChpbnQgKCopKFB5T2JqZWN0KiwgUHlPYmplY3QqLCBQeU9iamVjdCopKV9weUF1ZGlvX01hY09TWF9ob3N0QXBpU3BlY2lmaWNTdHJlYW1JbmZvX2luaXQsICAvKiB0cF9pbml0ICovCiAgICAwLCAgLyogdHBfYWxsb2MgKi8KICAgIDAsICAvKiB0cF9uZXcgKi8KfTsKI2VuZGlmCgoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICogU3RyZWFtIFdyYXBwZXIgUHl0aG9uIE9iamVjdAogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCnR5cGVkZWYgc3RydWN0IHsKICBQeU9iamVjdCAqY2FsbGJhY2s7CiAgbG9uZyBtYWluX3RocmVhZF9pZDsKICB1bnNpZ25lZCBpbnQgZnJhbWVfc2l6ZTsKfSBQeUF1ZGlvQ2FsbGJhY2tDb250ZXh0OwoKdHlwZWRlZiBzdHJ1Y3QgewogIFB5T2JqZWN0X0hFQUQKICBQYVN0cmVhbSAqc3RyZWFtOwogIFBhU3RyZWFtUGFyYW1ldGVycyAqaW5wdXRQYXJhbWV0ZXJzOwogIFBhU3RyZWFtUGFyYW1ldGVycyAqb3V0cHV0UGFyYW1ldGVyczsKCiAgLyogaW5jbHVkZSBQYVN0cmVhbUluZm8gdG9vISAqLwogIFBhU3RyZWFtSW5mbyAqc3RyZWFtSW5mbzsKCiAgLyogY29udGV4dCBmb3IgY2FsbGJhY2sgKi8KICBQeUF1ZGlvQ2FsbGJhY2tDb250ZXh0ICpjYWxsYmFja0NvbnRleHQ7CgogIGludCBpc19vcGVuOwp9IF9weUF1ZGlvX1N0cmVhbTsKCnN0YXRpYyBpbnQKX2lzX29wZW4oX3B5QXVkaW9fU3RyZWFtICpvYmopIHsKICByZXR1cm4gKG9iaikgJiYgKG9iai0+aXNfb3Blbik7Cn0KCnN0YXRpYyB2b2lkCl9jbGVhbnVwX1N0cmVhbV9vYmplY3QoX3B5QXVkaW9fU3RyZWFtICpzdHJlYW1PYmplY3QpCnsKICBpZiAoc3RyZWFtT2JqZWN0LT5zdHJlYW0gIT0gTlVMTCkgewogICAgUHlfQkVHSU5fQUxMT1dfVEhSRUFEUwogICAgUGFfQ2xvc2VTdHJlYW0oc3RyZWFtT2JqZWN0LT5zdHJlYW0pOwogICAgUHlfRU5EX0FMTE9XX1RIUkVBRFMKICAgIHN0cmVhbU9iamVjdC0+c3RyZWFtID0gTlVMTDsKICB9CgogIGlmIChzdHJlYW1PYmplY3QtPnN0cmVhbUluZm8pCiAgICBzdHJlYW1PYmplY3QtPnN0cmVhbUluZm8gPSBOVUxMOwoKICBpZiAoc3RyZWFtT2JqZWN0LT5pbnB1dFBhcmFtZXRlcnMgIT0gTlVMTCkgewogICAgZnJlZShzdHJlYW1PYmplY3QtPmlucHV0UGFyYW1ldGVycyk7CiAgICBzdHJlYW1PYmplY3QtPmlucHV0UGFyYW1ldGVycyA9IE5VTEw7CiAgfQoKICBpZiAoc3RyZWFtT2JqZWN0LT5vdXRwdXRQYXJhbWV0ZXJzICE9IE5VTEwpIHsKICAgIGZyZWUoc3RyZWFtT2JqZWN0LT5vdXRwdXRQYXJhbWV0ZXJzKTsKICAgIHN0cmVhbU9iamVjdC0+b3V0cHV0UGFyYW1ldGVycyA9IE5VTEw7CiAgfQoKICBpZiAoc3RyZWFtT2JqZWN0LT5jYWxsYmFja0NvbnRleHQgIT0gTlVMTCkgewogICAgUHlfWERFQ1JFRihzdHJlYW1PYmplY3QtPmNhbGxiYWNrQ29udGV4dC0+Y2FsbGJhY2spOwogICAgZnJlZShzdHJlYW1PYmplY3QtPmNhbGxiYWNrQ29udGV4dCk7CiAgICBzdHJlYW1PYmplY3QtPmNhbGxiYWNrQ29udGV4dCA9IE5VTEw7CiAgfQoKICAvKiBkZXNpZ25hdGUgdGhlIHN0cmVhbSBhcyBjbG9zZWQgKi8KICBzdHJlYW1PYmplY3QtPmlzX29wZW4gPSAwOwp9CgpzdGF0aWMgdm9pZApfcHlBdWRpb19TdHJlYW1fZGVhbGxvYyhfcHlBdWRpb19TdHJlYW0qIHNlbGYpCnsKICAvKiBkZWFsbG9jYXRlIG1lbW9yeSBpZiBuZWNlc3NhcnkgKi8KICBfY2xlYW51cF9TdHJlYW1fb2JqZWN0KHNlbGYpOwoKICAvKiBmcmVlIHRoZSBvYmplY3QgKi8KICBQeV9UWVBFKHNlbGYpLT50cF9mcmVlKChQeU9iamVjdCopIHNlbGYpOwp9CgoKc3RhdGljIFB5T2JqZWN0ICoKX3B5QXVkaW9fU3RyZWFtX2dldF9zdHJ1Y3RWZXJzaW9uKF9weUF1ZGlvX1N0cmVhbSAqc2VsZiwKCQkJCSAgdm9pZCAqY2xvc3VyZSkKewogIC8qIHNhbml0eSBjaGVjayAqLwogIGlmICghX2lzX29wZW4oc2VsZikpIHsKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19JT0Vycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgICJTdHJlYW0gY2xvc2VkIiwKCQkJCSAgcGFCYWRTdHJlYW1QdHIpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgaWYgKCghc2VsZi0+c3RyZWFtSW5mbykpIHsKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19JT0Vycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgICJObyBTdHJlYW1JbmZvIGF2YWlsYWJsZSIsCgkJCQkgIHBhQmFkU3RyZWFtUHRyKSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHJldHVybiBQeUxvbmdfRnJvbUxvbmcoc2VsZi0+c3RyZWFtSW5mby0+c3RydWN0VmVyc2lvbik7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCl9weUF1ZGlvX1N0cmVhbV9nZXRfaW5wdXRMYXRlbmN5KF9weUF1ZGlvX1N0cmVhbSAqc2VsZiwKCQkJCSB2b2lkICpjbG9zdXJlKQp7CiAgLyogc2FuaXR5IGNoZWNrICovCiAgaWYgKCFfaXNfb3BlbihzZWxmKSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIlN0cmVhbSBjbG9zZWQiLAoJCQkJICBwYUJhZFN0cmVhbVB0cikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoKCFzZWxmLT5zdHJlYW1JbmZvKSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIk5vIFN0cmVhbUluZm8gYXZhaWxhYmxlIiwKCQkJCSAgcGFCYWRTdHJlYW1QdHIpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5RmxvYXRfRnJvbURvdWJsZShzZWxmLT5zdHJlYW1JbmZvLT5pbnB1dExhdGVuY3kpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpfcHlBdWRpb19TdHJlYW1fZ2V0X291dHB1dExhdGVuY3koX3B5QXVkaW9fU3RyZWFtICpzZWxmLAoJCQkJICB2b2lkICpjbG9zdXJlKQp7CiAgLyogc2FuaXR5IGNoZWNrICovCiAgaWYgKCFfaXNfb3BlbihzZWxmKSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIlN0cmVhbSBjbG9zZWQiLAoJCQkJICBwYUJhZFN0cmVhbVB0cikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoKCFzZWxmLT5zdHJlYW1JbmZvKSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIk5vIFN0cmVhbUluZm8gYXZhaWxhYmxlIiwKCQkJCSAgcGFCYWRTdHJlYW1QdHIpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5RmxvYXRfRnJvbURvdWJsZShzZWxmLT5zdHJlYW1JbmZvLT5vdXRwdXRMYXRlbmN5KTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKX3B5QXVkaW9fU3RyZWFtX2dldF9zYW1wbGVSYXRlKF9weUF1ZGlvX1N0cmVhbSAqc2VsZiwKCQkJICAgICAgIHZvaWQgKmNsb3N1cmUpCnsKICAvKiBzYW5pdHkgY2hlY2sgKi8KICBpZiAoIV9pc19vcGVuKHNlbGYpKSB7CiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICAiU3RyZWFtIGNsb3NlZCIsCgkJCQkgIHBhQmFkU3RyZWFtUHRyKSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIC8qIHNhbml0eSBjaGVjayAqLwogIGlmICgoIXNlbGYtPnN0cmVhbUluZm8pKSB7CiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICAiTm8gU3RyZWFtSW5mbyBhdmFpbGFibGUiLAoJCQkJICBwYUJhZFN0cmVhbVB0cikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlGbG9hdF9Gcm9tRG91YmxlKHNlbGYtPnN0cmVhbUluZm8tPnNhbXBsZVJhdGUpOwp9CgpzdGF0aWMgaW50Cl9weUF1ZGlvX1N0cmVhbV9hbnRpc2V0KF9weUF1ZGlvX1N0cmVhbSAqc2VsZiwKCQkJUHlPYmplY3QgKnZhbHVlLAoJCQl2b2lkICpjbG9zdXJlKQp7CiAgLyogcmVhZC1vbmx5OiBkbyBub3QgYWxsb3cgdXNlcnMgdG8gY2hhbmdlIHZhbHVlcyAqLwogIFB5RXJyX1NldFN0cmluZyhQeUV4Y19BdHRyaWJ1dGVFcnJvciwKCQkgICJGaWVsZHMgcmVhZC1vbmx5OiBjYW5ub3QgbW9kaWZ5IHZhbHVlcyIpOwogIHJldHVybiAtMTsKfQoKc3RhdGljIFB5R2V0U2V0RGVmIF9weUF1ZGlvX1N0cmVhbV9nZXRzZXRlcnNbXSA9IHsKICB7InN0cnVjdFZlcnNpb24iLAogICAoZ2V0dGVyKSBfcHlBdWRpb19TdHJlYW1fZ2V0X3N0cnVjdFZlcnNpb24sCiAgIChzZXR0ZXIpIF9weUF1ZGlvX1N0cmVhbV9hbnRpc2V0LAogICAic3RydWN0IHZlcnNpb24iLAogICBOVUxMfSwKCiAgeyJpbnB1dExhdGVuY3kiLAogICAoZ2V0dGVyKSBfcHlBdWRpb19TdHJlYW1fZ2V0X2lucHV0TGF0ZW5jeSwKICAgKHNldHRlcikgX3B5QXVkaW9fU3RyZWFtX2FudGlzZXQsCiAgICJpbnB1dCBsYXRlbmN5IiwKICAgTlVMTH0sCgogIHsib3V0cHV0TGF0ZW5jeSIsCiAgIChnZXR0ZXIpIF9weUF1ZGlvX1N0cmVhbV9nZXRfb3V0cHV0TGF0ZW5jeSwKICAgKHNldHRlcikgX3B5QXVkaW9fU3RyZWFtX2FudGlzZXQsCiAgICJvdXRwdXQgbGF0ZW5jeSIsCiAgIE5VTEx9LAoKICB7InNhbXBsZVJhdGUiLAogICAoZ2V0dGVyKSBfcHlBdWRpb19TdHJlYW1fZ2V0X3NhbXBsZVJhdGUsCiAgIChzZXR0ZXIpIF9weUF1ZGlvX1N0cmVhbV9hbnRpc2V0LAogICAic2FtcGxlIHJhdGUiLAogICBOVUxMfSwKCiAge05VTEx9Cn07CgpzdGF0aWMgUHlUeXBlT2JqZWN0IF9weUF1ZGlvX1N0cmVhbVR5cGUgPSB7CiAgICBQeVZhck9iamVjdF9IRUFEX0lOSVQoTlVMTCwgMCkKICAgICJfcG9ydGF1ZGlvLlN0cmVhbSIsICAgICAgIC8qdHBfbmFtZSovCiAgICBzaXplb2YoX3B5QXVkaW9fU3RyZWFtKSwgICAgICAgICAvKnRwX2Jhc2ljc2l6ZSovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2l0ZW1zaXplKi8KICAgIChkZXN0cnVjdG9yKSBfcHlBdWRpb19TdHJlYW1fZGVhbGxvYywgLyp0cF9kZWFsbG9jKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfcHJpbnQqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9nZXRhdHRyKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfc2V0YXR0ciovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2NvbXBhcmUqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9yZXByKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfYXNfbnVtYmVyKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfYXNfc2VxdWVuY2UqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9hc19tYXBwaW5nKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfaGFzaCAqLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9jYWxsKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfc3RyKi8KICAgIDAsICAgICAgICAgICAgICAgICAgICAgICAgIC8qdHBfZ2V0YXR0cm8qLwogICAgMCwgICAgICAgICAgICAgICAgICAgICAgICAgLyp0cF9zZXRhdHRybyovCiAgICAwLCAgICAgICAgICAgICAgICAgICAgICAgICAvKnRwX2FzX2J1ZmZlciovCiAgICBQeV9UUEZMQUdTX0RFRkFVTFQsICAgICAgICAvKnRwX2ZsYWdzKi8KICAgICJQb3J0IEF1ZGlvIFN0cmVhbSIsICAgICAgIC8qIHRwX2RvYyAqLwogICAgMCwgIC8qIHRwX3RyYXZlcnNlICovCiAgICAwLCAgLyogdHBfY2xlYXIgKi8KICAgIDAsICAvKiB0cF9yaWNoY29tcGFyZSAqLwogICAgMCwgIC8qIHRwX3dlYWtsaXN0b2Zmc2V0ICovCiAgICAwLCAgLyogdHBfaXRlciAqLwogICAgMCwgIC8qIHRwX2l0ZXJuZXh0ICovCiAgICAwLCAgLyogdHBfbWV0aG9kcyAqLwogICAgMCwgIC8qIHRwX21lbWJlcnMgKi8KICAgIF9weUF1ZGlvX1N0cmVhbV9nZXRzZXRlcnMsIC8qIHRwX2dldHNldCAqLwogICAgMCwgIC8qIHRwX2Jhc2UgKi8KICAgIDAsICAvKiB0cF9kaWN0ICovCiAgICAwLCAgLyogdHBfZGVzY3JfZ2V0ICovCiAgICAwLCAgLyogdHBfZGVzY3Jfc2V0ICovCiAgICAwLCAgLyogdHBfZGljdG9mZnNldCAqLwogICAgMCwgIC8qIHRwX2luaXQgKi8KICAgIDAsICAvKiB0cF9hbGxvYyAqLwogICAgMCwgIC8qIHRwX25ldyAqLwp9OwoKc3RhdGljIF9weUF1ZGlvX1N0cmVhbSAqCl9jcmVhdGVfU3RyZWFtX29iamVjdCh2b2lkKQp7CiAgX3B5QXVkaW9fU3RyZWFtICpvYmo7CgogIC8qIGRvbid0IGFsbG93IHN1YmNsYXNzaW5nPyAqLwogIG9iaiA9IChfcHlBdWRpb19TdHJlYW0gKikgUHlPYmplY3RfTmV3KF9weUF1ZGlvX1N0cmVhbSwKCQkJCQkgJl9weUF1ZGlvX1N0cmVhbVR5cGUpOwogIHJldHVybiBvYmo7Cn0KCgovKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqCiAqIElJSS4gUG9ydEF1ZGlvIE1ldGhvZCBJbXBsZW1lbnRhdGlvbnMKICoKICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqIFZlcnNpb24gSW5mbwogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2dldF92ZXJzaW9uKFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewogIGlmICghUHlBcmdfUGFyc2VUdXBsZShhcmdzLCAiIikpCiAgICByZXR1cm4gTlVMTDsKCiAgcmV0dXJuIFB5TG9uZ19Gcm9tTG9uZyhQYV9HZXRWZXJzaW9uKCkpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpwYV9nZXRfdmVyc2lvbl90ZXh0KFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewogIGlmICghUHlBcmdfUGFyc2VUdXBsZShhcmdzLCAiIikpCiAgICByZXR1cm4gTlVMTDsKCiAgcmV0dXJuIFB5VW5pY29kZV9Gcm9tU3RyaW5nKFBhX0dldFZlcnNpb25UZXh0KCkpOwp9CgovKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKiBJbml0aWFsaXphdGlvbi9UZXJtaW5hdGlvbgogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2luaXRpYWxpemUoUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzKQp7CiAgaW50IGVycjsKICBlcnIgPSBQYV9Jbml0aWFsaXplKCk7CiAgaWYgKGVyciAhPSBwYU5vRXJyb3IpIHsKICAgIFBhX1Rlcm1pbmF0ZSgpOwojaWZkZWYgVkVSQk9TRQogICAgZnByaW50ZihzdGRlcnIsICJBbiBlcnJvciBvY2N1cmVkIHdoaWxlIHVzaW5nIHRoZSBwb3J0YXVkaW8gc3RyZWFtXG4iKTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbnVtYmVyOiAlZFxuIiwgZXJyKTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbWVzc2FnZTogJXNcbiIsIFBhX0dldEVycm9yVGV4dChlcnIpKTsKI2VuZGlmCiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICBQYV9HZXRFcnJvclRleHQoZXJyKSwgZXJyKSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIFB5X0lOQ1JFRihQeV9Ob25lKTsKICByZXR1cm4gUHlfTm9uZTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKcGFfdGVybWluYXRlKFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewogIFBhX1Rlcm1pbmF0ZSgpOwogIFB5X0lOQ1JFRihQeV9Ob25lKTsKICByZXR1cm4gUHlfTm9uZTsKfQoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICogSG9zdEFQSQogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2dldF9ob3N0X2FwaV9jb3VudChQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBQYUhvc3RBcGlJbmRleCBjb3VudDsKCiAgaWYgKCFQeUFyZ19QYXJzZVR1cGxlKGFyZ3MsICIiKSkKICAgIHJldHVybiBOVUxMOwoKICBjb3VudCA9IFBhX0dldEhvc3RBcGlDb3VudCgpOwoKICBpZiAoY291bnQgPCAwKSB7CgojaWZkZWYgVkVSQk9TRQogICAgZnByaW50ZihzdGRlcnIsICJBbiBlcnJvciBvY2N1cmVkIHdoaWxlIHVzaW5nIHRoZSBwb3J0YXVkaW8gc3RyZWFtXG4iKTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbnVtYmVyOiAlZFxuIiwgY291bnQpOwogICAgZnByaW50ZihzdGRlcnIsICJFcnJvciBtZXNzYWdlOiAlc1xuIiwgUGFfR2V0RXJyb3JUZXh0KGNvdW50KSk7CiNlbmRpZgoKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19JT0Vycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgIFBhX0dldEVycm9yVGV4dChjb3VudCksIGNvdW50KSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHJldHVybiBQeUxvbmdfRnJvbUxvbmcoY291bnQpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpwYV9nZXRfZGVmYXVsdF9ob3N0X2FwaShQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBQYUhvc3RBcGlJbmRleCBpbmRleDsKCiAgaWYgKCFQeUFyZ19QYXJzZVR1cGxlKGFyZ3MsICIiKSkKICAgIHJldHVybiBOVUxMOwoKICBpbmRleCA9IFBhX0dldERlZmF1bHRIb3N0QXBpKCk7CgogIGlmIChpbmRleCA8IDApIHsKCiNpZmRlZiBWRVJCT1NFCiAgICBmcHJpbnRmKHN0ZGVyciwgIkFuIGVycm9yIG9jY3VyZWQgd2hpbGUgdXNpbmcgdGhlIHBvcnRhdWRpbyBzdHJlYW1cbiIpOwogICAgZnByaW50ZihzdGRlcnIsICJFcnJvciBudW1iZXI6ICVkXG4iLCBpbmRleCk7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG1lc3NhZ2U6ICVzXG4iLCBQYV9HZXRFcnJvclRleHQoaW5kZXgpKTsKI2VuZGlmCgogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgUGFfR2V0RXJyb3JUZXh0KGluZGV4KSwgaW5kZXgpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5TG9uZ19Gcm9tTG9uZyhpbmRleCk7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2hvc3RfYXBpX3R5cGVfaWRfdG9faG9zdF9hcGlfaW5kZXgoUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzKQp7CiAgUGFIb3N0QXBpVHlwZUlkIHR5cGVpZDsKICBQYUhvc3RBcGlJbmRleCBpbmRleDsKCiAgaWYgKCFQeUFyZ19QYXJzZVR1cGxlKGFyZ3MsICJpIiwgJnR5cGVpZCkpCiAgICByZXR1cm4gTlVMTDsKCiAgaW5kZXggPSBQYV9Ib3N0QXBpVHlwZUlkVG9Ib3N0QXBpSW5kZXgodHlwZWlkKTsKCiAgaWYgKGluZGV4IDwgMCkgewoKI2lmZGVmIFZFUkJPU0UKICAgIGZwcmludGYoc3RkZXJyLCAiQW4gZXJyb3Igb2NjdXJlZCB3aGlsZSB1c2luZyB0aGUgcG9ydGF1ZGlvIHN0cmVhbVxuIik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG51bWJlcjogJWRcbiIsIGluZGV4KTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbWVzc2FnZTogJXNcbiIsIFBhX0dldEVycm9yVGV4dChpbmRleCkpOwojZW5kaWYKCiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICBQYV9HZXRFcnJvclRleHQoaW5kZXgpLCBpbmRleCkpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlMb25nX0Zyb21Mb25nKGluZGV4KTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKcGFfaG9zdF9hcGlfZGV2aWNlX2luZGV4X3RvX2RldmljZV9pbmRleChQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBQYUhvc3RBcGlJbmRleCBhcGlJbmRleDsKICBpbnQgaG9zdEFwaURldmljZWluZGV4OwogIFBhRGV2aWNlSW5kZXggZGV2SW5kZXg7CgoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgImlpIiwgJmFwaUluZGV4LCAmaG9zdEFwaURldmljZWluZGV4KSkKICAgIHJldHVybiBOVUxMOwoKICBkZXZJbmRleCA9IFBhX0hvc3RBcGlEZXZpY2VJbmRleFRvRGV2aWNlSW5kZXgoYXBpSW5kZXgsIGhvc3RBcGlEZXZpY2VpbmRleCk7CiAgaWYgKGRldkluZGV4IDwgMCkgewoKI2lmZGVmIFZFUkJPU0UKICAgIGZwcmludGYoc3RkZXJyLCAiQW4gZXJyb3Igb2NjdXJlZCB3aGlsZSB1c2luZyB0aGUgcG9ydGF1ZGlvIHN0cmVhbVxuIik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG51bWJlcjogJWRcbiIsIGRldkluZGV4KTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbWVzc2FnZTogJXNcbiIsIFBhX0dldEVycm9yVGV4dChkZXZJbmRleCkpOwojZW5kaWYKCiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICBQYV9HZXRFcnJvclRleHQoZGV2SW5kZXgpLCBkZXZJbmRleCkpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlMb25nX0Zyb21Mb25nKGRldkluZGV4KTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKcGFfZ2V0X2hvc3RfYXBpX2luZm8oUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzKQp7CiAgUGFIb3N0QXBpSW5kZXggaW5kZXg7CiAgUGFIb3N0QXBpSW5mbyogX2luZm87CiAgX3B5QXVkaW9fcGFIb3N0QXBpSW5mbyogcHlfaW5mbzsKCiAgaWYgKCFQeUFyZ19QYXJzZVR1cGxlKGFyZ3MsICJpIiwgJmluZGV4KSkKICAgIHJldHVybiBOVUxMOwoKICBfaW5mbyA9IChQYUhvc3RBcGlJbmZvICopIFBhX0dldEhvc3RBcGlJbmZvKGluZGV4KTsKCiAgaWYgKCFfaW5mbykgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIkludmFsaWQgaG9zdCBhcGkgaW5mbyIsCgkJCQkgIHBhSW52YWxpZEhvc3RBcGkpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcHlfaW5mbyA9IF9jcmVhdGVfcGFIb3N0QXBpSW5mb19vYmplY3QoKTsKICBweV9pbmZvLT5hcGlJbmZvID0gX2luZm87CgogIHJldHVybiAoUHlPYmplY3QgKikgcHlfaW5mbzsKfQoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICogRGV2aWNlIEFQSQogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2dldF9kZXZpY2VfY291bnQoUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzKQp7CiAgUGFEZXZpY2VJbmRleCBjb3VudDsKCiAgaWYgKCFQeUFyZ19QYXJzZVR1cGxlKGFyZ3MsICIiKSkKICAgIHJldHVybiBOVUxMOwoKICBjb3VudCA9IFBhX0dldERldmljZUNvdW50KCk7CiAgaWYgKGNvdW50IDwgMCkgewoKI2lmZGVmIFZFUkJPU0UKICAgIGZwcmludGYoc3RkZXJyLCAiQW4gZXJyb3Igb2NjdXJlZCB3aGlsZSB1c2luZyB0aGUgcG9ydGF1ZGlvIHN0cmVhbVxuIik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG51bWJlcjogJWRcbiIsIGNvdW50KTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbWVzc2FnZTogJXNcbiIsIFBhX0dldEVycm9yVGV4dChjb3VudCkpOwojZW5kaWYKCiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICBQYV9HZXRFcnJvclRleHQoY291bnQpLCBjb3VudCkpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlMb25nX0Zyb21Mb25nKGNvdW50KTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKcGFfZ2V0X2RlZmF1bHRfaW5wdXRfZGV2aWNlKFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewogIFBhRGV2aWNlSW5kZXggaW5kZXg7CgogIGlmICghUHlBcmdfUGFyc2VUdXBsZShhcmdzLCAiIikpCiAgICByZXR1cm4gTlVMTDsKCiAgaW5kZXggPSBQYV9HZXREZWZhdWx0SW5wdXREZXZpY2UoKTsKICBpZiAoaW5kZXggPT0gcGFOb0RldmljZSkgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0lPRXJyb3IsICJObyBEZWZhdWx0IElucHV0IERldmljZSBBdmFpbGFibGUiKTsKICAgIHJldHVybiBOVUxMOwogIH0gZWxzZSBpZiAoaW5kZXggPCAwKSB7CgojaWZkZWYgVkVSQk9TRQogICAgZnByaW50ZihzdGRlcnIsICJBbiBlcnJvciBvY2N1cmVkIHdoaWxlIHVzaW5nIHRoZSBwb3J0YXVkaW8gc3RyZWFtXG4iKTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbnVtYmVyOiAlZFxuIiwgaW5kZXgpOwogICAgZnByaW50ZihzdGRlcnIsICJFcnJvciBtZXNzYWdlOiAlc1xuIiwgUGFfR2V0RXJyb3JUZXh0KGluZGV4KSk7CiNlbmRpZgoKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19JT0Vycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgIFBhX0dldEVycm9yVGV4dChpbmRleCksIGluZGV4KSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHJldHVybiBQeUxvbmdfRnJvbUxvbmcoaW5kZXgpOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpwYV9nZXRfZGVmYXVsdF9vdXRwdXRfZGV2aWNlKFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewogIFBhRGV2aWNlSW5kZXggaW5kZXg7CgogIGlmICghUHlBcmdfUGFyc2VUdXBsZShhcmdzLCAiIikpCiAgICByZXR1cm4gTlVMTDsKCiAgaW5kZXggPSBQYV9HZXREZWZhdWx0T3V0cHV0RGV2aWNlKCk7CiAgaWYgKGluZGV4ID09IHBhTm9EZXZpY2UpIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19JT0Vycm9yLCAiTm8gRGVmYXVsdCBPdXRwdXQgRGV2aWNlIEF2YWlsYWJsZSIpOwogICAgcmV0dXJuIE5VTEw7CiAgfSBlbHNlIGlmIChpbmRleCA8IDApIHsKCiNpZmRlZiBWRVJCT1NFCiAgICBmcHJpbnRmKHN0ZGVyciwgIkFuIGVycm9yIG9jY3VyZWQgd2hpbGUgdXNpbmcgdGhlIHBvcnRhdWRpbyBzdHJlYW1cbiIpOwogICAgZnByaW50ZihzdGRlcnIsICJFcnJvciBudW1iZXI6ICVkXG4iLCBpbmRleCk7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG1lc3NhZ2U6ICVzXG4iLCBQYV9HZXRFcnJvclRleHQoaW5kZXgpKTsKI2VuZGlmCgogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgUGFfR2V0RXJyb3JUZXh0KGluZGV4KSwgaW5kZXgpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5TG9uZ19Gcm9tTG9uZyhpbmRleCk7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2dldF9kZXZpY2VfaW5mbyhQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBQYURldmljZUluZGV4IGluZGV4OwogIFBhRGV2aWNlSW5mbyogX2luZm87CiAgX3B5QXVkaW9fcGFEZXZpY2VJbmZvKiBweV9pbmZvOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgImkiLCAmaW5kZXgpKQogICAgcmV0dXJuIE5VTEw7CgogIF9pbmZvID0gKFBhRGV2aWNlSW5mbyAqKSBQYV9HZXREZXZpY2VJbmZvKGluZGV4KTsKCiAgaWYgKCFfaW5mbykgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIkludmFsaWQgZGV2aWNlIGluZm8iLCBwYUludmFsaWREZXZpY2UpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcHlfaW5mbyA9IF9jcmVhdGVfcGFEZXZpY2VJbmZvX29iamVjdCgpOwogIHB5X2luZm8tPmRldkluZm8gPSBfaW5mbzsKICByZXR1cm4gKFB5T2JqZWN0ICopIHB5X2luZm87Cn0KCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqIFN0cmVhbSBPcGVuIC8gQ2xvc2UgLyBTdXBwb3J0ZWQKICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgppbnQKX3N0cmVhbV9jYWxsYmFja19jZnVuY3Rpb24oY29uc3Qgdm9pZCAqaW5wdXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZvaWQgKm91dHB1dCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5zaWduZWQgbG9uZyBmcmFtZUNvdW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBQYVN0cmVhbUNhbGxiYWNrVGltZUluZm8gKnRpbWVJbmZvLAogICAgICAgICAgICAgICAgICAgICAgICAgICBQYVN0cmVhbUNhbGxiYWNrRmxhZ3Mgc3RhdHVzRmxhZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZvaWQgKnVzZXJEYXRhKQp7CiAgaW50IHJldHVybl92YWwgPSBwYUFib3J0OwogIFB5R0lMU3RhdGVfU1RBVEUgX3N0YXRlID0gUHlHSUxTdGF0ZV9FbnN1cmUoKTsKCiNpZmRlZiBWRVJCT1NFCiAgaWYgKHN0YXR1c0ZsYWdzICE9IDApIHsKICAgIHByaW50ZigiU3RhdHVzIGZsYWcgc2V0OiAiKTsKICAgIGlmIChzdGF0dXNGbGFncyAmIHBhSW5wdXRVbmRlcmZsb3cpIHsKICAgICAgcHJpbnRmKCJpbnB1dCB1bmRlcmZsb3chXG4iKTsKICAgIH0KICAgIGlmIChzdGF0dXNGbGFncyAmIHBhSW5wdXRPdmVyZmxvdykgewogICAgICBwcmludGYoImlucHV0IG92ZXJmbG93IVxuIik7CiAgICB9CiAgICBpZiAoc3RhdHVzRmxhZ3MgJiBwYU91dHB1dFVuZGVyZmxvdykgewogICAgICBwcmludGYoIm91dHB1dCB1bmRlcmZsb3chXG4iKTsKICAgIH0KICAgIGlmIChzdGF0dXNGbGFncyAmIHBhT3V0cHV0VW5kZXJmbG93KSB7CiAgICAgIHByaW50Zigib3V0cHV0IG92ZXJmbG93IVxuIik7CiAgICB9CiAgICBpZiAoc3RhdHVzRmxhZ3MgJiBwYVByaW1pbmdPdXRwdXQpIHsKICAgICAgcHJpbnRmKCJwcmltaW5nIG91dHB1dCFcbiIpOwogICAgfQogIH0KI2VuZGlmCgogIFB5QXVkaW9DYWxsYmFja0NvbnRleHQgKmNvbnRleHQgPSAoUHlBdWRpb0NhbGxiYWNrQ29udGV4dCAqKXVzZXJEYXRhOwogIFB5T2JqZWN0ICpweV9jYWxsYmFjayA9IGNvbnRleHQtPmNhbGxiYWNrOwogIHVuc2lnbmVkIGludCBieXRlc19wZXJfZnJhbWUgPSBjb250ZXh0LT5mcmFtZV9zaXplOwogIGxvbmcgbWFpbl90aHJlYWRfaWQgPSBjb250ZXh0LT5tYWluX3RocmVhZF9pZDsKCiAgUHlPYmplY3QgKnB5X2ZyYW1lX2NvdW50ID0gUHlMb25nX0Zyb21VbnNpZ25lZExvbmcoZnJhbWVDb3VudCk7CiAgUHlPYmplY3QgKnB5X3RpbWVfaW5mbyA9IFB5X0J1aWxkVmFsdWUoIntzOmQsczpkLHM6ZH0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpbnB1dF9idWZmZXJfYWRjX3RpbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVJbmZvLT5pbnB1dEJ1ZmZlckFkY1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImN1cnJlbnRfdGltZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZUluZm8tPmN1cnJlbnRUaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvdXRwdXRfYnVmZmVyX2RhY190aW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lSW5mby0+b3V0cHV0QnVmZmVyRGFjVGltZSk7CiAgUHlPYmplY3QgKnB5X3N0YXR1c19mbGFncyA9IFB5TG9uZ19Gcm9tVW5zaWduZWRMb25nKHN0YXR1c0ZsYWdzKTsKICBQeU9iamVjdCAqcHlfaW5wdXRfZGF0YSA9IFB5X05vbmU7CiAgY29uc3QgY2hhciAqcERhdGE7CiAgaW50IG91dHB1dF9sZW47CiAgUHlPYmplY3QgKnB5X3Jlc3VsdDsKCiAgaWYgKGlucHV0KSB7CiAgICBweV9pbnB1dF9kYXRhID0gUHlCeXRlc19Gcm9tU3RyaW5nQW5kU2l6ZShpbnB1dCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5dGVzX3Blcl9mcmFtZSAqIGZyYW1lQ291bnQpOwogIH0KCiAgcHlfcmVzdWx0ID0gUHlPYmplY3RfQ2FsbEZ1bmN0aW9uT2JqQXJncyhweV9jYWxsYmFjaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB5X2lucHV0X2RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBweV9mcmFtZV9jb3VudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB5X3RpbWVfaW5mbywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB5X3N0YXR1c19mbGFncywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5VTEwpOwoKICBpZiAocHlfcmVzdWx0ID09IE5VTEwpIHsKI2lmZGVmIFZFUkJPU0UKICAgIGZwcmludGYoc3RkZXJyLCAiQW4gZXJyb3Igb2NjdXJlZCB3aGlsZSB1c2luZyB0aGUgcG9ydGF1ZGlvIHN0cmVhbVxuIik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG1lc3NhZ2U6IENvdWxkIG5vdCBjYWxsIGNhbGxiYWNrIGZ1bmN0aW9uXG4iKTsKI2VuZGlmCiAgICBQeU9iamVjdCAqZXJyID0gUHlFcnJfT2NjdXJyZWQoKTsKCiAgICBpZiAoZXJyKSB7CiAgICAgICAgUHlUaHJlYWRTdGF0ZV9TZXRBc3luY0V4YyhtYWluX3RocmVhZF9pZCwgZXJyKTsKCiAgICAgICAgLy8gUHJpbnQgb3V0IGEgc3RhY2sgdHJhY2UgdG8gaGVscCBkZWJ1Z2dpbmcuCiAgICAgICAgLy8gVE9ETzogbWFrZSBWRVJCT1NFIGEgcnVudGltZSBmbGFnIHNvIHVzZXJzIGNhbiBjb250cm9sCiAgICAgICAgLy8gdGhlIGFtb3VudCBvZiBsb2dnaW5nLgogICAgICAgIFB5RXJyX1ByaW50KCk7CiAgICB9CgogICAgZ290byBlbmQ7CiAgfQoKCiAgaWYgKCFQeUFyZ19QYXJzZVR1cGxlKHB5X3Jlc3VsdCwKICAgICAgICAgICAgICAgICAgICAgICAgInojaSIsCiAgICAgICAgICAgICAgICAgICAgICAgICZwRGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgJm91dHB1dF9sZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICZyZXR1cm5fdmFsKSkgewojaWZkZWYgVkVSQk9TRQogICAgZnByaW50ZihzdGRlcnIsICJBbiBlcnJvciBvY2N1cmVkIHdoaWxlIHVzaW5nIHRoZSBwb3J0YXVkaW8gc3RyZWFtXG4iKTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbWVzc2FnZTogQ291bGQgbm90IHBhcnNlIGNhbGxiYWNrIHJldHVybiB2YWx1ZVxuIik7CiNlbmRpZgoKICAgIFB5T2JqZWN0ICplcnIgPSBQeUVycl9PY2N1cnJlZCgpOwoKICAgIGlmIChlcnIpIHsKICAgICAgICBQeVRocmVhZFN0YXRlX1NldEFzeW5jRXhjKG1haW5fdGhyZWFkX2lkLCBlcnIpOwoKICAgICAgICAvLyBQcmludCBvdXQgYSBzdGFjayB0cmFjZSB0byBoZWxwIGRlYnVnZ2luZy4KICAgICAgICAvLyBUT0RPOiBtYWtlIFZFUkJPU0UgYSBydW50aW1lIGZsYWcgc28gdXNlcnMgY2FuIGNvbnRyb2wKICAgICAgICAvLyB0aGUgYW1vdW50IG9mIGxvZ2dpbmcuCiAgICAgICAgUHlFcnJfUHJpbnQoKTsKICAgIH0KCiAgICBQeV9YREVDUkVGKHB5X3Jlc3VsdCk7CiAgICByZXR1cm5fdmFsID0gcGFBYm9ydDsKICAgIGdvdG8gZW5kOwogIH0KCiAgUHlfREVDUkVGKHB5X3Jlc3VsdCk7CgogIGlmICgocmV0dXJuX3ZhbCAhPSBwYUNvbXBsZXRlKSAmJgogICAgICAocmV0dXJuX3ZhbCAhPSBwYUFib3J0KSAmJgogICAgICAocmV0dXJuX3ZhbCAhPSBwYUNvbnRpbnVlKSkgewogICAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfVmFsdWVFcnJvciwKICAgICAgICAgICAgICAgICAgICAgICJJbnZhbGlkIFBhU3RyZWFtQ2FsbGJhY2tSZXN1bHQgZnJvbSBjYWxsYmFjayIpOwogICAgICBQeVRocmVhZFN0YXRlX1NldEFzeW5jRXhjKG1haW5fdGhyZWFkX2lkLCBQeUVycl9PY2N1cnJlZCgpKTsKICAgICAgUHlFcnJfUHJpbnQoKTsKCiAgICAgIC8vIFF1aXQgdGhlIGNhbGxiYWNrIGxvb3AKICAgICAgcmV0dXJuX3ZhbCA9IHBhQWJvcnQ7CgogICAgICBnb3RvIGVuZDsKICB9CgogIC8vIENvcHkgYnl0ZXMgZm9yIHBsYXliYWNrIG9ubHkgaWYgdGhpcyBpcyBhbiBvdXRwdXQgc3RyZWFtOgoKICBpZiAob3V0cHV0KSB7CiAgICAgIGNoYXIgKm91dHB1dF9kYXRhID0gKGNoYXIqKW91dHB1dDsKICAgICAgbWVtY3B5KG91dHB1dF9kYXRhLCBwRGF0YSwgbWluKG91dHB1dF9sZW4sIGJ5dGVzX3Blcl9mcmFtZSAqIGZyYW1lQ291bnQpKTsKCiAgICAgIC8vIFBhZCBvdXQgdGhlIHJlc3Qgb2YgdGhlIGJ1ZmZlciB3aXRoIDBzIGlmIGNhbGxiYWNrIHJldHVybmVkCiAgICAgIC8vIHRvbyBmZXcgZnJhbWVzIChhbmQgYXNzdW1lIHBhQ29tcGxldGUpLgogICAgICBpZiAob3V0cHV0X2xlbiA8IChmcmFtZUNvdW50ICogYnl0ZXNfcGVyX2ZyYW1lKSkgewogICAgICAgICAgbWVtc2V0KG91dHB1dF9kYXRhICsgb3V0cHV0X2xlbiwKICAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgIChmcmFtZUNvdW50ICogYnl0ZXNfcGVyX2ZyYW1lKSAtIG91dHB1dF9sZW4pOwogICAgICAgICAgcmV0dXJuX3ZhbCA9IHBhQ29tcGxldGU7CiAgICAgIH0KICB9CgogZW5kOgoKICBpZiAoaW5wdXQpIHsKICAgIC8vIERlY3JlbWVudCB0aGlzIGF0IHRoZSBlbmQsIGFmdGVyIG1lbWNweSwgaW4gY2FzZSB0aGUgdXNlcgogICAgLy8gcmV0dXJucyBweV9pbnB1dF9kYXRhIGJhY2sgZm9yIHBsYXliYWNrLgogICAgUHlfREVDUkVGKHB5X2lucHV0X2RhdGEpOwogIH0KCiAgUHlfWERFQ1JFRihweV9mcmFtZV9jb3VudCk7CiAgUHlfWERFQ1JFRihweV90aW1lX2luZm8pOwogIFB5X1hERUNSRUYocHlfc3RhdHVzX2ZsYWdzKTsKCiAgUHlHSUxTdGF0ZV9SZWxlYXNlKF9zdGF0ZSk7CiAgcmV0dXJuIHJldHVybl92YWw7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCnBhX29wZW4oUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzLCBQeU9iamVjdCAqa3dhcmdzKQp7CiAgaW50IHJhdGUsIGNoYW5uZWxzOwogIGludCBpbnB1dCwgb3V0cHV0LCBmcmFtZXNfcGVyX2J1ZmZlcjsKICBpbnQgaW5wdXRfZGV2aWNlX2luZGV4ID0gLTE7CiAgaW50IG91dHB1dF9kZXZpY2VfaW5kZXggPSAtMTsKICBQeU9iamVjdCAqaW5wdXRfZGV2aWNlX2luZGV4X2FyZyA9IE5VTEw7CiAgUHlPYmplY3QgKm91dHB1dF9kZXZpY2VfaW5kZXhfYXJnID0gTlVMTDsKICBQeU9iamVjdCAqc3RyZWFtX2NhbGxiYWNrID0gTlVMTDsKICBQYVNhbXBsZUZvcm1hdCBmb3JtYXQ7CiAgUGFFcnJvciBlcnI7CiAgUHlPYmplY3QgKmlucHV0X2RldmljZV9pbmRleF9sb25nOwogIFB5T2JqZWN0ICpvdXRwdXRfZGV2aWNlX2luZGV4X2xvbmc7CiAgUGFTdHJlYW1QYXJhbWV0ZXJzICpvdXRwdXRQYXJhbWV0ZXJzID0gTlVMTDsKICBQYVN0cmVhbVBhcmFtZXRlcnMgKmlucHV0UGFyYW1ldGVycyA9IE5VTEw7CiAgUGFTdHJlYW0gKnN0cmVhbSA9IE5VTEw7CiAgUGFTdHJlYW1JbmZvICpzdHJlYW1JbmZvID0gTlVMTDsKICBQeUF1ZGlvQ2FsbGJhY2tDb250ZXh0ICpjb250ZXh0ID0gTlVMTDsKICBfcHlBdWRpb19TdHJlYW0gKnN0cmVhbU9iamVjdDsKCiAgLyogcGFzcyBpbiByYXRlLCBjaGFubmVsLCB3aWR0aCAqLwogIHN0YXRpYyBjaGFyICprd2xpc3RbXSA9IHsicmF0ZSIsCgkJCSAgICJjaGFubmVscyIsCgkJCSAgICJmb3JtYXQiLAoJCQkgICAiaW5wdXQiLAoJCQkgICAib3V0cHV0IiwKCQkJICAgImlucHV0X2RldmljZV9pbmRleCIsCgkJCSAgICJvdXRwdXRfZGV2aWNlX2luZGV4IiwKCQkJICAgImZyYW1lc19wZXJfYnVmZmVyIiwKCQkJICAgImlucHV0X2hvc3RfYXBpX3NwZWNpZmljX3N0cmVhbV9pbmZvIiwKCQkJICAgIm91dHB1dF9ob3N0X2FwaV9zcGVjaWZpY19zdHJlYW1faW5mbyIsCgkJCSAgICJzdHJlYW1fY2FsbGJhY2siLAoJCQkgICBOVUxMfTsKCiNpZmRlZiBNQUNPU1gKICBfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mbyAqaW5wdXRIb3N0U3BlY2lmaWNTdHJlYW1JbmZvID0KICAgICAgTlVMTDsKICBfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mbyAqb3V0cHV0SG9zdFNwZWNpZmljU3RyZWFtSW5mbyA9CiAgICAgIE5VTEw7CiNlbHNlCiAgLyogbW9zdGx5IGlnbm9yZWQuLi4qLwogIFB5T2JqZWN0ICppbnB1dEhvc3RTcGVjaWZpY1N0cmVhbUluZm8gPSBOVUxMOwogIFB5T2JqZWN0ICpvdXRwdXRIb3N0U3BlY2lmaWNTdHJlYW1JbmZvID0gTlVMTDsKI2VuZGlmCgogIC8qIGRlZmF1bHQgdG8gbmVpdGhlciBvdXRwdXQgbm9yIGlucHV0ICovCiAgaW5wdXQgPSAwOwogIG91dHB1dCA9IDA7CiAgZnJhbWVzX3Blcl9idWZmZXIgPSBERUZBVUxUX0ZSQU1FU19QRVJfQlVGRkVSOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGVBbmRLZXl3b3JkcyhhcmdzLCBrd2FyZ3MsCiNpZmRlZiBNQUNPU1gKCQkJCSAgICJpaWt8aWlPT2lPIU8hTyIsCiNlbHNlCgkJCQkgICAiaWlrfGlpT09pT09PIiwKI2VuZGlmCgkJCQkgICBrd2xpc3QsCgkJCQkgICAmcmF0ZSwgJmNoYW5uZWxzLCAmZm9ybWF0LAoJCQkJICAgJmlucHV0LCAmb3V0cHV0LAoJCQkJICAgJmlucHV0X2RldmljZV9pbmRleF9hcmcsCgkJCQkgICAmb3V0cHV0X2RldmljZV9pbmRleF9hcmcsCgkJCQkgICAmZnJhbWVzX3Blcl9idWZmZXIsCiNpZmRlZiBNQUNPU1gKCQkJCSAgICZfcHlBdWRpb19NYWNPU1hfaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mb1R5cGUsCiNlbmRpZgoJCQkJICAgJmlucHV0SG9zdFNwZWNpZmljU3RyZWFtSW5mbywKI2lmZGVmIE1BQ09TWAoJCQkJICAgJl9weUF1ZGlvX01hY09TWF9ob3N0QXBpU3BlY2lmaWNTdHJlYW1JbmZvVHlwZSwKI2VuZGlmCgkJCQkgICAmb3V0cHV0SG9zdFNwZWNpZmljU3RyZWFtSW5mbywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmc3RyZWFtX2NhbGxiYWNrKSkKCiAgICByZXR1cm4gTlVMTDsKCiAgaWYgKHN0cmVhbV9jYWxsYmFjayAmJiAoUHlDYWxsYWJsZV9DaGVjayhzdHJlYW1fY2FsbGJhY2spID09IDApKSB7CiAgICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19UeXBlRXJyb3IsICJzdHJlYW1fY2FsbGJhY2sgbXVzdCBiZSBjYWxsYWJsZSIpOwogICAgICByZXR1cm4gTlVMTDsKICB9CgogIC8qIGNoZWNrIHRvIHNlZSBpZiBkZXZpY2UgaW5kaWNlcyB3ZXJlIHNwZWNpZmllZCAqLwogIGlmICgoaW5wdXRfZGV2aWNlX2luZGV4X2FyZyA9PSBOVUxMKSB8fAogICAgICAoaW5wdXRfZGV2aWNlX2luZGV4X2FyZyA9PSBQeV9Ob25lKSkgewoKI2lmZGVmIFZFUkJPU0UKICAgIHByaW50ZigiVXNpbmcgZGVmYXVsdCBpbnB1dCBkZXZpY2VcbiIpOwojZW5kaWYKCiAgICBpbnB1dF9kZXZpY2VfaW5kZXggPSAtMTsKCiAgfSBlbHNlIHsKICAgIC8vIFN1cHBvcnQgYm90aCBQeXRob24gMiBhbmQgUHl0aG9uIDMgYnkgdXNpbmcgUHlOdW1iZXJfQ2hlY2sKICAgIGlmICghUHlOdW1iZXJfQ2hlY2soaW5wdXRfZGV2aWNlX2luZGV4X2FyZykpIHsKICAgICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX1ZhbHVlRXJyb3IsCgkJICAgICAgImlucHV0X2RldmljZV9pbmRleCBtdXN0IGJlIGludGVnZXIgKG9yIE5vbmUpIik7CiAgICAgIHJldHVybiBOVUxMOwogICAgfQoKICAgIGlucHV0X2RldmljZV9pbmRleF9sb25nID0KICAgICAgUHlOdW1iZXJfTG9uZyhpbnB1dF9kZXZpY2VfaW5kZXhfYXJnKTsKCiAgICBpbnB1dF9kZXZpY2VfaW5kZXggPSAoaW50KSBQeUxvbmdfQXNMb25nKGlucHV0X2RldmljZV9pbmRleF9sb25nKTsKICAgIFB5X0RFQ1JFRihpbnB1dF9kZXZpY2VfaW5kZXhfbG9uZyk7CgojaWZkZWYgVkVSQk9TRQogICAgcHJpbnRmKCJVc2luZyBpbnB1dCBkZXZpY2UgaW5kZXggbnVtYmVyOiAlZFxuIiwgaW5wdXRfZGV2aWNlX2luZGV4KTsKI2VuZGlmCiAgfQoKICBpZiAoKG91dHB1dF9kZXZpY2VfaW5kZXhfYXJnID09IE5VTEwpIHx8CiAgICAgIChvdXRwdXRfZGV2aWNlX2luZGV4X2FyZyA9PSBQeV9Ob25lKSkgewoKI2lmZGVmIFZFUkJPU0UKICAgIHByaW50ZigiVXNpbmcgZGVmYXVsdCBvdXRwdXQgZGV2aWNlXG4iKTsKI2VuZGlmCgogICAgb3V0cHV0X2RldmljZV9pbmRleCA9IC0xOwoKICB9IGVsc2UgewogICAgLy8gU3VwcG9ydCBib3RoIFB5dGhvbiAyIGFuZCBQeXRob24gMyBieSB1c2luZyBQeU51bWJlcl9DaGVjawogICAgaWYgKCFQeU51bWJlcl9DaGVjayhvdXRwdXRfZGV2aWNlX2luZGV4X2FyZykpIHsKICAgICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX1ZhbHVlRXJyb3IsCgkJICAgICAgIm91dHB1dF9kZXZpY2VfaW5kZXggbXVzdCBiZSBpbnRlZ2VyIChvciBOb25lKSIpOwogICAgICByZXR1cm4gTlVMTDsKICAgIH0KCiAgICBvdXRwdXRfZGV2aWNlX2luZGV4X2xvbmcgPQogICAgICBQeU51bWJlcl9Mb25nKG91dHB1dF9kZXZpY2VfaW5kZXhfYXJnKTsKICAgIG91dHB1dF9kZXZpY2VfaW5kZXggPSAoaW50KSBQeUxvbmdfQXNMb25nKG91dHB1dF9kZXZpY2VfaW5kZXhfbG9uZyk7CiAgICBQeV9ERUNSRUYob3V0cHV0X2RldmljZV9pbmRleF9sb25nKTsKCiNpZmRlZiBWRVJCT1NFCiAgICBwcmludGYoIlVzaW5nIG91dHB1dCBkZXZpY2UgaW5kZXggbnVtYmVyOiAlZFxuIiwgb3V0cHV0X2RldmljZV9pbmRleCk7CiNlbmRpZgogIH0KCiAgLyogc2FuaXR5IGNoZWNrcyAqLwogIGlmIChpbnB1dCA9PSAwICYmIG91dHB1dCA9PSAwKSB7CiAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfVmFsdWVFcnJvciwgIk11c3Qgc3BlY2lmeSBlaXRoZXIgaW5wdXQgb3Igb3V0cHV0Iik7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIGlmIChjaGFubmVscyA8IDEpIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19WYWx1ZUVycm9yLCAiSW52YWxpZCBhdWRpbyBjaGFubmVscyIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBpZiAob3V0cHV0KSB7CiAgICBvdXRwdXRQYXJhbWV0ZXJzID0KICAgICAgKFBhU3RyZWFtUGFyYW1ldGVycyAqKSBtYWxsb2Moc2l6ZW9mKFBhU3RyZWFtUGFyYW1ldGVycykpOwoKCiAgICBpZiAob3V0cHV0X2RldmljZV9pbmRleCA8IDApCiAgICAgIC8qIGRlZmF1bHQgb3V0cHV0IGRldmljZSAqLwogICAgICBvdXRwdXRQYXJhbWV0ZXJzLT5kZXZpY2UgPSBQYV9HZXREZWZhdWx0T3V0cHV0RGV2aWNlKCk7CiAgICBlbHNlCiAgICAgIG91dHB1dFBhcmFtZXRlcnMtPmRldmljZSA9IG91dHB1dF9kZXZpY2VfaW5kZXg7CgogICAgLyogZmluYWwgY2hlY2sgLS0gZW5zdXJlIHRoYXQgdGhlcmUgaXMgYSBkZWZhdWx0IGRldmljZSAqLwogICAgaWYgKG91dHB1dFBhcmFtZXRlcnMtPmRldmljZSA8IDAgfHwKICAgICAgICBvdXRwdXRQYXJhbWV0ZXJzLT5kZXZpY2UgPj0gUGFfR2V0RGV2aWNlQ291bnQoKSkgewogICAgICBmcmVlKG91dHB1dFBhcmFtZXRlcnMpOwogICAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgICAgIkludmFsaWQgb3V0cHV0IGRldmljZSAiCgkJCQkgICAgIihubyBkZWZhdWx0IG91dHB1dCBkZXZpY2UpIiwKCQkJCSAgICBwYUludmFsaWREZXZpY2UpKTsKICAgICAgcmV0dXJuIE5VTEw7CiAgICB9CgogICAgb3V0cHV0UGFyYW1ldGVycy0+Y2hhbm5lbENvdW50ID0gY2hhbm5lbHM7CiAgICBvdXRwdXRQYXJhbWV0ZXJzLT5zYW1wbGVGb3JtYXQgPSBmb3JtYXQ7CiAgICBvdXRwdXRQYXJhbWV0ZXJzLT5zdWdnZXN0ZWRMYXRlbmN5ID0KICAgICAgUGFfR2V0RGV2aWNlSW5mbyhvdXRwdXRQYXJhbWV0ZXJzLT5kZXZpY2UpLT5kZWZhdWx0TG93T3V0cHV0TGF0ZW5jeTsKICAgIG91dHB1dFBhcmFtZXRlcnMtPmhvc3RBcGlTcGVjaWZpY1N0cmVhbUluZm8gPSBOVUxMOwoKI2lmZGVmIE1BQ09TWAogICAgaWYgKG91dHB1dEhvc3RTcGVjaWZpY1N0cmVhbUluZm8pIHsKICAgICAgb3V0cHV0UGFyYW1ldGVycy0+aG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mbyA9CglvdXRwdXRIb3N0U3BlY2lmaWNTdHJlYW1JbmZvLT5wYU1hY0NvcmVTdHJlYW1JbmZvOwogICAgfQojZW5kaWYKCiAgfQoKICBpZiAoaW5wdXQpIHsKICAgIGlucHV0UGFyYW1ldGVycyA9CiAgICAgIChQYVN0cmVhbVBhcmFtZXRlcnMgKikgbWFsbG9jKHNpemVvZihQYVN0cmVhbVBhcmFtZXRlcnMpKTsKCiAgICBpZiAoaW5wdXRfZGV2aWNlX2luZGV4IDwgMCkgewogICAgICAvKiBkZWZhdWx0IG91dHB1dCBkZXZpY2UgKi8KICAgICAgaW5wdXRQYXJhbWV0ZXJzLT5kZXZpY2UgPSBQYV9HZXREZWZhdWx0SW5wdXREZXZpY2UoKTsKICAgIH0gZWxzZSB7CiAgICAgIGlucHV0UGFyYW1ldGVycy0+ZGV2aWNlID0gaW5wdXRfZGV2aWNlX2luZGV4OwogICAgfQoKICAgIC8qIGZpbmFsIGNoZWNrIC0tIGVuc3VyZSB0aGF0IHRoZXJlIGlzIGEgZGVmYXVsdCBkZXZpY2UgKi8KICAgIGlmIChpbnB1dFBhcmFtZXRlcnMtPmRldmljZSA8IDApIHsKICAgICAgZnJlZShpbnB1dFBhcmFtZXRlcnMpOwogICAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgICAgIkludmFsaWQgaW5wdXQgZGV2aWNlICIKCQkJCSAgICAiKG5vIGRlZmF1bHQgb3V0cHV0IGRldmljZSkiLAoJCQkJICAgIHBhSW52YWxpZERldmljZSkpOwogICAgICByZXR1cm4gTlVMTDsKICAgIH0KCiAgICBpbnB1dFBhcmFtZXRlcnMtPmNoYW5uZWxDb3VudCA9IGNoYW5uZWxzOwogICAgaW5wdXRQYXJhbWV0ZXJzLT5zYW1wbGVGb3JtYXQgPSBmb3JtYXQ7CiAgICBpbnB1dFBhcmFtZXRlcnMtPnN1Z2dlc3RlZExhdGVuY3kgPQogICAgICBQYV9HZXREZXZpY2VJbmZvKGlucHV0UGFyYW1ldGVycy0+ZGV2aWNlKS0+ZGVmYXVsdExvd0lucHV0TGF0ZW5jeTsKICAgIGlucHV0UGFyYW1ldGVycy0+aG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mbyA9IE5VTEw7CgojaWZkZWYgTUFDT1NYCiAgICBpZiAoaW5wdXRIb3N0U3BlY2lmaWNTdHJlYW1JbmZvKSB7CiAgICAgIGlucHV0UGFyYW1ldGVycy0+aG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mbyA9CglpbnB1dEhvc3RTcGVjaWZpY1N0cmVhbUluZm8tPnBhTWFjQ29yZVN0cmVhbUluZm87CiAgICB9CiNlbmRpZgoKICB9CgogIC8vIEhhbmRsZSBjYWxsYmFjayBtb2RlOgogIGlmIChzdHJlYW1fY2FsbGJhY2spIHsKICAgIFB5X0lOQ1JFRihzdHJlYW1fY2FsbGJhY2spOwogICAgY29udGV4dCA9IChQeUF1ZGlvQ2FsbGJhY2tDb250ZXh0ICopIG1hbGxvYyhzaXplb2YoUHlBdWRpb0NhbGxiYWNrQ29udGV4dCkpOwogICAgY29udGV4dC0+Y2FsbGJhY2sgPSAoUHlPYmplY3QgKikgc3RyZWFtX2NhbGxiYWNrOwogICAgY29udGV4dC0+bWFpbl90aHJlYWRfaWQgPSBQeVRocmVhZFN0YXRlX0dldCgpLT50aHJlYWRfaWQ7CiAgICBjb250ZXh0LT5mcmFtZV9zaXplID0gUGFfR2V0U2FtcGxlU2l6ZShmb3JtYXQpICogY2hhbm5lbHM7CiAgfQoKICBlcnIgPSBQYV9PcGVuU3RyZWFtKCZzdHJlYW0sCgkJICAgICAgLyogaW5wdXQvb3V0cHV0IHBhcmFtZXRlcnMgKi8KCQkgICAgICAvKiBOVUxMIHZhbHVlcyBhcmUgaWdub3JlZCAqLwoJCSAgICAgIGlucHV0UGFyYW1ldGVycywKCQkgICAgICBvdXRwdXRQYXJhbWV0ZXJzLAoJCSAgICAgIC8qIFNhbXBsZXMgUGVyIFNlY29uZCAqLwoJCSAgICAgIHJhdGUsCgkJICAgICAgLyogYWxsb2NhdGUgZnJhbWVzIGluIHRoZSBidWZmZXIgKi8KCQkgICAgICBmcmFtZXNfcGVyX2J1ZmZlciwKCQkgICAgICAvKiB3ZSB3b24ndCBvdXRwdXQgb3V0IG9mIHJhbmdlIHNhbXBsZXMKCQkJIHNvIGRvbid0IGJvdGhlciBjbGlwcGluZyB0aGVtICovCgkJICAgICAgcGFDbGlwT2ZmLAoJCSAgICAgIC8qIGNhbGxiYWNrLCBpZiBzcGVjaWZpZWQgKi8KCQkgICAgICAoc3RyZWFtX2NhbGxiYWNrKT8oX3N0cmVhbV9jYWxsYmFja19jZnVuY3Rpb24pOihOVUxMKSwKCQkgICAgICAvKiBjYWxsYmFjayB1c2VyRGF0YSwgaWYgYXBwbGljYWJsZSAqLwoJCSAgICAgIGNvbnRleHQpOwoKICBpZiAoZXJyICE9IHBhTm9FcnJvcikgewoKI2lmZGVmIFZFUkJPU0UKICAgIGZwcmludGYoc3RkZXJyLCAiQW4gZXJyb3Igb2NjdXJlZCB3aGlsZSB1c2luZyB0aGUgcG9ydGF1ZGlvIHN0cmVhbVxuIik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG51bWJlcjogJWRcbiIsIGVycik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG1lc3NhZ2U6ICVzXG4iLCBQYV9HZXRFcnJvclRleHQoZXJyKSk7CiNlbmRpZgoKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19JT0Vycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgIFBhX0dldEVycm9yVGV4dChlcnIpLCBlcnIpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgc3RyZWFtSW5mbyA9IChQYVN0cmVhbUluZm8gKikgUGFfR2V0U3RyZWFtSW5mbyhzdHJlYW0pOwogIGlmICghc3RyZWFtSW5mbykgewogICAgLyogUGFfVGVybWluYXRlKCk7ICovCiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAogCQkJCSAgIkNvdWxkIG5vdCBnZXQgc3RyZWFtIGluZm9ybWF0aW9uIiwKCQkJCSAgcGFJbnRlcm5hbEVycm9yKSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHN0cmVhbU9iamVjdCA9IF9jcmVhdGVfU3RyZWFtX29iamVjdCgpOwogIHN0cmVhbU9iamVjdC0+c3RyZWFtID0gc3RyZWFtOwogIHN0cmVhbU9iamVjdC0+aW5wdXRQYXJhbWV0ZXJzID0gaW5wdXRQYXJhbWV0ZXJzOwogIHN0cmVhbU9iamVjdC0+b3V0cHV0UGFyYW1ldGVycyA9IG91dHB1dFBhcmFtZXRlcnM7CiAgc3RyZWFtT2JqZWN0LT5pc19vcGVuID0gMTsKICBzdHJlYW1PYmplY3QtPnN0cmVhbUluZm8gPSBzdHJlYW1JbmZvOwogIHN0cmVhbU9iamVjdC0+Y2FsbGJhY2tDb250ZXh0ID0gY29udGV4dDsKCiAgcmV0dXJuIChQeU9iamVjdCAqKSBzdHJlYW1PYmplY3Q7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2Nsb3NlKFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewogIFB5T2JqZWN0ICpzdHJlYW1fYXJnOwogIF9weUF1ZGlvX1N0cmVhbSAqc3RyZWFtT2JqZWN0OwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgIk8hIiwgJl9weUF1ZGlvX1N0cmVhbVR5cGUsICZzdHJlYW1fYXJnKSkKICAgIHJldHVybiBOVUxMOwoKICBzdHJlYW1PYmplY3QgPSAoX3B5QXVkaW9fU3RyZWFtICopIHN0cmVhbV9hcmc7CgogIF9jbGVhbnVwX1N0cmVhbV9vYmplY3Qoc3RyZWFtT2JqZWN0KTsKCiAgUHlfSU5DUkVGKFB5X05vbmUpOwogIHJldHVybiBQeV9Ob25lOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpwYV9nZXRfc2FtcGxlX3NpemUoUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzKQp7CiAgUGFTYW1wbGVGb3JtYXQgZm9ybWF0OwogIGludCBzaXplX2luX2J5dGVzOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgImsiLCAmZm9ybWF0KSkKICAgIHJldHVybiBOVUxMOwoKICBzaXplX2luX2J5dGVzID0gUGFfR2V0U2FtcGxlU2l6ZShmb3JtYXQpOwoKICBpZiAoc2l6ZV9pbl9ieXRlcyA8IDApIHsKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19WYWx1ZUVycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgIFBhX0dldEVycm9yVGV4dChzaXplX2luX2J5dGVzKSwKCQkJCSAgc2l6ZV9pbl9ieXRlcykpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gUHlMb25nX0Zyb21Mb25nKHNpemVfaW5fYnl0ZXMpOwp9CgoKc3RhdGljIFB5T2JqZWN0ICoKcGFfaXNfZm9ybWF0X3N1cHBvcnRlZChQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MsCgkJICAgICAgIFB5T2JqZWN0ICprd2FyZ3MpCnsKICAvKiBwYXNzIGluIHJhdGUsIGNoYW5uZWwsIHdpZHRoICovCiAgc3RhdGljIGNoYXIgKmt3bGlzdFtdID0gewogICAgICAic2FtcGxlX3JhdGUiLAogICAgICAiaW5wdXRfZGV2aWNlIiwKICAgICAgImlucHV0X2NoYW5uZWxzIiwKICAgICAgImlucHV0X2Zvcm1hdCIsCiAgICAgICJvdXRwdXRfZGV2aWNlIiwKICAgICAgIm91dHB1dF9jaGFubmVscyIsCiAgICAgICJvdXRwdXRfZm9ybWF0IiwKICAgICAgTlVMTAogIH07CgogIGludCBpbnB1dF9kZXZpY2UsIGlucHV0X2NoYW5uZWxzOwogIGludCBvdXRwdXRfZGV2aWNlLCBvdXRwdXRfY2hhbm5lbHM7CiAgZmxvYXQgc2FtcGxlX3JhdGU7CiAgUGFTdHJlYW1QYXJhbWV0ZXJzIGlucHV0UGFyYW1zOwogIFBhU3RyZWFtUGFyYW1ldGVycyBvdXRwdXRQYXJhbXM7CiAgUGFTYW1wbGVGb3JtYXQgaW5wdXRfZm9ybWF0LCBvdXRwdXRfZm9ybWF0OwogIFBhRXJyb3IgZXJyb3I7CgogIGlucHV0X2RldmljZSA9IGlucHV0X2NoYW5uZWxzID0KICAgIG91dHB1dF9kZXZpY2UgPSBvdXRwdXRfY2hhbm5lbHMgPSAtMTsKCiAgaW5wdXRfZm9ybWF0ID0gb3V0cHV0X2Zvcm1hdCA9IC0xOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGVBbmRLZXl3b3JkcyhhcmdzLCBrd2FyZ3MsICJmfGlpa2lpayIsIGt3bGlzdCwKCQkJCSAgICZzYW1wbGVfcmF0ZSwKCQkJCSAgICZpbnB1dF9kZXZpY2UsCgkJCQkgICAmaW5wdXRfY2hhbm5lbHMsCgkJCQkgICAmaW5wdXRfZm9ybWF0LAoJCQkJICAgJm91dHB1dF9kZXZpY2UsCgkJCQkgICAmb3V0cHV0X2NoYW5uZWxzLAoJCQkJICAgJm91dHB1dF9mb3JtYXQpKQogICAgcmV0dXJuIE5VTEw7CgogIGlmICghKGlucHV0X2RldmljZSA8IDApKSB7CiAgICBpbnB1dFBhcmFtcy5kZXZpY2UgPSBpbnB1dF9kZXZpY2U7CiAgICBpbnB1dFBhcmFtcy5jaGFubmVsQ291bnQgPSBpbnB1dF9jaGFubmVsczsKICAgIGlucHV0UGFyYW1zLnNhbXBsZUZvcm1hdCA9IGlucHV0X2Zvcm1hdDsKICAgIGlucHV0UGFyYW1zLnN1Z2dlc3RlZExhdGVuY3kgPSAwOwogICAgaW5wdXRQYXJhbXMuaG9zdEFwaVNwZWNpZmljU3RyZWFtSW5mbyA9IE5VTEw7CiAgfQoKICBpZiAoIShvdXRwdXRfZGV2aWNlIDwgMCkpIHsKICAgIG91dHB1dFBhcmFtcy5kZXZpY2UgPSBvdXRwdXRfZGV2aWNlOwogICAgb3V0cHV0UGFyYW1zLmNoYW5uZWxDb3VudCA9IG91dHB1dF9jaGFubmVsczsKICAgIG91dHB1dFBhcmFtcy5zYW1wbGVGb3JtYXQgPSBvdXRwdXRfZm9ybWF0OwogICAgb3V0cHV0UGFyYW1zLnN1Z2dlc3RlZExhdGVuY3kgPSAwOwogICAgb3V0cHV0UGFyYW1zLmhvc3RBcGlTcGVjaWZpY1N0cmVhbUluZm8gPSBOVUxMOwogIH0KCiAgZXJyb3IgPSBQYV9Jc0Zvcm1hdFN1cHBvcnRlZCgoaW5wdXRfZGV2aWNlIDwgMCkgPyBOVUxMIDogJmlucHV0UGFyYW1zLAoJCQkgICAgICAgKG91dHB1dF9kZXZpY2UgPCAwKSA/IE5VTEwgOiAmb3V0cHV0UGFyYW1zLAoJCQkgICAgICAgc2FtcGxlX3JhdGUpOwoKICBpZiAoZXJyb3IgPT0gcGFGb3JtYXRJc1N1cHBvcnRlZCkgewogICAgUHlfSU5DUkVGKFB5X1RydWUpOwogICAgcmV0dXJuIFB5X1RydWU7CiAgfSBlbHNlIHsKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19WYWx1ZUVycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgIFBhX0dldEVycm9yVGV4dChlcnJvciksCgkJCQkgIGVycm9yKSk7CiAgICByZXR1cm4gTlVMTDsKICB9Cn0KCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqIFN0cmVhbSBTdGFydCAvIFN0b3AgLyBJbmZvCiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKc3RhdGljIFB5T2JqZWN0ICoKcGFfc3RhcnRfc3RyZWFtKFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewogIGludCBlcnI7CiAgUHlPYmplY3QgKnN0cmVhbV9hcmc7CiAgX3B5QXVkaW9fU3RyZWFtICpzdHJlYW1PYmplY3Q7CiAgUGFTdHJlYW0gKnN0cmVhbTsKCiAgaWYgKCFQeUFyZ19QYXJzZVR1cGxlKGFyZ3MsICJPISIsICZfcHlBdWRpb19TdHJlYW1UeXBlLCAmc3RyZWFtX2FyZykpCiAgICByZXR1cm4gTlVMTDsKCiAgc3RyZWFtT2JqZWN0ID0gKF9weUF1ZGlvX1N0cmVhbSAqKSBzdHJlYW1fYXJnOwoKICBpZiAoIV9pc19vcGVuKHN0cmVhbU9iamVjdCkpIHsKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19JT0Vycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgICJTdHJlYW0gY2xvc2VkIiwKCQkJCSAgcGFCYWRTdHJlYW1QdHIpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgc3RyZWFtID0gc3RyZWFtT2JqZWN0LT5zdHJlYW07CgogIGlmICggKChlcnIgPSBQYV9TdGFydFN0cmVhbShzdHJlYW0pKSAhPSBwYU5vRXJyb3IpICYmCiAgICAgICAoZXJyICE9IHBhU3RyZWFtSXNOb3RTdG9wcGVkKSkgewogICAgX2NsZWFudXBfU3RyZWFtX29iamVjdChzdHJlYW1PYmplY3QpOwoKI2lmZGVmIFZFUkJPU0UKICAgIGZwcmludGYoc3RkZXJyLCAiQW4gZXJyb3Igb2NjdXJlZCB3aGlsZSB1c2luZyB0aGUgcG9ydGF1ZGlvIHN0cmVhbVxuIik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG51bWJlcjogJWRcbiIsIGVycik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG1lc3NhZ2U6ICVzXG4iLCBQYV9HZXRFcnJvclRleHQoZXJyKSk7CiNlbmRpZgoKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19JT0Vycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgIFBhX0dldEVycm9yVGV4dChlcnIpLAoJCQkJICBlcnIpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgUHlfSU5DUkVGKFB5X05vbmUpOwogIHJldHVybiBQeV9Ob25lOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpwYV9zdG9wX3N0cmVhbShQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKCiAgaW50IGVycjsKICBQeU9iamVjdCAqc3RyZWFtX2FyZzsKICBfcHlBdWRpb19TdHJlYW0gKnN0cmVhbU9iamVjdDsKICBQYVN0cmVhbSAqc3RyZWFtOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgIk8hIiwgJl9weUF1ZGlvX1N0cmVhbVR5cGUsICZzdHJlYW1fYXJnKSkKICAgIHJldHVybiBOVUxMOwoKICBzdHJlYW1PYmplY3QgPSAoX3B5QXVkaW9fU3RyZWFtICopIHN0cmVhbV9hcmc7CgogIGlmICghX2lzX29wZW4oc3RyZWFtT2JqZWN0KSkgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0lPRXJyb3IsICJTdHJlYW0gbm90IG9wZW4iKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgc3RyZWFtID0gc3RyZWFtT2JqZWN0LT5zdHJlYW07CgogIFB5X0JFR0lOX0FMTE9XX1RIUkVBRFMKICBlcnIgPSBQYV9TdG9wU3RyZWFtKHN0cmVhbSk7CiAgUHlfRU5EX0FMTE9XX1RIUkVBRFMKCiAgaWYgKChlcnIgIT0gcGFOb0Vycm9yKSAmJiAoZXJyICE9IHBhU3RyZWFtSXNTdG9wcGVkKSkgewogICAgX2NsZWFudXBfU3RyZWFtX29iamVjdChzdHJlYW1PYmplY3QpOwoKI2lmZGVmIFZFUkJPU0UKICAgIGZwcmludGYoc3RkZXJyLCAiQW4gZXJyb3Igb2NjdXJlZCB3aGlsZSB1c2luZyB0aGUgcG9ydGF1ZGlvIHN0cmVhbVxuIik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG51bWJlcjogJWRcbiIsIGVycik7CiAgICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG1lc3NhZ2U6ICVzXG4iLCBQYV9HZXRFcnJvclRleHQoZXJyKSk7CiNlbmRpZgoKICAgIFB5RXJyX1NldE9iamVjdChQeUV4Y19JT0Vycm9yLAoJCSAgICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQkgIFBhX0dldEVycm9yVGV4dChlcnIpLAoJCQkJICBlcnIpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgUHlfSU5DUkVGKFB5X05vbmUpOwogIHJldHVybiBQeV9Ob25lOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpwYV9hYm9ydF9zdHJlYW0oUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzKQp7CiAgaW50IGVycjsKICBQeU9iamVjdCAqc3RyZWFtX2FyZzsKICBfcHlBdWRpb19TdHJlYW0gKnN0cmVhbU9iamVjdDsKICBQYVN0cmVhbSAqc3RyZWFtOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgIk8hIiwgJl9weUF1ZGlvX1N0cmVhbVR5cGUsICZzdHJlYW1fYXJnKSkKICAgIHJldHVybiBOVUxMOwoKICBzdHJlYW1PYmplY3QgPSAoX3B5QXVkaW9fU3RyZWFtICopIHN0cmVhbV9hcmc7CgogIGlmICghX2lzX29wZW4oc3RyZWFtT2JqZWN0KSkgewogICAgUHlFcnJfU2V0U3RyaW5nKFB5RXhjX0lPRXJyb3IsICJTdHJlYW0gbm90IG9wZW4iKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgc3RyZWFtID0gc3RyZWFtT2JqZWN0LT5zdHJlYW07CgogIFB5X0JFR0lOX0FMTE9XX1RIUkVBRFMKICBlcnIgPSBQYV9BYm9ydFN0cmVhbShzdHJlYW0pOwogIFB5X0VORF9BTExPV19USFJFQURTCgogIGlmICgoZXJyICE9IHBhTm9FcnJvcikgJiYgKGVyciAhPSBwYVN0cmVhbUlzU3RvcHBlZCkpIHsKICAgIF9jbGVhbnVwX1N0cmVhbV9vYmplY3Qoc3RyZWFtT2JqZWN0KTsKCiNpZmRlZiBWRVJCT1NFCiAgICBmcHJpbnRmKHN0ZGVyciwgIkFuIGVycm9yIG9jY3VyZWQgd2hpbGUgdXNpbmcgdGhlIHBvcnRhdWRpbyBzdHJlYW1cbiIpOwogICAgZnByaW50ZihzdGRlcnIsICJFcnJvciBudW1iZXI6ICVkXG4iLCBlcnIpOwogICAgZnByaW50ZihzdGRlcnIsICJFcnJvciBtZXNzYWdlOiAlc1xuIiwgUGFfR2V0RXJyb3JUZXh0KGVycikpOwojZW5kaWYKCiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICBQYV9HZXRFcnJvclRleHQoZXJyKSwKCQkJCSAgZXJyKSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIFB5X0lOQ1JFRihQeV9Ob25lKTsKICByZXR1cm4gUHlfTm9uZTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKcGFfaXNfc3RyZWFtX3N0b3BwZWQoUHlPYmplY3QgKnNlbGYsIFB5T2JqZWN0ICphcmdzKQp7CiAgaW50IGVycjsKICBQeU9iamVjdCAqc3RyZWFtX2FyZzsKICBfcHlBdWRpb19TdHJlYW0gKnN0cmVhbU9iamVjdDsKICBQYVN0cmVhbSAqc3RyZWFtOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgIk8hIiwgJl9weUF1ZGlvX1N0cmVhbVR5cGUsICZzdHJlYW1fYXJnKSkKICAgIHJldHVybiBOVUxMOwoKICBzdHJlYW1PYmplY3QgPSAoX3B5QXVkaW9fU3RyZWFtICopIHN0cmVhbV9hcmc7CgogIGlmICghX2lzX29wZW4oc3RyZWFtT2JqZWN0KSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIlN0cmVhbSBjbG9zZWQiLAoJCQkJICBwYUJhZFN0cmVhbVB0cikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBzdHJlYW0gPSBzdHJlYW1PYmplY3QtPnN0cmVhbTsKCiAgaWYgKChlcnIgPSBQYV9Jc1N0cmVhbVN0b3BwZWQoc3RyZWFtKSkgPCAwKSB7CiAgICBfY2xlYW51cF9TdHJlYW1fb2JqZWN0KHN0cmVhbU9iamVjdCk7CgojaWZkZWYgVkVSQk9TRQogICAgZnByaW50ZihzdGRlcnIsICJBbiBlcnJvciBvY2N1cmVkIHdoaWxlIHVzaW5nIHRoZSBwb3J0YXVkaW8gc3RyZWFtXG4iKTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbnVtYmVyOiAlZFxuIiwgZXJyKTsKICAgIGZwcmludGYoc3RkZXJyLCAiRXJyb3IgbWVzc2FnZTogJXNcbiIsIFBhX0dldEVycm9yVGV4dChlcnIpKTsKI2VuZGlmCgogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgUGFfR2V0RXJyb3JUZXh0KGVyciksCgkJCQkgIGVycikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBpZiAoZXJyKSB7CiAgICBQeV9JTkNSRUYoUHlfVHJ1ZSk7CiAgICByZXR1cm4gUHlfVHJ1ZTsKICB9CgogIFB5X0lOQ1JFRihQeV9GYWxzZSk7CiAgcmV0dXJuIFB5X0ZhbHNlOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpwYV9pc19zdHJlYW1fYWN0aXZlKFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewoKICBpbnQgZXJyOwogIFB5T2JqZWN0ICpzdHJlYW1fYXJnOwogIF9weUF1ZGlvX1N0cmVhbSAqc3RyZWFtT2JqZWN0OwogIFBhU3RyZWFtICpzdHJlYW07CgogIGlmICghUHlBcmdfUGFyc2VUdXBsZShhcmdzLCAiTyEiLCAmX3B5QXVkaW9fU3RyZWFtVHlwZSwgJnN0cmVhbV9hcmcpKQogICAgcmV0dXJuIE5VTEw7CgogIHN0cmVhbU9iamVjdCA9IChfcHlBdWRpb19TdHJlYW0gKikgc3RyZWFtX2FyZzsKCiAgaWYgKCFfaXNfb3BlbihzdHJlYW1PYmplY3QpKSB7CiAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfSU9FcnJvciwgIlN0cmVhbSBub3Qgb3BlbiIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBzdHJlYW0gPSBzdHJlYW1PYmplY3QtPnN0cmVhbTsKCiAgaWYgKChlcnIgPSBQYV9Jc1N0cmVhbUFjdGl2ZShzdHJlYW0pKSA8IDApIHsKICAgIF9jbGVhbnVwX1N0cmVhbV9vYmplY3Qoc3RyZWFtT2JqZWN0KTsKCiNpZmRlZiBWRVJCT1NFCiAgICBmcHJpbnRmKHN0ZGVyciwgIkFuIGVycm9yIG9jY3VyZWQgd2hpbGUgdXNpbmcgdGhlIHBvcnRhdWRpbyBzdHJlYW1cbiIpOwogICAgZnByaW50ZihzdGRlcnIsICJFcnJvciBudW1iZXI6ICVkXG4iLCBlcnIpOwogICAgZnByaW50ZihzdGRlcnIsICJFcnJvciBtZXNzYWdlOiAlc1xuIiwgUGFfR2V0RXJyb3JUZXh0KGVycikpOwojZW5kaWYKCiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICBQYV9HZXRFcnJvclRleHQoZXJyKSwKCQkJCSAgZXJyKSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIGlmIChlcnIpIHsKICAgIFB5X0lOQ1JFRihQeV9UcnVlKTsKICAgIHJldHVybiBQeV9UcnVlOwogIH0KCiAgUHlfSU5DUkVGKFB5X0ZhbHNlKTsKICByZXR1cm4gUHlfRmFsc2U7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2dldF9zdHJlYW1fdGltZShQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBkb3VibGUgdGltZTsKICBQeU9iamVjdCAqc3RyZWFtX2FyZzsKICBfcHlBdWRpb19TdHJlYW0gKnN0cmVhbU9iamVjdDsKICBQYVN0cmVhbSAqc3RyZWFtOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgIk8hIiwgJl9weUF1ZGlvX1N0cmVhbVR5cGUsICZzdHJlYW1fYXJnKSkKICAgIHJldHVybiBOVUxMOwoKICBzdHJlYW1PYmplY3QgPSAoX3B5QXVkaW9fU3RyZWFtICopIHN0cmVhbV9hcmc7CgogIGlmICghX2lzX29wZW4oc3RyZWFtT2JqZWN0KSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIlN0cmVhbSBjbG9zZWQiLAoJCQkJICBwYUJhZFN0cmVhbVB0cikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBzdHJlYW0gPSBzdHJlYW1PYmplY3QtPnN0cmVhbTsKCiAgaWYgKCh0aW1lID0gUGFfR2V0U3RyZWFtVGltZShzdHJlYW0pKSA9PSAwKSB7CiAgICBfY2xlYW51cF9TdHJlYW1fb2JqZWN0KHN0cmVhbU9iamVjdCk7CiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICAiSW50ZXJuYWwgRXJyb3IiLAoJCQkJICBwYUludGVybmFsRXJyb3IpKTsKICAgIHJldHVybiBOVUxMOwogIH0KCiAgcmV0dXJuIFB5RmxvYXRfRnJvbURvdWJsZSh0aW1lKTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKcGFfZ2V0X3N0cmVhbV9jcHVfbG9hZChQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBQeU9iamVjdCAqc3RyZWFtX2FyZzsKICBfcHlBdWRpb19TdHJlYW0gKnN0cmVhbU9iamVjdDsKICBQYVN0cmVhbSAqc3RyZWFtOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgIk8hIiwgJl9weUF1ZGlvX1N0cmVhbVR5cGUsICZzdHJlYW1fYXJnKSkKICAgIHJldHVybiBOVUxMOwoKICBzdHJlYW1PYmplY3QgPSAoX3B5QXVkaW9fU3RyZWFtICopIHN0cmVhbV9hcmc7CgogIGlmICghX2lzX29wZW4oc3RyZWFtT2JqZWN0KSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIlN0cmVhbSBjbG9zZWQiLAoJCQkJICBwYUJhZFN0cmVhbVB0cikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBzdHJlYW0gPSBzdHJlYW1PYmplY3QtPnN0cmVhbTsKICByZXR1cm4gUHlGbG9hdF9Gcm9tRG91YmxlKFBhX0dldFN0cmVhbUNwdUxvYWQoc3RyZWFtKSk7Cn0KCgovKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKiBTdHJlYW0gUmVhZC9Xcml0ZQogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCnN0YXRpYyBQeU9iamVjdCAqCnBhX3dyaXRlX3N0cmVhbShQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBjb25zdCBjaGFyICpkYXRhOwogIGludCB0b3RhbF9zaXplOwogIGludCB0b3RhbF9mcmFtZXM7CiAgaW50IGVycjsKICBpbnQgc2hvdWxkX3Rocm93X2V4Y2VwdGlvbiA9IDA7CgogIFB5T2JqZWN0ICpzdHJlYW1fYXJnOwogIF9weUF1ZGlvX1N0cmVhbSAqc3RyZWFtT2JqZWN0OwogIFBhU3RyZWFtICpzdHJlYW07CgogIGlmICghUHlBcmdfUGFyc2VUdXBsZShhcmdzLCAiTyFzI2l8aSIsCgkJCSZfcHlBdWRpb19TdHJlYW1UeXBlLAoJCQkmc3RyZWFtX2FyZywKCQkJJmRhdGEsCgkJCSZ0b3RhbF9zaXplLAoJCQkmdG90YWxfZnJhbWVzLAoJCQkmc2hvdWxkX3Rocm93X2V4Y2VwdGlvbikpCiAgICByZXR1cm4gTlVMTDsKCiAgLyogbWFrZSBzdXJlIHRvdGFsIGZyYW1lcyBpcyBsYXJnZXIgdGhhbiAwICovCiAgaWYgKHRvdGFsX2ZyYW1lcyA8IDApIHsKICAgIFB5RXJyX1NldFN0cmluZyhQeUV4Y19WYWx1ZUVycm9yLAoJCSAgICAiSW52YWxpZCBudW1iZXIgb2YgZnJhbWVzIik7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHN0cmVhbU9iamVjdCA9IChfcHlBdWRpb19TdHJlYW0gKikgc3RyZWFtX2FyZzsKCiAgaWYgKCFfaXNfb3BlbihzdHJlYW1PYmplY3QpKSB7CiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICAiU3RyZWFtIGNsb3NlZCIsCgkJCQkgIHBhQmFkU3RyZWFtUHRyKSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIHN0cmVhbSA9IHN0cmVhbU9iamVjdC0+c3RyZWFtOwoKICBQeV9CRUdJTl9BTExPV19USFJFQURTCiAgZXJyID0gUGFfV3JpdGVTdHJlYW0oc3RyZWFtLCBkYXRhLCB0b3RhbF9mcmFtZXMpOwogIFB5X0VORF9BTExPV19USFJFQURTCgogIGlmIChlcnIgIT0gcGFOb0Vycm9yKSB7CiAgICBpZiAoZXJyID09IHBhT3V0cHV0VW5kZXJmbG93ZWQpIHsKICAgICAgaWYgKHNob3VsZF90aHJvd19leGNlcHRpb24pCglnb3RvIGVycm9yOwogICAgfSBlbHNlCiAgICAgIGdvdG8gZXJyb3I7CiAgfQoKICBQeV9JTkNSRUYoUHlfTm9uZSk7CiAgcmV0dXJuIFB5X05vbmU7CgogZXJyb3I6CiAgLyogY2xlYW51cCAqLwogIF9jbGVhbnVwX1N0cmVhbV9vYmplY3Qoc3RyZWFtT2JqZWN0KTsKCiNpZmRlZiBWRVJCT1NFCiAgZnByaW50ZihzdGRlcnIsICJBbiBlcnJvciBvY2N1cmVkIHdoaWxlIHVzaW5nIHRoZSBwb3J0YXVkaW8gc3RyZWFtXG4iKTsKICBmcHJpbnRmKHN0ZGVyciwgIkVycm9yIG51bWJlcjogJWRcbiIsIGVycik7CiAgZnByaW50ZihzdGRlcnIsICJFcnJvciBtZXNzYWdlOiAlc1xuIiwgUGFfR2V0RXJyb3JUZXh0KGVycikpOwojZW5kaWYKCiAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICBQeV9CdWlsZFZhbHVlKCIocyxpKSIsCgkJCQlQYV9HZXRFcnJvclRleHQoZXJyKSwKCQkJCWVycikpOwogIHJldHVybiBOVUxMOwp9CgpzdGF0aWMgUHlPYmplY3QgKgpwYV9yZWFkX3N0cmVhbShQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBpbnQgZXJyOwogIGludCB0b3RhbF9mcmFtZXM7CiAgc2hvcnQgKnNhbXBsZUJsb2NrOwogIGludCBudW1fYnl0ZXM7CiAgUHlPYmplY3QgKnJ2OwoKICBQeU9iamVjdCAqc3RyZWFtX2FyZzsKICBfcHlBdWRpb19TdHJlYW0gKnN0cmVhbU9iamVjdDsKICBQYVN0cmVhbSAqc3RyZWFtOwogIFBhU3RyZWFtUGFyYW1ldGVycyAqaW5wdXRQYXJhbWV0ZXJzOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgIk8haSIsCgkJCSZfcHlBdWRpb19TdHJlYW1UeXBlLAoJCQkmc3RyZWFtX2FyZywKCQkJJnRvdGFsX2ZyYW1lcykpCiAgICByZXR1cm4gTlVMTDsKCiAgLyogbWFrZSBzdXJlIHZhbHVlIGlzIHBvc2l0aXZlISAqLwogIGlmICh0b3RhbF9mcmFtZXMgPCAwKSB7CiAgICBQeUVycl9TZXRTdHJpbmcoUHlFeGNfVmFsdWVFcnJvciwgIkludmFsaWQgbnVtYmVyIG9mIGZyYW1lcyIpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBzdHJlYW1PYmplY3QgPSAoX3B5QXVkaW9fU3RyZWFtICopIHN0cmVhbV9hcmc7CgogIGlmICghX2lzX29wZW4oc3RyZWFtT2JqZWN0KSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIlN0cmVhbSBjbG9zZWQiLAoJCQkJICBwYUJhZFN0cmVhbVB0cikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBzdHJlYW0gPSBzdHJlYW1PYmplY3QtPnN0cmVhbTsKICBpbnB1dFBhcmFtZXRlcnMgPSBzdHJlYW1PYmplY3QtPmlucHV0UGFyYW1ldGVyczsKICBudW1fYnl0ZXMgPSAodG90YWxfZnJhbWVzKSAqIChpbnB1dFBhcmFtZXRlcnMtPmNoYW5uZWxDb3VudCkgKgogICAgKFBhX0dldFNhbXBsZVNpemUoaW5wdXRQYXJhbWV0ZXJzLT5zYW1wbGVGb3JtYXQpKTsKCiNpZmRlZiBWRVJCT1NFCiAgZnByaW50ZihzdGRlcnIsICJBbGxvY2F0aW5nICVkIGJ5dGVzXG4iLCBudW1fYnl0ZXMpOwojZW5kaWYKCiAgcnYgPSBQeUJ5dGVzX0Zyb21TdHJpbmdBbmRTaXplKE5VTEwsIG51bV9ieXRlcyk7CiAgc2FtcGxlQmxvY2sgPSAoc2hvcnQgKikgUHlCeXRlc19Bc1N0cmluZyhydik7CgogIGlmIChzYW1wbGVCbG9jayA9PSBOVUxMKSB7CiAgICBQeUVycl9TZXRPYmplY3QoUHlFeGNfSU9FcnJvciwKCQkgICAgUHlfQnVpbGRWYWx1ZSgiKHMsaSkiLAoJCQkJICAiT3V0IG9mIG1lbW9yeSIsCgkJCQkgIHBhSW5zdWZmaWNpZW50TWVtb3J5KSk7CiAgICByZXR1cm4gTlVMTDsKICB9CgogIFB5X0JFR0lOX0FMTE9XX1RIUkVBRFMKICBlcnIgPSBQYV9SZWFkU3RyZWFtKHN0cmVhbSwgc2FtcGxlQmxvY2ssIHRvdGFsX2ZyYW1lcyk7CiAgUHlfRU5EX0FMTE9XX1RIUkVBRFMKCiAgaWYgKGVyciAhPSBwYU5vRXJyb3IpIHsKCiAgICAvKiBpZ25vcmUgaW5wdXQgb3ZlcmZsb3cgYW5kIG91dHB1dCB1bmRlcmZsb3cgKi8KICAgIGlmIChlcnIgJiBwYUlucHV0T3ZlcmZsb3dlZCkgewoKI2lmZGVmIFZFUkJPU0UKICAgICAgZnByaW50ZihzdGRlcnIsICJJbnB1dCBPdmVyZmxvdy5cbiIpOwojZW5kaWYKCiAgICB9IGVsc2UgaWYgKGVyciAmIHBhT3V0cHV0VW5kZXJmbG93ZWQpIHsKCiNpZmRlZiBWRVJCT1NFCiAgICAgIGZwcmludGYoc3RkZXJyLCAiT3V0cHV0IFVuZGVyZmxvdy5cbiIpOwojZW5kaWYKCiAgICB9IGVsc2UgewogICAgICAvKiBjbGVhbiB1cCAqLwogICAgICBfY2xlYW51cF9TdHJlYW1fb2JqZWN0KHN0cmVhbU9iamVjdCk7CiAgICB9CgogICAgLyogZnJlZSB0aGUgc3RyaW5nIGJ1ZmZlciAqLwogICAgUHlfWERFQ1JFRihydik7CgogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgUGFfR2V0RXJyb3JUZXh0KGVyciksIGVycikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICByZXR1cm4gcnY7Cn0KCnN0YXRpYyBQeU9iamVjdCAqCnBhX2dldF9zdHJlYW1fd3JpdGVfYXZhaWxhYmxlKFB5T2JqZWN0ICpzZWxmLCBQeU9iamVjdCAqYXJncykKewogIHNpZ25lZCBsb25nIGZyYW1lczsKICBQeU9iamVjdCAqc3RyZWFtX2FyZzsKICBfcHlBdWRpb19TdHJlYW0gKnN0cmVhbU9iamVjdDsKICBQYVN0cmVhbSAqc3RyZWFtOwoKICBpZiAoIVB5QXJnX1BhcnNlVHVwbGUoYXJncywgIk8hIiwgJl9weUF1ZGlvX1N0cmVhbVR5cGUsICZzdHJlYW1fYXJnKSkKICAgIHJldHVybiBOVUxMOwoKICBzdHJlYW1PYmplY3QgPSAoX3B5QXVkaW9fU3RyZWFtICopIHN0cmVhbV9hcmc7CgogIGlmICghX2lzX29wZW4oc3RyZWFtT2JqZWN0KSkgewogICAgUHlFcnJfU2V0T2JqZWN0KFB5RXhjX0lPRXJyb3IsCgkJICAgIFB5X0J1aWxkVmFsdWUoIihzLGkpIiwKCQkJCSAgIlN0cmVhbSBjbG9zZWQiLAoJCQkJICBwYUJhZFN0cmVhbVB0cikpOwogICAgcmV0dXJuIE5VTEw7CiAgfQoKICBzdHJlYW0gPSBzdHJlYW1PYmplY3QtPnN0cmVhbTsKICBmcmFtZXMgPSBQYV9HZXRTdHJlYW1Xcml0ZUF2YWlsYWJsZShzdHJlYW0pOwogIHJldHVybiBQeUxvbmdfRnJvbUxvbmcoZnJhbWVzKTsKfQoKc3RhdGljIFB5T2JqZWN0ICoKcGFfZ2V0X3N0cmVhbV9yZWFkX2F2YWlsYWJsZShQeU9iamVjdCAqc2VsZiwgUHlPYmplY3QgKmFyZ3MpCnsKICBzaWduZWQgbG9uZyBmcmFtZXM7CiAg