Files
watrbx-game-engine/Client.LegacyAssemblies/Roblox.Common/Roblox.Common.Mime/MimeReader.cs
T
2025-09-18 17:55:52 -04:00

241 lines
5.5 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Mime;
namespace Roblox.Common.Mime;
public class MimeReader
{
public const string Crlf = "\r\n";
private static readonly char[] HeaderWhitespaceChars = new char[2] { ' ', '\t' };
private Queue<string> _lines;
private MimeEntity _entity;
private MimeReader()
{
_entity = new MimeEntity();
}
private MimeReader(MimeEntity entity, Queue<string> lines)
: this()
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
if (lines == null)
{
throw new ArgumentNullException("lines");
}
_lines = lines;
_entity = new MimeEntity(entity);
}
public MimeReader(string[] lines)
: this()
{
if (lines == null)
{
throw new ArgumentNullException("lines");
}
_lines = new Queue<string>(lines);
}
private int ParseHeaders()
{
string name = string.Empty;
string line = string.Empty;
while (_lines.Count > 0 && !string.IsNullOrEmpty(_lines.Peek()))
{
line = _lines.Dequeue();
if (line.StartsWith(" ") || line.StartsWith(Convert.ToString('\t')))
{
_entity.Headers[name] = _entity.Headers[name] + line;
continue;
}
int idx = line.IndexOf(':');
if (idx >= 0)
{
string key = line.Substring(0, idx);
string value = line.Substring(idx + 1).Trim(HeaderWhitespaceChars);
_entity.Headers.Add(key.ToLower(), value);
name = key;
}
}
if (_lines.Count > 0)
{
_lines.Dequeue();
}
return _entity.Headers.Count;
}
private void ProcessHeaders()
{
string[] allKeys = _entity.Headers.AllKeys;
foreach (string headerName in allKeys)
{
switch (headerName)
{
case "content-description":
_entity.ContentDescription = _entity.Headers[headerName];
break;
case "content-disposition":
_entity.ContentDisposition = new ContentDisposition(_entity.Headers[headerName]);
break;
case "content-id":
_entity.ContentId = _entity.Headers[headerName];
break;
case "content-transfer-encoding":
_entity.TransferEncoding = _entity.Headers[headerName];
_entity.ContentTransferEncoding = GetTransferEncoding(_entity.Headers[headerName]);
break;
case "content-type":
_entity.SetContentType(GetContentType(_entity.Headers[headerName]));
break;
case "mime-version":
_entity.MimeVersion = _entity.Headers[headerName];
break;
}
}
}
public MimeEntity CreateMimeEntity()
{
ParseHeaders();
ProcessHeaders();
ParseBody();
SetDecodedContentStream();
return _entity;
}
private void SetDecodedContentStream()
{
switch (_entity.ContentTransferEncoding)
{
case TransferEncoding.QuotedPrintable:
_entity.Content = new MemoryStream(GetBytes(QuotedPrintableEncoding.Decode(_entity.EncodedMessage.ToString())), writable: false);
break;
case TransferEncoding.Base64:
_entity.Content = new MemoryStream(Convert.FromBase64String(_entity.EncodedMessage.ToString()), writable: false);
break;
default:
_entity.Content = new MemoryStream(GetBytes(_entity.EncodedMessage.ToString()), writable: false);
break;
}
}
private byte[] GetBytes(string content)
{
using MemoryStream stream = new MemoryStream();
using (StreamWriter streamWriter = new StreamWriter(stream))
{
streamWriter.Write(content);
}
return stream.ToArray();
}
private void ParseBody()
{
if (_entity.HasBoundry)
{
while (_lines.Count > 0 && !string.Equals(_lines.Peek(), _entity.EndBoundry) && (_entity.Parent == null || !string.Equals(_entity.Parent.StartBoundry, _lines.Peek())))
{
if (string.Equals(_lines.Peek(), _entity.StartBoundry))
{
AddChildEntity(_entity, _lines);
continue;
}
if (string.Equals(_entity.ContentType.MediaType, MediaTypes.MessageRfc822, StringComparison.InvariantCultureIgnoreCase) && string.Equals(_entity.ContentDisposition.DispositionType, "attachment", StringComparison.InvariantCultureIgnoreCase))
{
AddChildEntity(_entity, _lines);
break;
}
_entity.EncodedMessage.Append(_lines.Dequeue() + "\r\n");
}
}
else
{
while (_lines.Count > 0)
{
_entity.EncodedMessage.Append(_lines.Dequeue() + "\r\n");
}
}
}
private void AddChildEntity(MimeEntity entity, Queue<string> lines)
{
MimeReader reader = new MimeReader(entity, lines);
entity.Children.Add(reader.CreateMimeEntity());
}
public static ContentType GetContentType(string contentType)
{
if (string.IsNullOrEmpty(contentType))
{
contentType = "text/plain; charset=us-ascii";
}
return new ContentType(contentType);
}
public static string GetMediaType(string mediaType)
{
if (string.IsNullOrEmpty(mediaType))
{
return MediaTypes.TextPlain;
}
return mediaType.Trim();
}
public static string GetMediaMainType(string mediaType)
{
int idx = mediaType.IndexOf('/');
if (idx < 0)
{
return mediaType;
}
return mediaType.Substring(0, idx);
}
public static string GetMediaSubType(string mediaType)
{
int idx = mediaType.IndexOf('/');
if (idx < 0)
{
if (mediaType.Equals("text"))
{
return "plain";
}
return string.Empty;
}
if (mediaType.Length > idx)
{
return mediaType.Substring(idx + 1);
}
if (GetMediaMainType(mediaType).Equals("text"))
{
return "plain";
}
return string.Empty;
}
public static TransferEncoding GetTransferEncoding(string transferEncoding)
{
switch (transferEncoding.Trim().ToLowerInvariant())
{
case "7bit":
case "8bit":
return TransferEncoding.SevenBit;
case "quoted-printable":
return TransferEncoding.QuotedPrintable;
case "base64":
return TransferEncoding.Base64;
default:
return TransferEncoding.Unknown;
}
}
}