bool CopyFileToDevice(const FString& IPAPath, FString PathOnDevice, int PacketSize)
 {
     bool Result = false;
     // reconnect to the device and start the AFC service
     Connect();
     if (!AFC::StartService(DeviceHandle, &AFCHandle))
     {
         if (!AFC::ConnectionOpen(AFCHandle, &AFCConnection))
         {
     
             // ensure the directory on the phone exists
             FString DirectoryOnDevice = FPaths::GetPath(PathOnDevice);
             CreateDirectory(DirectoryOnDevice + TEXT("/"));
     
             // transfer the file
             IPlatformFile& PlatformFile = IPlatformFile::GetPlatformPhysical();
             IFileHandle* SourceFile = PlatformFile.OpenRead(*IPAPath);
             if (SourceFile != NULL)
             {
                 uint64 DestinationHandle = 0;
                 if (AFC::FileRefOpen(AFCConnection, PathOnDevice, 3, &DestinationHandle) == 0)
                 {
                     int TotalBytes = 0;
                     int PacketCount = SourceFile->Size() / PacketSize;
                     uint8* buffer = new uint8[PacketSize];
                     for (int Index = 0; Index < PacketCount; ++Index)
                     {
                         if (SourceFile->Read(buffer, PacketSize))
                         {
                             TotalBytes += PacketSize;
                             AFC::FileRefWrite(AFCConnection, DestinationHandle, buffer, PacketSize);
                         }
                     }
             
                     if (SourceFile->Read(buffer, SourceFile->Size() - TotalBytes))
                     {
                         AFC::FileRefWrite(AFCConnection, DestinationHandle, buffer, SourceFile->Size() - TotalBytes);
                     }
             
                     // flush the destination and close
                     AFC::FileRefClose(AFCConnection, DestinationHandle);
                     
                     Result = true;
                 }
                 delete SourceFile;
             }
     
             // stop the AFC service and disconnect from the device
             AFC::ConnectionClose(AFCConnection);
             AFCConnection = NULL;
             Disconnect();
         }
     }
     return Result;
 }
