Example #1
0
XN_C_API XnStatus xnLogInitFromINIFile(const XnChar* cpINIFileName, const XnChar* cpSectionName)
{
	XnStatus nRetVal = XN_STATUS_OK;
	XnInt32 nTemp;

	// read filters
	xnLogReadMasksFromINI(cpINIFileName, cpSectionName, "LogMasks", xnLogBCSetMaskState);
	xnLogReadMasksFromINI(cpINIFileName, cpSectionName, "DumpMasks", xnDumpSetMaskState);

	//Test if log redirection is needed 
	XnChar strLogPath[XN_FILE_MAX_PATH] = {0};
	nRetVal = xnOSReadStringFromINI(cpINIFileName, cpSectionName, "LogPath", strLogPath, XN_FILE_MAX_PATH);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetOutputFolder(strLogPath);
		XN_IS_STATUS_OK(nRetVal);
	}

	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "Verbosity", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetMaskMinSeverity(XN_LOG_MASK_ALL, (XnLogSeverity)nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}

	// configure writers
	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "LogToConsole", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetConsoleOutput(nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}

	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "LogToFile", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetFileOutput(nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}

#if XN_PLATFORM == XN_PLATFORM_ANDROID_ARM
	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "LogToAndroidLog", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetAndroidOutput(nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}
