void xnLogGetMasksString(XnChar* csString)
{
	switch (g_logData.m_nLogFilteringType)
	{
	case XN_LOG_WRITE_NONE:
		xnOSStrCopy(csString, "NONE", XN_LOG_MASKS_STRING_LEN);
		return;
	case XN_LOG_WRITE_ALL:
		xnOSStrCopy(csString, "ALL", XN_LOG_MASKS_STRING_LEN);
		return;
	case XN_LOG_WRITE_MASKS:
		{
			csString[0] = '\0';

			for (XnStringsHash::Iterator it = g_logData.m_LogMasks.begin(); it != g_logData.m_LogMasks.end(); ++it)
			{
				xnOSStrAppend(csString, it.Key(), XN_LOG_MASKS_STRING_LEN);
				xnOSStrAppend(csString, ";", XN_LOG_MASKS_STRING_LEN);
			}

			return;
		}
	default:
		xnOSStrCopy(csString, "UNKNOWN", XN_LOG_MASKS_STRING_LEN);
		return;
	}
}
XnStatus XnDeviceBase::GetSupportedStreams(const XnChar** aStreamNames, XnUInt32* pnStreamNamesCount)
{
	XN_VALIDATE_OUTPUT_PTR(pnStreamNamesCount);
	// NOTE: we allow aStreamName to be NULL

	// first of all count streams
	XnUInt32 nStreamsCount = m_SupportedStreams.Size();

	// now check if we have enough room
	if (nStreamsCount > *pnStreamNamesCount)
	{
		*pnStreamNamesCount = nStreamsCount;
		return XN_STATUS_OUTPUT_BUFFER_OVERFLOW;
	}

	// now copy values
	nStreamsCount = 0;
	for (XnStringsHash::Iterator it = m_SupportedStreams.begin(); it != m_SupportedStreams.end(); ++it)
	{
		aStreamNames[nStreamsCount] = it.Key();
		nStreamsCount++;
	}

	*pnStreamNamesCount = nStreamsCount;
	return XN_STATUS_OK;
}
XnStatus XnDeviceBase::GetStreamNames(const XnChar** pstrNames, XnUInt32* pnNamesCount)
{
	// first we need to count them
	XnUInt32 nCount = 0;

	for (XnStringsHash::Iterator it = m_Modules.begin(); it != m_Modules.end(); ++it)
	{
		XnDeviceModuleHolder* pModuleHolder = (XnDeviceModuleHolder*)it.Value();
		if (IsStream(pModuleHolder->GetModule()))
		{
			nCount++;
		}
	}

	if (nCount > *pnNamesCount)
	{
		*pnNamesCount = nCount;
		return XN_STATUS_OUTPUT_BUFFER_OVERFLOW;
	}

	// OK. we have enough space. Copy into it
	nCount = 0;
	for (XnStringsHash::Iterator it = m_Modules.begin(); it != m_Modules.end(); ++it)
	{
		XnDeviceModuleHolder* pModuleHolder = (XnDeviceModuleHolder*)it.Value();
		if (IsStream(pModuleHolder->GetModule()))
		{
			pstrNames[nCount] = it.Key();
			nCount++;
		}
	}

	*pnNamesCount = nCount;

	return XN_STATUS_OK;
}
XnStatus XnFileDevice::HandleStreamRemoved(const XnChar* strName)
{
	XnStatus nRetVal = XN_STATUS_OK;

	// check for specific case: all streams are removed and then end-of-file is reached.
	// in this case, we don't really want to destroy streams, just wrap around.
	XnStringsHash StreamsToRemove;
	nRetVal = StreamsToRemove.Set(strName, NULL);
	XN_IS_STATUS_OK(nRetVal);

	XnPackedDataType nType = XN_PACKED_STREAM_REMOVED;
	XnUInt32 nPositionBefore;

	while (TRUE)
	{
		nRetVal = m_pInputStream->Tell(&nPositionBefore);
		XN_IS_STATUS_OK(nRetVal);

		nRetVal = m_pDataPacker->ReadNextObject(&nType);
		XN_IS_STATUS_OK(nRetVal);

		if (nType == XN_PACKED_STREAM_REMOVED)
		{
			XnChar strTempName[XN_DEVICE_MAX_STRING_LENGTH];
			nRetVal = m_pDataPacker->ReadStreamRemoved(strTempName);
			XN_IS_STATUS_OK(nRetVal);

			nRetVal = StreamsToRemove.Set(strTempName, NULL);
			XN_IS_STATUS_OK(nRetVal);
		}
		else
		{
			break;
		}
	}

	if (nType != XN_PACKED_END)
	{
		// Not the case we were looking for. Remove those streams.
		for (XnStringsHash::Iterator it = StreamsToRemove.begin(); it != StreamsToRemove.end(); ++it)
		{
			nRetVal = m_pNotifications->OnNodeRemoved(m_pNotificationsCookie, it.Key());
			XN_IS_STATUS_OK(nRetVal);

			XnNodeInfo* pNodeInfo;
			m_nodeInfoMap.Get(it.Key(), pNodeInfo);
			XN_DELETE(pNodeInfo->pXnCodec);
			m_nodeInfoMap.Remove(it.Key());
			m_ignoreNewNodes.Remove(it.Key());
		}

		m_bNodeCollectionChanged = TRUE;
	}

	// in any case, the last object we read wasn't handled yet (end-of-stream or another event), so
	// seek back, so it will be handled.
	nRetVal = m_pInputStream->Seek(nPositionBefore);
	XN_IS_STATUS_OK(nRetVal);

	return (XN_STATUS_OK);
}