<commit_before>/*
 *  Copyright (c) 2014, Oculus VR, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant 
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

// Common includes
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN32
#include <filesystem>
#else
#include <experimental/filesystem>
#endif
#include "Kbhit.h"

#include "GetTime.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "StringCompressor.h"
#include "PacketizedTCP.h"

// Client only includes
#include "FileListTransferCBInterface.h"
#include "FileListTransfer.h"
#include "AutopatcherClient.h"
#include "AutopatcherPatchContext.h"
#include "Gets.h"
#include "RakSleep.h"

std::experimental::filesystem::path WORKING_DIRECTORY;
std::experimental::filesystem::path PATH_TO_XDELTA_EXE;

class TestCB : public RakNet::AutopatcherClientCBInterface
{
public:
	virtual bool OnFile(OnFileStruct *onFileStruct)
	{
		if (onFileStruct->context.op==PC_HASH_1_WITH_PATCH || onFileStruct->context.op==PC_HASH_2_WITH_PATCH)
			printf("Patched: ");
		else if (onFileStruct->context.op==PC_WRITE_FILE)
			printf("Written: ");
		else if (onFileStruct->context.op==PC_ERROR_FILE_WRITE_FAILURE)
			printf("Write Failure: ");
		else if (onFileStruct->context.op==PC_ERROR_PATCH_TARGET_MISSING)
			printf("Patch target missing: ");
		else if (onFileStruct->context.op==PC_ERROR_PATCH_APPLICATION_FAILURE)
			printf("Patch process failure: ");
		else if (onFileStruct->context.op==PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE)
			printf("Patch checksum failure: ");
		else if (onFileStruct->context.op==PC_NOTICE_WILL_COPY_ON_RESTART)
			printf("Copy pending restart: ");
		else if (onFileStruct->context.op==PC_NOTICE_FILE_DOWNLOADED)
			printf("Downloaded: ");
		else if (onFileStruct->context.op==PC_NOTICE_FILE_DOWNLOADED_PATCH)
			printf("Downloaded Patch: ");
		else
			RakAssert(0);


		printf("%i. (100%%) %i/%i %s %ib / %ib\n", onFileStruct->setID, onFileStruct->fileIndex+1, onFileStruct->numberOfFilesInThisSet,
			onFileStruct->fileName, onFileStruct->byteLengthOfThisFile,
			onFileStruct->byteLengthOfThisSet);

		// Return false for the file data to be deallocated automatically
		return false;
	}

	virtual void OnFileProgress(FileProgressStruct *fps)
	{
		printf("Downloading: %i. (%i%%) %i/%i %s %ib/%ib %ib/%ib total\n", fps->onFileStruct->setID,
			(int) (100.0*(double)fps->onFileStruct->bytesDownloadedForThisFile/(double)fps->onFileStruct->byteLengthOfThisFile),
			fps->onFileStruct->fileIndex+1, fps->onFileStruct->numberOfFilesInThisSet, fps->onFileStruct->fileName,
			fps->onFileStruct->bytesDownloadedForThisFile,
			fps->onFileStruct->byteLengthOfThisFile,			
			fps->onFileStruct->bytesDownloadedForThisSet,
			fps->onFileStruct->byteLengthOfThisSet
			);
	}

	virtual PatchContext ApplyPatchBase(const char *oldFilePath, char **newFileContents, unsigned int *newFileSize, char *patchContents, unsigned int patchSize, uint32_t patchAlgorithm)
	{
		if (patchAlgorithm==0)
		{
			return ApplyPatchBSDiff(oldFilePath, newFileContents, newFileSize, patchContents, patchSize);
		}
		else
		{
			std::string buff;
			RakNet::TimeUS time = RakNet::GetTimeUS();
			buff = time;
			std::experimental::filesystem::path pathToPatch1, pathToPatch2;
			std::experimental::filesystem::path commandLine;
			commandLine = WORKING_DIRECTORY;
			commandLine /= commandLine.concat("patchClient_" + buff + ".tmp");
			auto pathToPatch1U8 = pathToPatch1.u8string();
			auto pathToPatch2U8 = pathToPatch2.u8string();
			FILE *fpPatch = fopen(pathToPatch1U8.c_str(), "wb");
			if (fpPatch==0)
				return PC_ERROR_PATCH_TARGET_MISSING;
			fwrite(patchContents, 1, patchSize, fpPatch);
			fclose(fpPatch);

			// Invoke xdelta
			// See https://code.google.com/p/xdelta/wiki/CommandLineSyntax
			std::string xdeltaCommandLine;
			xdeltaCommandLine = "-d -f -s " + std::string(oldFilePath) + " patchClient_" + std::string(buff) + ".tmp  newFile_" + std::string(buff) + ".tmp";

			std::string shellExecute;
			shellExecute = "cd " + WORKING_DIRECTORY.string() + " && " + PATH_TO_XDELTA_EXE.string() + commandLine.string();
			system(shellExecute.c_str());

			// ShellExecute(NULL, "open", PATH_TO_XDELTA_EXE, commandLine, WORKING_DIRECTORY, SW_SHOWNORMAL);

			pathToPatch2 = WORKING_DIRECTORY;
			pathToPatch2 /= pathToPatch2.concat("newFile_" + buff + ".tmp");
			fpPatch = fopen(pathToPatch2U8.c_str(), "r+b");
			RakNet::TimeUS stopWaiting = time + 60000000;
			while (fpPatch==0 && RakNet::GetTimeUS() < stopWaiting)
			{
				RakSleep(1000);
				fpPatch = fopen(pathToPatch2U8.c_str(), "r+b");
			}
			if (fpPatch==0)
			{
				auto commandLineString = commandLine.string();
				printf("\nERROR: Could not open %s.\nerr=%i (%s)\narguments=%s\n", pathToPatch2, errno, strerror(errno), commandLineString.c_str());
				return PC_ERROR_PATCH_TARGET_MISSING;
			}
		
			fseek(fpPatch, 0, SEEK_END);
			*newFileSize = ftell(fpPatch);
			fseek(fpPatch, 0, SEEK_SET);
			*newFileContents = (char*) rakMalloc_Ex(*newFileSize, _FILE_AND_LINE_);
			fread(*newFileContents, 1, *newFileSize, fpPatch);
			fclose(fpPatch);

			int unlinkRes1 = std::experimental::filesystem::remove(pathToPatch1);
			int unlinkRes2 = std::experimental::filesystem::remove(pathToPatch2);
			std::error_code errorCode1;
			std::error_code errorCode2;
			while ((unlinkRes1!=0 || unlinkRes2!=0) && RakNet::GetTimeUS() < stopWaiting)
			{
				RakSleep(1000);
				if (unlinkRes1!=0)
					unlinkRes1 = std::experimental::filesystem::remove(pathToPatch1, errorCode1);
				if (unlinkRes2!=0)
					unlinkRes2 = std::experimental::filesystem::remove(pathToPatch2, errorCode2);
			}

			if (unlinkRes1 == false)
				printf("\nWARNING: unlink %s failed.\nerr=%i (%s)\n", pathToPatch1U8.c_str(), errorCode1.value(), errorCode1.message().c_str());
			if (unlinkRes2 == false)
				printf("\nWARNING: unlink %s failed.\nerr=%i (%s)\n", pathToPatch2U8.c_str(), errorCode1.value(), errorCode2.message().c_str());

			return PC_WRITE_FILE;
		}
	}

} transferCallback;

#define USE_TCP

int main(int argc, char **argv)
{
	printf("A simple client interface for the advanced autopatcher.\n");
	printf("Use DirectoryDeltaTransfer for a simpler version of an autopatcher.\n");
	printf("Difficulty: Intermediate\n\n");

	printf("Client starting...");
	RakNet::SystemAddress serverAddress=RakNet::UNASSIGNED_SYSTEM_ADDRESS;
	RakNet::AutopatcherClient autopatcherClient;
	RakNet::FileListTransfer fileListTransfer;
	autopatcherClient.SetFileListTransferPlugin(&fileListTransfer);
	unsigned short localPort=0;
	if (argc>=6)
	{
		localPort=atoi(argv[5]);
	}
#ifdef USE_TCP<commit_msg>Proper usage of unlink.<commit_after>/*
 *  Copyright (c) 2014, Oculus VR, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant 
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

// Common includes
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef _WIN32
#include <filesystem>
#else
#include <experimental/filesystem>
#endif
#include "Kbhit.h"

#include "GetTime.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "StringCompressor.h"
#include "PacketizedTCP.h"

// Client only includes
#include "FileListTransferCBInterface.h"
#include "FileListTransfer.h"
#include "AutopatcherClient.h"
#include "AutopatcherPatchContext.h"
#include "Gets.h"
#include "RakSleep.h"

std::experimental::filesystem::path WORKING_DIRECTORY;
std::experimental::filesystem::path PATH_TO_XDELTA_EXE;

class TestCB : public RakNet::AutopatcherClientCBInterface
{
public:
	virtual bool OnFile(OnFileStruct *onFileStruct)
	{
		if (onFileStruct->context.op==PC_HASH_1_WITH_PATCH || onFileStruct->context.op==PC_HASH_2_WITH_PATCH)
			printf("Patched: ");
		else if (onFileStruct->context.op==PC_WRITE_FILE)
			printf("Written: ");
		else if (onFileStruct->context.op==PC_ERROR_FILE_WRITE_FAILURE)
			printf("Write Failure: ");
		else if (onFileStruct->context.op==PC_ERROR_PATCH_TARGET_MISSING)
			printf("Patch target missing: ");
		else if (onFileStruct->context.op==PC_ERROR_PATCH_APPLICATION_FAILURE)
			printf("Patch process failure: ");
		else if (onFileStruct->context.op==PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE)
			printf("Patch checksum failure: ");
		else if (onFileStruct->context.op==PC_NOTICE_WILL_COPY_ON_RESTART)
			printf("Copy pending restart: ");
		else if (onFileStruct->context.op==PC_NOTICE_FILE_DOWNLOADED)
			printf("Downloaded: ");
		else if (onFileStruct->context.op==PC_NOTICE_FILE_DOWNLOADED_PATCH)
			printf("Downloaded Patch: ");
		else
			RakAssert(0);


		printf("%i. (100%%) %i/%i %s %ib / %ib\n", onFileStruct->setID, onFileStruct->fileIndex+1, onFileStruct->numberOfFilesInThisSet,
			onFileStruct->fileName, onFileStruct->byteLengthOfThisFile,
			onFileStruct->byteLengthOfThisSet);

		// Return false for the file data to be deallocated automatically
		return false;
	}

	virtual void OnFileProgress(FileProgressStruct *fps)
	{
		printf("Downloading: %i. (%i%%) %i/%i %s %ib/%ib %ib/%ib total\n", fps->onFileStruct->setID,
			(int) (100.0*(double)fps->onFileStruct->bytesDownloadedForThisFile/(double)fps->onFileStruct->byteLengthOfThisFile),
			fps->onFileStruct->fileIndex+1, fps->onFileStruct->numberOfFilesInThisSet, fps->onFileStruct->fileName,
			fps->onFileStruct->bytesDownloadedForThisFile,
			fps->onFileStruct->byteLengthOfThisFile,			
			fps->onFileStruct->bytesDownloadedForThisSet,
			fps->onFileStruct->byteLengthOfThisSet
			);
	}

	virtual PatchContext ApplyPatchBase(const char *oldFilePath, char **newFileContents, unsigned int *newFileSize, char *patchContents, unsigned int patchSize, uint32_t patchAlgorithm)
	{
		if (patchAlgorithm==0)
		{
			return ApplyPatchBSDiff(oldFilePath, newFileContents, newFileSize, patchContents, patchSize);
		}
		else
		{
			std::string buff;
			RakNet::TimeUS time = RakNet::GetTimeUS();
			buff = time;
			std::experimental::filesystem::path pathToPatch1, pathToPatch2;
			std::experimental::filesystem::path commandLine;
			commandLine = WORKING_DIRECTORY;
			commandLine /= commandLine.concat("patchClient_" + buff + ".tmp");
			auto pathToPatch1U8 = pathToPatch1.u8string();
			auto pathToPatch2U8 = pathToPatch2.u8string();
			FILE *fpPatch = fopen(pathToPatch1U8.c_str(), "wb");
			if (fpPatch==0)
				return PC_ERROR_PATCH_TARGET_MISSING;
			fwrite(patchContents, 1, patchSize, fpPatch);
			fclose(fpPatch);

			// Invoke xdelta
			// See https://code.google.com/p/xdelta/wiki/CommandLineSyntax
			std::string xdeltaCommandLine;
			xdeltaCommandLine = "-d -f -s " + std::string(oldFilePath) + " patchClient_" + std::string(buff) + ".tmp  newFile_" + std::string(buff) + ".tmp";

			std::string shellExecute;
			shellExecute = "cd " + WORKING_DIRECTORY.string() + " && " + PATH_TO_XDELTA_EXE.string() + commandLine.string();
			system(shellExecute.c_str());

			// ShellExecute(NULL, "open", PATH_TO_XDELTA_EXE, commandLine, WORKING_DIRECTORY, SW_SHOWNORMAL);

			pathToPatch2 = WORKING_DIRECTORY;
			pathToPatch2 /= pathToPatch2.concat("newFile_" + buff + ".tmp");
			fpPatch = fopen(pathToPatch2U8.c_str(), "r+b");
			RakNet::TimeUS stopWaiting = time + 60000000;
			while (fpPatch==0 && RakNet::GetTimeUS() < stopWaiting)
			{
				RakSleep(1000);
				fpPatch = fopen(pathToPatch2U8.c_str(), "r+b");
			}
			if (fpPatch==0)
			{
				auto commandLineString = commandLine.string();
				printf("\nERROR: Could not open %s.\nerr=%i (%s)\narguments=%s\n", pathToPatch2, errno, strerror(errno), commandLineString.c_str());
				return PC_ERROR_PATCH_TARGET_MISSING;
			}
		
			fseek(fpPatch, 0, SEEK_END);
			*newFileSize = ftell(fpPatch);
			fseek(fpPatch, 0, SEEK_SET);
			*newFileContents = (char*) rakMalloc_Ex(*newFileSize, _FILE_AND_LINE_);
			fread(*newFileContents, 1, *newFileSize, fpPatch);
			fclose(fpPatch);

			std::error_code errorCode1;
			std::error_code errorCode2;

			int unlinkRes1 = std::experimental::filesystem::remove(pathToPatch1, errorCode1);
			int unlinkRes2 = std::experimental::filesystem::remove(pathToPatch2, errorCode2);

			while ((unlinkRes1 == false || unlinkRes2) && RakNet::GetTimeUS() < stopWaiting)
			{
				RakSleep(1000);
				if (unlinkRes1 == false)
					unlinkRes1 = std::experimental::filesystem::remove(pathToPatch1, errorCode1);
				if (unlinkRes2 == false)
					unlinkRes2 = std::experimental::filesystem::remove(pathToPatch2, errorCode2);
			}
			auto errorCode1String = errorCode1.message();
			auto errorCode2String = errorCode2.message();
			if (unlinkRes1 == false)
				printf("\nWARNING: unlink %s failed.\nerr=%i (%s)\n", pathToPatch1U8.c_str(), errorCode1.value(), errorCode1String.c_str());
			if (unlinkRes2 == false)
				printf("\nWARNING: unlink %s failed.\nerr=%i (%s)\n", pathToPatch2U8.c_str(), errorCode1.value(), errorCode2String.c_str());

			return PC_WRITE_FILE;
		}
	}

} transferCallback;

#define USE_TCP

int main(int argc, char **argv)
{
	printf("A simple client interface for the advanced autopatcher.\n");
	printf("Use DirectoryDeltaTransfer for a simpler version of an autopatcher.\n");
	printf("Difficulty: Intermediate\n\n");

	printf("Client starting...");
	RakNet::SystemAddress serverAddress=RakNet::UNASSIGNED_SYSTEM_ADDRESS;
	RakNet::AutopatcherClient autopatcherClient;
	RakNet::FileListTransfer fileListTransfer;
	autopatcherClient.SetFileListTransferPlugin(&fileListTransfer);
	unsigned short localPort=0;
	if (argc>=6)
	{
		localPort=atoi(argv[5]);
	}
#ifdef USE_TCP
{'fraction_non_alphanumeric': 0.13613897368803604, 'fraction_numerical': 0.014246256723360953, 'mean_word_length': 5.447516401124648, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 87, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5211341', 'n_tokens_mistral': 5307, 'n_tokens_neox': 4731, 'n_words': 901}