151 lines
4.9 KiB
C#
151 lines
4.9 KiB
C#
using System.Text;
|
|
|
|
namespace PacketIO;
|
|
|
|
public class TreePacketFile
|
|
{
|
|
public static async ValueTask WriteTreeFiles(Stream stream, params IPacketFile[] files)
|
|
{
|
|
foreach (IPacketFile file in files)
|
|
{
|
|
await WriteTreeFile(stream, file).ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
public static async ValueTask WriteTreeFile(Stream stream, IPacketFile file)
|
|
{
|
|
byte fileType = (byte) file.GetFileType();
|
|
string fileName = file.GetFileName();
|
|
long fileSize = file.GetFileSize();
|
|
|
|
byte[] fileNameBuffer = Encoding.UTF8.GetBytes(fileName);
|
|
|
|
byte[] buffer = new byte[sizeof(byte) + sizeof(int) + sizeof(long) + fileNameBuffer.Length];
|
|
buffer[0] = fileType;
|
|
Array.Copy(BitConverter.GetBytes(fileNameBuffer.Length), 0, buffer, 1, sizeof(int));
|
|
Array.Copy(BitConverter.GetBytes(fileSize), 0, buffer, 5, sizeof(long));
|
|
Array.Copy(fileNameBuffer, 0, buffer, 13, fileNameBuffer.Length);
|
|
|
|
await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
|
|
|
switch (file.GetFileType())
|
|
{
|
|
case PacketFileType.Directory:
|
|
{
|
|
long fileCount = file.EnumerableFiles().LongCount();
|
|
buffer = BitConverter.GetBytes(fileCount);
|
|
await stream.WriteAsync(buffer, 0, sizeof(long));
|
|
|
|
await WriteTreeFiles(stream, file.EnumerableFiles().ToArray()).ConfigureAwait(false);
|
|
break;
|
|
}
|
|
case PacketFileType.File:
|
|
{
|
|
int c;
|
|
buffer = new byte[8192];
|
|
PacketFile packetFile = (PacketFile) file;
|
|
packetFile.Seek(0, SeekOrigin.Begin);
|
|
do
|
|
{
|
|
c = await packetFile.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
|
|
|
await stream.WriteAsync(buffer, 0, c).ConfigureAwait(false);
|
|
} while (c > 0);
|
|
break;
|
|
}
|
|
default:
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public static async ValueTask<IEnumerable<IPacketFile>> ReadTreeFiles(Stream stream)
|
|
{
|
|
List<IPacketFile> files = new List<IPacketFile>();
|
|
|
|
IPacketFile? file = null;
|
|
do
|
|
{
|
|
file = await ReadTreeFile(stream).ConfigureAwait(false);
|
|
if (file is object)
|
|
{
|
|
files.Add(file);
|
|
}
|
|
} while (file is object);
|
|
|
|
return files;
|
|
}
|
|
|
|
public static async ValueTask<IPacketFile?> ReadTreeFile(Stream stream)
|
|
{
|
|
byte[] buffer = new byte[sizeof(byte) + sizeof(int) + sizeof(long)];
|
|
int c = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
|
if (c <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
PacketFileType fileType = (PacketFileType) buffer[0];
|
|
int fileNameBufferSize = BitConverter.ToInt32(buffer, 1);
|
|
long fileSize = BitConverter.ToInt64(buffer, 5);
|
|
|
|
buffer = new byte[fileNameBufferSize];
|
|
c = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
|
if (c <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
string fileName = Encoding.UTF8.GetString(buffer);
|
|
|
|
switch (fileType)
|
|
{
|
|
case PacketFileType.Directory:
|
|
{
|
|
buffer = new byte[sizeof(long)];
|
|
c = await stream.ReadAsync(buffer, 0, buffer.Length);
|
|
if (c <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
long fileCount = BitConverter.ToInt64(buffer, 0);
|
|
|
|
PacketDirectory directory = new PacketDirectory(fileName);
|
|
for (long i = 0 ; i < fileCount ; i++)
|
|
{
|
|
IPacketFile? file = await ReadTreeFile(stream).ConfigureAwait(false);
|
|
if (file is null)
|
|
{
|
|
break;
|
|
}
|
|
|
|
directory.AddFile(file);
|
|
}
|
|
|
|
return directory;
|
|
}
|
|
case PacketFileType.File:
|
|
{
|
|
PacketFile file = new PacketFile(fileName);
|
|
|
|
buffer = new byte[8192];
|
|
long remainedSize = fileSize;
|
|
long readed = 0;
|
|
do
|
|
{
|
|
int leftSize = (int) Math.Min(buffer.Length, fileSize - readed);
|
|
c = await stream.ReadAsync(buffer, 0, leftSize).ConfigureAwait(false);
|
|
await file.WriteAsync(buffer, 0, c).ConfigureAwait(false);
|
|
remainedSize -= c;
|
|
readed += c;
|
|
} while (remainedSize > 0);
|
|
|
|
file.Seek(0, SeekOrigin.Begin);
|
|
return file;
|
|
}
|
|
default:
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
}
|