#endif

	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "LogLineInfo", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetLineInfo(nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}

	return XN_STATUS_OK;
}
// TODO: check this is working and use it with ONI recordings??
void ofxOpenNIContext::enableLogging() {
	
	XnStatus result = xnLogSetConsoleOutput(true);
	SHOW_RC(result, "Set console output");
	
	result = xnLogSetSeverityFilter(XN_LOG_ERROR);	// TODO: set different log levels with code; enable and disable functionality
	SHOW_RC(result, "Set log level");

	xnLogSetMaskState(XN_LOG_MASK_ALL, TRUE);
	
}
Example #3
0
XN_C_API XnStatus xnLogInitFromINIFile(const XnChar* cpINIFileName, const XnChar* cpSectionName)
{
	XnStatus nRetVal = XN_STATUS_OK;
	XnUInt32 nTemp;

	nRetVal = xnLogInitSystem();
	XN_IS_STATUS_OK(nRetVal);

	// read filters
	xnLogReadMasksFromINI(cpINIFileName, cpSectionName, "LogMasks", xnLogSetMaskState);
	xnLogReadMasksFromINI(cpINIFileName, cpSectionName, "DumpMasks", xnDumpSetMaskState);

	g_logData.m_nFilterSeverity = XN_LOG_ERROR;
	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "LogLevel", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetSeverityFilter((XnLogSeverity)nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}

	// configure writers
	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "LogWriteToConsole", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetConsoleOutput(nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}

	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "LogWriteToFile", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetFileOutput(nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}

	nRetVal = xnOSReadIntFromINI(cpINIFileName, cpSectionName, "LogWriteLineInfo", &nTemp);
	if (nRetVal == XN_STATUS_OK)
	{
		nRetVal = xnLogSetLineInfo(nTemp);
		XN_IS_STATUS_OK(nRetVal);
	}

	return XN_STATUS_OK;
}
Example #4
0
int main(XnInt argc, XnChar* argv[])
{
	const XnChar* strFilePath = NULL;
	const XnChar* strConfigDir = NULL;
	XnBool bRegister = TRUE;
	XnBool bVerbose = FALSE;
	XnBool bList = FALSE;

	if (argc > 1 && strcmp(argv[1], "-l") == 0)
	{
		bList = TRUE;
	}
	else
	{
		for (int i = 1; i < argc; ++i)
		{
			const XnChar* arg = argv[i];
			if (arg[0] == '-')
			{
				if (arg[2] != '\0')
				{
					printUsage(argv[0]);
					return -1;
				}

				switch (arg[1])
				{
				case 'r':
					bRegister = TRUE;
					break;
				case 'u':
					bRegister = FALSE;
					break;
				case 'v':
					bVerbose = TRUE;
					break;
				default:
					printf("Unknown option: -%c\n", arg[1]);
					printUsage(argv[0]);
					return -1;
				}
			}
			else if (strFilePath == NULL)
			{
				strFilePath = arg;
			}
			else if (strConfigDir == NULL)
			{
				strConfigDir = arg;
			}
			else
			{
				printUsage(argv[0]);
				return -1;
			}
		} // args for

		if (strFilePath == NULL)
		{
			printUsage(argv[0]);
			return -1;
		}
	}

	xnLogInitSystem();
	xnLogSetConsoleOutput(bVerbose || bList);
	xnLogSetMaskMinSeverity(XN_LOG_MASK_ALL, bVerbose ? XN_LOG_VERBOSE : XN_LOG_WARNING);

	XnStatus nRetVal = XN_STATUS_OK;
	if (bList)
	{
		nRetVal = xnPrintRegisteredModules();
	}
	else if (bRegister)
	{
		nRetVal = xnRegisterModule(strFilePath, strConfigDir);
	}
	else
	{
		nRetVal = xnUnregisterModule(strFilePath);
	}

	if (nRetVal != XN_STATUS_OK)
	{
		printf("Failed: %s\n", xnGetStatusString(nRetVal));
		return -1;
	}

	if (bVerbose)
	{
		printf("Done.\n");
	}

	return 0;
}
Example #5
0
XN_C_API XnStatus xnLogInitFromXmlFile(const XnChar* strFileName)
{
	XnStatus nRetVal = XN_STATUS_OK;

	nRetVal = xnLogInitSystem();
	XN_IS_STATUS_OK(nRetVal);

	TiXmlDocument doc;
	nRetVal = xnXmlLoadDocument(doc, strFileName);
	XN_IS_STATUS_OK(nRetVal);

	TiXmlElement* pRootElem = doc.RootElement();
	if (pRootElem != NULL)
	{
		TiXmlElement* pLog = pRootElem->FirstChildElement("Log");
		if (pLog != NULL)
		{
			XnBool bOn;

			// configure filters
			TiXmlElement* pLogLevel = pLog->FirstChildElement("LogLevel");
			if (pLogLevel != NULL)
			{
				XnInt nValue;
				nRetVal = xnXmlReadIntAttribute(pLogLevel, "value", &nValue);
				XN_IS_STATUS_OK(nRetVal);

				nRetVal = xnLogSetSeverityFilter((XnLogSeverity)nValue);
				XN_IS_STATUS_OK(nRetVal);
			}

			TiXmlElement* pMasks = pLog->FirstChildElement("Masks");
			if (pMasks != NULL)
			{
				TiXmlElement* pMask = pMasks->FirstChildElement("Mask");
				while (pMask != NULL)
				{
					const XnChar* strName;
					nRetVal = xnXmlReadStringAttribute(pMask, "name", &strName);
					XN_IS_STATUS_OK(nRetVal);

					nRetVal = xnXmlReadBoolAttribute(pMask, "on", &bOn);
					XN_IS_STATUS_OK(nRetVal);

					nRetVal = xnLogSetMaskState(strName, bOn);
					XN_IS_STATUS_OK(nRetVal);

					pMask = pMask->NextSiblingElement("Mask");
				}
			}

			// configure writers
			if (pLog->Attribute("writeToConsole"))
			{
				nRetVal = xnXmlReadBoolAttribute(pLog, "writeToConsole", &bOn);
				XN_IS_STATUS_OK(nRetVal);

				nRetVal = xnLogSetConsoleOutput(bOn);
				XN_IS_STATUS_OK(nRetVal);
			}

			if (pLog->Attribute("writeToFile"))
			{
				nRetVal = xnXmlReadBoolAttribute(pLog, "writeToFile", &bOn);
				XN_IS_STATUS_OK(nRetVal);

				nRetVal = xnLogSetFileOutput(bOn);
				XN_IS_STATUS_OK(nRetVal);
			}

			if (pLog->Attribute("writeLineInfo"))
			{
				nRetVal = xnXmlReadBoolAttribute(pLog, "writeLineInfo", &bOn);
				XN_IS_STATUS_OK(nRetVal);

				nRetVal = xnLogSetLineInfo(bOn);
				XN_IS_STATUS_OK(nRetVal);
			}

			// Dumps
			TiXmlElement* pDumps = pLog->FirstChildElement("Dumps");
			if (pDumps != NULL)
			{
				TiXmlElement* pDump = pDumps->FirstChildElement("Dump");
				while (pDump != NULL)
				{
					const XnChar* strName;
					nRetVal = xnXmlReadStringAttribute(pDump, "name", &strName);
					XN_IS_STATUS_OK(nRetVal);

					nRetVal = xnXmlReadBoolAttribute(pDump, "on", &bOn);
					XN_IS_STATUS_OK(nRetVal);

					nRetVal = xnDumpSetMaskState(strName, bOn);
					XN_IS_STATUS_OK(nRetVal);

					pDump = pDump->NextSiblingElement("Dump");
				}
			}
		}
	}

	return (XN_STATUS_OK);
}
Example #6
0
OniStatus Context::initialize()
{
	XnBool repositoryOverridden = FALSE;
	XnChar repositoryFromINI[XN_FILE_MAX_PATH] = {0};

	m_initializationCounter++;
	if (m_initializationCounter > 1)
	{
		xnLogVerbose(XN_MASK_ONI_CONTEXT, "Initialize: Already initialized");
		return ONI_STATUS_OK;
	}

	XnStatus rc;

	XnChar strModulePath[XN_FILE_MAX_PATH];
	rc = xnOSGetModulePathForProcAddress(reinterpret_cast<void*>(&dummyFunctionToTakeAddress), strModulePath);
	if (rc != XN_STATUS_OK)
	{
		m_errorLogger.Append("Couldn't get the OpenNI shared library module's path: %s", xnGetStatusString(rc));
		return OniStatusFromXnStatus(rc);
	}

	XnChar strBaseDir[XN_FILE_MAX_PATH];
	rc = xnOSGetDirName(strModulePath, strBaseDir, XN_FILE_MAX_PATH);
	if (rc != XN_STATUS_OK)
	{
		// Very unlikely to happen, but just in case.
		m_errorLogger.Append("Couldn't get the OpenNI shared library module's directory: %s", xnGetStatusString(rc));
		return OniStatusFromXnStatus(rc);
	}

	s_valid = TRUE;

	// Read configuration file

	XnChar strOniConfigurationFile[XN_FILE_MAX_PATH];
	XnBool configurationFileExists = FALSE;

	// Search the module directory for OpenNI.ini.
	xnOSStrCopy(strOniConfigurationFile, strBaseDir, XN_FILE_MAX_PATH);
	rc = xnOSAppendFilePath(strOniConfigurationFile, ONI_CONFIGURATION_FILE, XN_FILE_MAX_PATH);
	if (rc == XN_STATUS_OK)
	{
		xnOSDoesFileExist(strOniConfigurationFile, &configurationFileExists);
	}

#ifdef ONI_PLATFORM_ANDROID_OS
	xnLogSetMaskMinSeverity(XN_LOG_MASK_ALL, (XnLogSeverity)0);
	xnLogSetAndroidOutput(TRUE);
#endif
	
	if (configurationFileExists)
	{
		// First, we should process the log related configuration as early as possible.

		XnInt32 nValue;
		XnChar strLogPath[XN_FILE_MAX_PATH] = {0};

		//Test if log redirection is needed 
		rc = xnOSReadStringFromINI(strOniConfigurationFile, "Log", "LogPath", strLogPath, XN_FILE_MAX_PATH);
		if (rc == XN_STATUS_OK)
		{
			rc = xnLogSetOutputFolder(strLogPath);
			if (rc != XN_STATUS_OK)
			{
				xnLogWarning(XN_MASK_ONI_CONTEXT, "Failed to set log output folder: %s", xnGetStatusString(rc));
			}
			else
			{
				xnLogVerbose(XN_MASK_ONI_CONTEXT, "Log directory redirected to: %s", strLogPath);
			}
		}

		rc = xnOSReadIntFromINI(strOniConfigurationFile, "Log", "Verbosity", &nValue);
		if (rc == XN_STATUS_OK)
		{
			xnLogSetMaskMinSeverity(XN_LOG_MASK_ALL, (XnLogSeverity)nValue);
		}

		rc = xnOSReadIntFromINI(strOniConfigurationFile, "Log", "LogToConsole", &nValue);
		if (rc == XN_STATUS_OK)
		{
			xnLogSetConsoleOutput(nValue == 1);
		}
		
		rc = xnOSReadIntFromINI(strOniConfigurationFile, "Log", "LogToFile", &nValue);
		if (rc == XN_STATUS_OK)
		{
			xnLogSetFileOutput(nValue == 1);
		}

		// Then, process the other device configurations.

		rc = xnOSReadStringFromINI(strOniConfigurationFile, "Device", "Override", m_overrideDevice, XN_FILE_MAX_PATH);
		if (rc != XN_STATUS_OK)
		{
			xnLogVerbose(XN_MASK_ONI_CONTEXT, "No override device in configuration file");
		}

		rc = xnOSReadStringFromINI(strOniConfigurationFile, "Drivers", "Repository", repositoryFromINI, XN_FILE_MAX_PATH);
		if (rc == XN_STATUS_OK)
		{
			repositoryOverridden = TRUE;
		}



		xnLogVerbose(XN_MASK_ONI_CONTEXT, "Configuration has been read from '%s'", strOniConfigurationFile);
	}
	else
	{
		xnLogVerbose(XN_MASK_ONI_CONTEXT, "Couldn't find configuration file '%s'", strOniConfigurationFile);
	}

	xnLogVerbose(XN_MASK_ONI_CONTEXT, "OpenNI %s", ONI_VERSION_STRING);

	// Resolve the drive path based on the module's directory.
	XnChar strDriverPath[XN_FILE_MAX_PATH];
	xnOSStrCopy(strDriverPath, strBaseDir, XN_FILE_MAX_PATH);

	if (repositoryOverridden)
	{
		xnLogVerbose(XN_MASK_ONI_CONTEXT, "Extending the driver path by '%s', as configured in file '%s'", repositoryFromINI, strOniConfigurationFile);
		rc = xnOSAppendFilePath(strDriverPath, repositoryFromINI, XN_FILE_MAX_PATH);
	}
	else
	{
		rc = xnOSAppendFilePath(strDriverPath, ONI_DEFAULT_DRIVERS_REPOSITORY, XN_FILE_MAX_PATH);
	}

	if (rc != XN_STATUS_OK)
	{
		m_errorLogger.Append("The driver path gets too long");
		return OniStatusFromXnStatus(rc);
	}

	xnLogVerbose(XN_MASK_ONI_CONTEXT, "Using '%s' as driver path", strDriverPath);
	rc = loadLibraries(strDriverPath);

	if (rc == XN_STATUS_OK)
	{
		m_errorLogger.Clear();
	}

	return OniStatusFromXnStatus(rc);
}
Example #7
0
// The recorder
int main(int argc, char** argv)
{
	// OpenNi objects
	xn::Context context;
	xn::DepthGenerator depthGenerator;
	xn::ImageGenerator imageGenerator;

	// To count missed frames
	XnUInt64 nLastDepthTime = 0;
	XnUInt64 nLastImageTime = 0;
	XnUInt32 nMissedDepthFrames = 0;
	XnUInt32 nMissedImageFrames = 0;
	XnUInt32 nDepthFrames = 0;
	XnUInt32 nImageFrames = 0;

	RecConfiguration config;

	XnStatus nRetVal = XN_STATUS_OK;

	// Parse the command line arguments
	if (!ParseArgs(argc, argv, config))
	{
		printf("Parse error\n");
		return 1;
	}

	if (config.bVerbose)
	{
		// Turn on log
		xnLogInitSystem();
		xnLogSetConsoleOutput(TRUE);
		xnLogSetMaskMinSeverity(XN_LOG_MASK_ALL, XN_LOG_VERBOSE);
	}

	// Initialize OpenNI
	nRetVal = context.Init();
	CHECK_RC(nRetVal, "Init");

	nRetVal = ConfigureGenerators(config, context, depthGenerator, imageGenerator);
	CHECK_RC(nRetVal, "Config generators");

	nRetVal = context.StartGeneratingAll();
	CHECK_RC(nRetVal, "Generate all");

	// Create and initialize the cyclic buffer
	CyclicBuffer cyclicBuffer(context, depthGenerator, imageGenerator, config);
	cyclicBuffer.Initialize(config.strDirName, config.nDumpTime);

	// Mainloop
	for (;;)
	{
		if (xnOSWasKeyboardHit())
		{
			char c = xnOSReadCharFromInput();
			XnBool bStop = FALSE;
			switch (c)
			{
			case 27:
				bStop = TRUE;
				break;
			case 'd':
				cyclicBuffer.Dump();
				break;
			}
			if (bStop)
			{
				break;
			}
		}
		// Get next data
		context.WaitAndUpdateAll();
		// Save data
		cyclicBuffer.Update(depthGenerator, imageGenerator);

		// Check for missed frames
		if (config.bRecordDepth)
		{
			++nDepthFrames;
			XnUInt64 nTimestamp = depthGenerator.GetTimestamp();
			if (nLastDepthTime != 0 && nTimestamp - nLastDepthTime > 35000)
			{
				int missed = (int)(nTimestamp-nLastDepthTime)/32000 - 1;
				printf("Missed depth: %llu -> %llu = %d > 35000 - %d frames\n",
					nLastDepthTime, nTimestamp, XnUInt32(nTimestamp-nLastDepthTime), missed);
				nMissedDepthFrames += missed;
			}
			nLastDepthTime = nTimestamp;
		}
		if (config.bRecordImage)
		{
			++nImageFrames;
			XnUInt64 nTimestamp = imageGenerator.GetTimestamp();
			if (nLastImageTime != 0 && nTimestamp - nLastImageTime > 35000)
			{
				int missed = (int)(nTimestamp-nLastImageTime)/32000 - 1;
				printf("Missed image: %llu -> %llu = %d > 35000 - %d frames\n",
					nLastImageTime, nTimestamp, XnUInt32(nTimestamp-nLastImageTime), missed);
				nMissedImageFrames += missed;
			}
			nLastImageTime = nTimestamp;

		}

	}

	if (config.bRecordDepth)
	{
		printf("Missed %d of %d depth frames (%5.2f%%)\n", nMissedDepthFrames, (nMissedDepthFrames+nDepthFrames), (nMissedDepthFrames*100.0)/(nMissedDepthFrames+nDepthFrames));
	}
	if (config.bRecordImage)
	{
		printf("Missed %d of %d image frames (%5.2f%%)\n", nMissedImageFrames, (nMissedImageFrames+nImageFrames), (nMissedImageFrames*100.0)/(nMissedImageFrames+nImageFrames));
	}

	imageGenerator.Release();
	depthGenerator.Release();
	context.Release();

	return 0;
}
Example #8
0
OniStatus Context::initialize()
{
	XnBool repositoryOverridden = FALSE;
	XnChar repositoryFromINI[XN_FILE_MAX_PATH] = {0};

	m_initializationCounter++;
	if (m_initializationCounter > 1)
	{
		xnLogVerbose(XN_LOG_MASK_ALL, "Initialize: Already initialized");
		return ONI_STATUS_OK;
	}

	XnStatus rc;

	rc = m_newFrameAvailableEvent.Create(FALSE);
	if (rc != XN_STATUS_OK)
	{
		m_errorLogger.Append("Couldn't create event for new frames: %s", xnGetStatusString(rc));
		return ONI_STATUS_ERROR;
	}

	s_valid = TRUE;

	// Read configuration file

	XnBool configurationFileExists = FALSE;
	rc = xnOSDoesFileExist(ONI_CONFIGURATION_FILE, &configurationFileExists);
	if (configurationFileExists)
	{
		rc = xnOSReadStringFromINI(ONI_CONFIGURATION_FILE, "Device", "Override", m_overrideDevice, XN_FILE_MAX_PATH);
		if (rc != XN_STATUS_OK)
		{
			xnLogVerbose(XN_LOG_MASK_ALL, "No override device in configuration file");
		}

		XnInt32 nValue;
		rc = xnOSReadIntFromINI(ONI_CONFIGURATION_FILE, "Log", "Verbosity", &nValue);
		if (rc == XN_STATUS_OK)
		{
			xnLogSetMaskMinSeverity(XN_LOG_MASK_ALL, (XnLogSeverity)nValue);
		}

		rc = xnOSReadIntFromINI(ONI_CONFIGURATION_FILE, "Log", "LogToConsole", &nValue);
		if (rc == XN_STATUS_OK)
		{
			xnLogSetConsoleOutput(nValue == 1);
		}
		rc = xnOSReadIntFromINI(ONI_CONFIGURATION_FILE, "Log", "LogToFile", &nValue);
		if (rc == XN_STATUS_OK)
		{
			xnLogSetFileOutput(nValue == 1);
		}
		rc = xnOSReadStringFromINI(ONI_CONFIGURATION_FILE, "Drivers", "Repository", repositoryFromINI, XN_FILE_MAX_PATH);
		if (rc == XN_STATUS_OK)
		{
			repositoryOverridden = TRUE;
		}
	}
	else
	{
		xnLogVerbose(XN_LOG_MASK_ALL, "Couldn't find configuration file '%s'", ONI_CONFIGURATION_FILE);
	}

	xnLogVerbose(XN_LOG_MASK_ALL, "OpenNI %s", ONI_VERSION_STRING);

	// Use path specified in ini file
	if (repositoryOverridden)
	{
		xnLogVerbose(XN_LOG_MASK_ALL, "Using '%s' as driver path, as configured in file '%s'", repositoryFromINI, ONI_CONFIGURATION_FILE);
		rc = loadLibraries(repositoryFromINI);
		return OniStatusFromXnStatus(rc);
	}

	xnLogVerbose(XN_LOG_MASK_ALL, "Using '%s' as driver path", ONI_DEFAULT_DRIVERS_REPOSITORY);
	// Use default path
	rc = loadLibraries(ONI_DEFAULT_DRIVERS_REPOSITORY);
	if (rc != XN_STATUS_OK)
	{
		// Can't find through default - try environment variable
		xnLogVerbose(XN_LOG_MASK_ALL, "Can't load drivers from default directory '%s'.", ONI_DEFAULT_DRIVERS_REPOSITORY);

		char dirName[XN_FILE_MAX_PATH];
		XnStatus envrc = xnOSGetEnvironmentVariable(ONI_ENV_VAR_DRIVERS_REPOSITORY, dirName, XN_FILE_MAX_PATH);
		if (envrc == XN_STATUS_OK)
		{
			xnLogVerbose(XN_LOG_MASK_ALL, "Using '%s' as driver path, as configured by environment variable '%s'", dirName, ONI_ENV_VAR_DRIVERS_REPOSITORY);
			rc = loadLibraries(dirName);
		}
	}

	if (rc == XN_STATUS_OK)
	{
		m_errorLogger.Clear();
	}

	return OniStatusFromXnStatus(rc);
}
Example #9
0
int main(int argc, char* argv[])
{
	const char* strVendor = NULL;
	const char* strKey = NULL;
	bool bRegister = TRUE;
	XnBool bVerbose = FALSE;
	XnBool bList = FALSE;

	if (argc > 1 && strcmp(argv[1], "-l") == 0)
	{
		bList = TRUE;
	}
	else
	{
		for (int i = 1; i < argc; ++i)
		{
			const XnChar* arg = argv[i];
			if (arg[0] == '-')
			{
				if (arg[2] != '\0')
				{
					printUsage(argv[0]);
					return -1;
				}

				switch (arg[1])
				{
				case 'r':
					bRegister = TRUE;
					break;
				case 'u':
					bRegister = FALSE;
					break;
				case 'v':
					bVerbose = TRUE;
					break;
				default:
					printf("Unknown option: -%c\n", arg[1]);
					printUsage(argv[0]);
					return -1;
				}
			}
			else if (strVendor == NULL)
			{
				strVendor = arg;
			}
			else if (strKey == NULL)
			{
				strKey = arg;
			}
			else
			{
				printUsage(argv[0]);
				return -1;
			}
		} // args for

		if (strVendor == NULL || strKey == NULL)
		{
			printUsage(argv[0]);
			return -1;
		}
	}

	xnLogInitSystem();
	xnLogSetConsoleOutput(bVerbose || bList);
	xnLogSetSeverityFilter(bVerbose ? XN_LOG_VERBOSE : XN_LOG_WARNING);
	xnLogSetMaskState(XN_LOG_MASK_ALL, TRUE);

	XnStatus nRetVal = XN_STATUS_OK;

	XnLicense license = {0};
	if (!bList)
	{
		nRetVal = xnOSStrNCopy(license.strVendor, strVendor, strlen(strVendor) + 1, sizeof(license.strVendor));
		if (nRetVal != XN_STATUS_OK)
		{
			printf("Error: Vendor name is too long (should be up to %u characters).", (unsigned)sizeof(license.strVendor) - 1);
			return -1;
		}

		nRetVal = xnOSStrNCopy(license.strKey, strKey, strlen(strKey) + 1, sizeof(license.strKey));
		if (nRetVal != XN_STATUS_OK)
		{
			printf("Error: Key is too long (should be up to %u characters).", (unsigned)sizeof(license.strKey) - 1);
			return -1;
		}
	}

	if (bList)
	{
		nRetVal = xnPrintRegisteredLicenses();
	}
	else if (bRegister)
	{
		nRetVal = xnRegisterGlobalLicense(&license);
	}
	else
	{
		nRetVal = xnUnregisterGlobalLicense(&license);
	}

	if (nRetVal != XN_STATUS_OK)
	{
		printf("Failed: %s\n", xnGetStatusString(nRetVal));
		return -1;
	}

	if (bVerbose)
	{
		printf("Done.\n");
	}

	return 0;
}