void FNetworkFileServerClientConnection::ProcessReadFile( FArchive& In, FArchive& Out )
{
	// Get Handle ID
	uint64 HandleId = 0;
	In << HandleId;

	int64 BytesToRead = 0;
	In << BytesToRead;

	int64 BytesRead = 0;
	IFileHandle* File = FindOpenFile(HandleId);

	if (File)
	{
		uint8* Dest = (uint8*)FMemory::Malloc(BytesToRead);		

		if (File->Read(Dest, BytesToRead))
		{
			BytesRead = BytesToRead;
			Out << BytesRead;
			Out.Serialize(Dest, BytesRead);
		}
		else
		{
			Out << BytesRead;
		}

		FMemory::Free(Dest);
	}
	else
	{
		Out << BytesRead;
	}
}
bool FStreamingNetworkPlatformFile::InitializeInternal(IPlatformFile* Inner, const TCHAR* HostIP)
{
	// look for the commandline that will read files from over the network
	if (HostIP == nullptr)
	{
		UE_LOG(LogStreamingPlatformFile, Error, TEXT("No Host IP specified in the commandline."));
		bIsUsable = false;

		return false;
	}

	// optionally get the port from the command line
	int32 OverridePort;
	if (FParse::Value(FCommandLine::Get(), TEXT("fileserverport="), OverridePort))
	{
		UE_LOG(LogStreamingPlatformFile, Display, TEXT("Overriding file server port: %d"), OverridePort);
		FileServerPort = OverridePort;
	}

	// Send the filenames and timestamps to the server.
	FNetworkFileArchive Payload(NFS_Messages::GetFileList);
	FillGetFileList(Payload, true);

	// Send the directories over, and wait for a response.
	FArrayReader Response;

	if(SendPayloadAndReceiveResponse(Payload,Response))
	{
		// Receive the cooked version information.
		int32 ServerPackageVersion = 0;
		int32 ServerPackageLicenseeVersion = 0;
		ProcessServerInitialResponse(Response, ServerPackageVersion, ServerPackageLicenseeVersion);

		// Make sure we can sync a file.
		FString TestSyncFile = FPaths::Combine(*(FPaths::EngineDir()), TEXT("Config/BaseEngine.ini"));
		IFileHandle* TestFileHandle = OpenRead(*TestSyncFile);
		if (TestFileHandle != nullptr)
		{
			uint8* FileContents = (uint8*)FMemory::Malloc(TestFileHandle->Size());
			if (!TestFileHandle->Read(FileContents, TestFileHandle->Size()))
			{
				UE_LOG(LogStreamingPlatformFile, Fatal, TEXT("Could not read test file %s."), *TestSyncFile);
			}
			FMemory::Free(FileContents);
			delete TestFileHandle;
		}
		else
		{
			UE_LOG(LogStreamingPlatformFile, Fatal, TEXT("Could not open test file %s."), *TestSyncFile);
		}

		FCommandLine::AddToSubprocessCommandline( *FString::Printf( TEXT("-StreamingHostIP=%s"), HostIP ) );

		return true; 
	}

	return false; 
}
bool FPakPlatformFile::BufferedCopyFile(IFileHandle& Dest, IFileHandle& Source, const int64 FileSize, uint8* Buffer, const int64 BufferSize) const
{	
	int64 RemainingSizeToCopy = FileSize;
	// Continue copying chunks using the buffer
	while (RemainingSizeToCopy > 0)
	{
		const int64 SizeToCopy = FMath::Min(BufferSize, RemainingSizeToCopy);
		if (Source.Read(Buffer, SizeToCopy) == false)
		{
			return false;
		}
		if (Dest.Write(Buffer, SizeToCopy) == false)
		{
			return false;
		}
		RemainingSizeToCopy -= SizeToCopy;
	}
	return true;
}
void FNetworkFileServerClientConnection::PackageFile( FString& Filename, FArchive& Out )
{
	// get file timestamp and send it to client
	FDateTime ServerTimeStamp = Sandbox->GetTimeStamp(*Filename);

	TArray<uint8> Contents;
	// open file
	IFileHandle* File = Sandbox->OpenRead(*Filename);

	if (!File)
	{
		ServerTimeStamp = FDateTime::MinValue(); // if this was a directory, this will make sure it is not confused with a zero byte file

		UE_LOG(LogFileServer, Warning, TEXT("Request for missing file %s."), *Filename );
	}
	else
	{
		if (!File->Size())
		{
			UE_LOG(LogFileServer, Warning, TEXT("Sending empty file %s...."), *Filename);
		}
		else
		{
			// read it
			Contents.AddUninitialized(File->Size());
			File->Read(Contents.GetData(), Contents.Num());
		}

		// close it
		delete File;

		UE_LOG(LogFileServer, Display, TEXT("Read %s, %d bytes"), *Filename, Contents.Num());
	}

	Out << Filename;
	Out << ServerTimeStamp;
	uint64 FileSize = Contents.Num();
	Out << FileSize;
	Out.Serialize(Contents.GetData(), FileSize);
}
void FNetworkPlatformFile::InitializeAfterSetActive()
{
	double NetworkFileStartupTime = 0.0;
	{
		SCOPE_SECONDS_COUNTER(NetworkFileStartupTime);

		// send the filenames and timestamps to the server
		FNetworkFileArchive Payload(NFS_Messages::GetFileList);
		FillGetFileList(Payload, false);

		// send the directories over, and wait for a response
		FArrayReader Response;
		if (!SendPayloadAndReceiveResponse(Payload, Response))
		{
			delete Transport; 
			return; 
		}
		else
		{
			// receive the cooked version information
			int32 ServerPackageVersion = 0;
			int32 ServerPackageLicenseeVersion = 0;
			ProcessServerInitialResponse(Response, ServerPackageVersion, ServerPackageLicenseeVersion);

			// receive a list of the cache files and their timestamps
			TMap<FString, FDateTime> ServerCachedFiles;
			Response << ServerCachedFiles;

			bool bDeleteAllFiles = true;
			// Check the stored cooked version
			FString CookedVersionFile = FPaths::GeneratedConfigDir() / TEXT("CookedVersion.txt");

			if (InnerPlatformFile->FileExists(*CookedVersionFile) == true)
			{
				IFileHandle* FileHandle = InnerPlatformFile->OpenRead(*CookedVersionFile);
				if (FileHandle != NULL)
				{
					int32 StoredPackageCookedVersion;
					int32 StoredPackageCookedLicenseeVersion;
					if (FileHandle->Read((uint8*)&StoredPackageCookedVersion, sizeof(int32)) == true)
					{
						if (FileHandle->Read((uint8*)&StoredPackageCookedLicenseeVersion, sizeof(int32)) == true)
						{
							if ((ServerPackageVersion == StoredPackageCookedVersion) &&
								(ServerPackageLicenseeVersion == StoredPackageCookedLicenseeVersion))
							{
								bDeleteAllFiles = false;
							}
							else
							{
								UE_LOG(LogNetworkPlatformFile, Display, 
									TEXT("Engine version mismatch: Server %d.%d, Stored %d.%d\n"), 
									ServerPackageVersion, ServerPackageLicenseeVersion,
									StoredPackageCookedVersion, StoredPackageCookedLicenseeVersion);
							}
						}
					}

					delete FileHandle;
				}
			}
			else
			{
				UE_LOG(LogNetworkPlatformFile, Display, TEXT("Cooked version file missing: %s\n"), *CookedVersionFile);
			}

			if (bDeleteAllFiles == true)
			{
				// Make sure the config file exists...
				InnerPlatformFile->CreateDirectoryTree(*(FPaths::GeneratedConfigDir()));
				// Update the cooked version file
				IFileHandle* FileHandle = InnerPlatformFile->OpenWrite(*CookedVersionFile);
				if (FileHandle != NULL)
				{
					FileHandle->Write((const uint8*)&ServerPackageVersion, sizeof(int32));
					FileHandle->Write((const uint8*)&ServerPackageLicenseeVersion, sizeof(int32));
					delete FileHandle;
				}
			}

			// list of directories to skip
			TArray<FString> DirectoriesToSkip;
			TArray<FString> DirectoriesToNotRecurse;
			// use the timestamp grabbing visitor to get all the content times
			FLocalTimestampDirectoryVisitor Visitor(*InnerPlatformFile, DirectoriesToSkip, DirectoriesToNotRecurse, false);

			TArray<FString> RootContentPaths;
			FPackageName::QueryRootContentPaths( RootContentPaths );
			for( TArray<FString>::TConstIterator RootPathIt( RootContentPaths ); RootPathIt; ++RootPathIt )
			{
				const FString& RootPath = *RootPathIt;
				const FString& ContentFolder = FPackageName::LongPackageNameToFilename(RootPath);

				InnerPlatformFile->IterateDirectory( *ContentFolder, Visitor);
			}

			// delete out of date files using the server cached files
			for (TMap<FString, FDateTime>::TIterator It(ServerCachedFiles); It; ++It)
			{
				bool bDeleteFile = bDeleteAllFiles;
				FString ServerFile = It.Key();

				// Convert the filename to the client version
				ConvertServerFilenameToClientFilename(ServerFile);

				// Set it in the visitor file times list
				Visitor.FileTimes.Add(ServerFile, FDateTime::MinValue());

				if (bDeleteFile == false)
				{
					// Check the time stamps...
					// get local time
					FDateTime LocalTime = InnerPlatformFile->GetTimeStamp(*ServerFile);
					// If local time == MinValue than the file does not exist in the cache.
					if (LocalTime != FDateTime::MinValue())
					{
						FDateTime ServerTime = It.Value();
						// delete if out of date
						// We will use 1.0 second as the tolerance to cover any platform differences in resolution
						FTimespan TimeDiff = LocalTime - ServerTime;
						double TimeDiffInSeconds = TimeDiff.GetTotalSeconds();
						bDeleteFile = (TimeDiffInSeconds > 1.0) || (TimeDiffInSeconds < -1.0);
						if (bDeleteFile == true)
						{
							if (InnerPlatformFile->FileExists(*ServerFile) == true)
							{
								UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: TimeDiff %5.3f, %s"), TimeDiffInSeconds, *It.Key());
							}
							else
							{
								// It's a directory
								bDeleteFile = false;
							}
						}
					}
				}
				if (bDeleteFile == true)
				{
					InnerPlatformFile->DeleteFile(*ServerFile);
				}
			}

			// Any content files we have locally that were not cached, delete them
			for (TMap<FString, FDateTime>::TIterator It(Visitor.FileTimes); It; ++It)
			{
				if (It.Value() != FDateTime::MinValue())
				{
					// This was *not* found in the server file list... delete it
					UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: %s"), *It.Key());
					InnerPlatformFile->DeleteFile(*It.Key());
				}
			}

			// make sure we can sync a file
			FString TestSyncFile = FPaths::Combine(*(FPaths::EngineDir()), TEXT("Config/BaseEngine.ini"));

			InnerPlatformFile->SetReadOnly(*TestSyncFile, false);
			InnerPlatformFile->DeleteFile(*TestSyncFile);
			if (InnerPlatformFile->FileExists(*TestSyncFile))
			{
				UE_LOG(LogNetworkPlatformFile, Fatal, TEXT("Could not delete file sync test file %s."), *TestSyncFile);
			}

			EnsureFileIsLocal(TestSyncFile);

			if (!InnerPlatformFile->FileExists(*TestSyncFile) || InnerPlatformFile->FileSize(*TestSyncFile) < 1)
			{
				UE_LOG(LogNetworkPlatformFile, Fatal, TEXT("Could not sync test file %s."), *TestSyncFile);
			}
		}
	}

	FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Network file startup time: %5.3f seconds\n"), NetworkFileStartupTime);

}