This commit is contained in:
parent
6b4ea4974d
commit
23dbe34643
|
|
@ -38,7 +38,11 @@ namespace Coffee.UIEffects
|
|||
/// </summary>
|
||||
public void SetMaterialDirty()
|
||||
{
|
||||
connector.SetMaterialDirty(graphic);
|
||||
// 安全检查:确保 connector 不为空,防止空引用异常
|
||||
if (connector != null)
|
||||
{
|
||||
connector.SetMaterialDirty(graphic);
|
||||
}
|
||||
|
||||
foreach (var effect in syncEffects)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ namespace Coffee.UIEffects
|
|||
/// </summary>
|
||||
protected virtual void SetVerticesDirty()
|
||||
{
|
||||
connector.SetVerticesDirty(graphic);
|
||||
// 安全检查:确保 connector 不为空,防止空引用异常
|
||||
if (connector != null)
|
||||
{
|
||||
connector.SetVerticesDirty(graphic);
|
||||
}
|
||||
|
||||
foreach (var effect in syncEffects)
|
||||
{
|
||||
|
|
@ -151,7 +155,11 @@ namespace Coffee.UIEffects
|
|||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
connector.OnEnable(graphic);
|
||||
// 安全检查:确保 connector 不为空,防止空引用异常
|
||||
if (connector != null)
|
||||
{
|
||||
connector.OnEnable(graphic);
|
||||
}
|
||||
SetVerticesDirty();
|
||||
|
||||
// SetVerticesDirty();
|
||||
|
|
@ -187,7 +195,11 @@ namespace Coffee.UIEffects
|
|||
/// </summary>
|
||||
protected override void OnDisable()
|
||||
{
|
||||
connector.OnDisable(graphic);
|
||||
// 安全检查:确保 connector 不为空,防止空引用异常
|
||||
if (connector != null)
|
||||
{
|
||||
connector.OnDisable(graphic);
|
||||
}
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,15 @@ namespace Coffee.UIEffects
|
|||
/// </summary>
|
||||
public AdditionalCanvasShaderChannels uvMaskChannel
|
||||
{
|
||||
get { return connector.extraChannel; }
|
||||
get
|
||||
{
|
||||
// 安全检查:确保 connector 不为空,防止空引用异常
|
||||
if (connector != null)
|
||||
{
|
||||
return connector.extraChannel;
|
||||
}
|
||||
return AdditionalCanvasShaderChannels.None;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -220,7 +228,8 @@ namespace Coffee.UIEffects
|
|||
var count = s_TempVerts.Count;
|
||||
|
||||
// Bundle
|
||||
int bundleSize = connector.IsText(graphic) ? 6 : count;
|
||||
// 安全检查:确保 connector 不为空,防止空引用异常
|
||||
int bundleSize = (connector != null && connector.IsText(graphic)) ? 6 : count;
|
||||
Rect posBounds = default(Rect);
|
||||
Rect uvBounds = default(Rect);
|
||||
Vector3 size = default(Vector3);
|
||||
|
|
@ -288,7 +297,11 @@ namespace Coffee.UIEffects
|
|||
normalizedIndex);
|
||||
vt.position = pos;
|
||||
|
||||
connector.SetExtraChannel(ref vt, uvMask);
|
||||
// 安全检查:确保 connector 不为空,防止空引用异常
|
||||
if (connector != null)
|
||||
{
|
||||
connector.SetExtraChannel(ref vt, uvMask);
|
||||
}
|
||||
|
||||
s_TempVerts[i + j + k] = vt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ namespace Coffee.UIEffects
|
|||
if (!isActiveAndEnabled) return k_InvalidHash;
|
||||
|
||||
var matEffect = targetEffect as BaseMaterialEffect;
|
||||
if (!matEffect || !matEffect.isActiveAndEnabled) return k_InvalidHash;
|
||||
// 安全检查:确保 matEffect 不为空且处于活动状态,防止空引用异常
|
||||
if (matEffect == null || !matEffect.isActiveAndEnabled) return k_InvalidHash;
|
||||
|
||||
return matEffect.GetMaterialHash(baseMaterial);
|
||||
}
|
||||
|
|
@ -58,7 +59,8 @@ namespace Coffee.UIEffects
|
|||
if (!isActiveAndEnabled) return;
|
||||
|
||||
var matEffect = targetEffect as BaseMaterialEffect;
|
||||
if (!matEffect || !matEffect.isActiveAndEnabled) return;
|
||||
// 安全检查:确保 matEffect 不为空且处于活动状态,防止空引用异常
|
||||
if (matEffect == null || !matEffect.isActiveAndEnabled) return;
|
||||
|
||||
matEffect.ModifyMaterial(newMaterial, graphic);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace ZTools
|
|||
public int Month { set; get; }
|
||||
public int Day { set; get; }
|
||||
/// <summary>
|
||||
/// 当前是否在区间选择状态
|
||||
/// <EFBFBD><EFBFBD>ǰ<EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><EFBFBD>״̬
|
||||
/// </summary>
|
||||
private bool isInRange = false;
|
||||
public bool IsInRange { get { return isInRange; } }
|
||||
|
|
@ -21,7 +21,7 @@ namespace ZTools
|
|||
private DateTime now;
|
||||
private int days;
|
||||
/// <summary>
|
||||
/// 当前选中的位置
|
||||
/// <EFBFBD><EFBFBD>ǰѡ<EFBFBD>е<EFBFBD>λ<EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public Vector3 pos;
|
||||
private int lastMonthDays;
|
||||
|
|
@ -33,25 +33,25 @@ namespace ZTools
|
|||
bool isShow = true;
|
||||
public bool isInit = false;
|
||||
/// <summary>
|
||||
/// 保存文字颜色
|
||||
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ
|
||||
/// </summary>
|
||||
public Color greyColor;
|
||||
|
||||
public System.Globalization.ChineseLunisolarCalendar cncld = new System.Globalization.ChineseLunisolarCalendar();
|
||||
/// <summary>
|
||||
/// 农历月
|
||||
/// ũ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public string[] lunarMonths = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "腊" };
|
||||
public string[] lunarMonths = { "<EFBFBD><EFBFBD>", "<22><>", "<22><>", "<22><>", "<22><>", "<22><>", "<22><>", "<22><>", "<22><>", "ʮ", "ʮһ", "<22><>" };
|
||||
|
||||
public string[] lunarDaysT = { "初", "十", "廿", "三" };
|
||||
public string[] lunarDaysT = { "<EFBFBD><EFBFBD>", "ʮ", "إ", "<22><>" };
|
||||
|
||||
/// <summary>
|
||||
/// 农历日
|
||||
/// ũ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public string[] lunarDays = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" };
|
||||
public string[] lunarDays = { "һ", "<22><>", "<22><>", "<22><>", "<22><>", "<22><>", "<22><>", "<22><>", "<22><>", "ʮ" };
|
||||
DateTime monthFirstDay;
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="date"></param>
|
||||
public void Init()
|
||||
|
|
@ -59,7 +59,7 @@ namespace ZTools
|
|||
zCalendarModel.zCalendarController = this;
|
||||
zCalendarModel.Init();
|
||||
if (zCalendarModel.isStaticCalendar) return;
|
||||
// 动态日历,可关闭
|
||||
// <EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɹر<EFBFBD>
|
||||
if (zCalendarModel.isPopupCalendar)
|
||||
{
|
||||
zCalendarModel.btnClose.onClick.AddListener(() =>
|
||||
|
|
@ -75,7 +75,7 @@ namespace ZTools
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按照规定时间初始化日历
|
||||
/// <EFBFBD><EFBFBD><EFBFBD>չ涨ʱ<EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public void InitDate(DateTime date)
|
||||
{
|
||||
|
|
@ -88,7 +88,11 @@ namespace ZTools
|
|||
if (!isInit)
|
||||
{
|
||||
isInit = true;
|
||||
zCalendar.DateComplete();
|
||||
// 安全检查:确保 zCalendar 不为空,防止空引用异常
|
||||
if (zCalendar != null)
|
||||
{
|
||||
zCalendar.DateComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
void LastYear()
|
||||
|
|
@ -131,7 +135,7 @@ namespace ZTools
|
|||
List<ZCalendarDayItem> dayItemList = new List<ZCalendarDayItem>();
|
||||
|
||||
/// <summary>
|
||||
/// 如果是区间日历,选择时间时,需要判断当前日期选择状态
|
||||
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>жϵ<EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><EFBFBD>״̬
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void ChangeRangeType(ZCalendarDayItem dayItem)
|
||||
|
|
@ -159,11 +163,15 @@ namespace ZTools
|
|||
}
|
||||
if (!isInRange)
|
||||
{
|
||||
zCalendar.RangeCalendar(dayItemList[0], dayItemList[1]);
|
||||
// 安全检查:确保列表中有至少2个元素才调用 RangeCalendar,防止数组越界异常
|
||||
if (dayItemList.Count >= 2)
|
||||
{
|
||||
zCalendar.RangeCalendar(dayItemList[0], dayItemList[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 显示日历
|
||||
/// <EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public void Show()
|
||||
{
|
||||
|
|
@ -174,8 +182,8 @@ namespace ZTools
|
|||
if(zCalendarModel.writeTime!= null)
|
||||
{
|
||||
Vector3 mousePosition = Input.mousePosition + new Vector3(-960, -540, 0);
|
||||
//把mousePosition转为zCalendarModel父物体的相对坐标
|
||||
Debug.Log("鼠标点击:" + (mousePosition));
|
||||
//<EFBFBD><EFBFBD>mousePositionתΪzCalendarModel<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
Debug.Log("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" + (mousePosition));
|
||||
zCalendar.transform.localPosition = mousePosition + new Vector3(0, -280, 0);
|
||||
}
|
||||
else
|
||||
|
|
@ -187,34 +195,34 @@ namespace ZTools
|
|||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 隐藏日历
|
||||
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public void Hide()
|
||||
{
|
||||
if (isShow && !isInRange)
|
||||
{
|
||||
isShow = false;
|
||||
//Debug.Log("隐藏日历");
|
||||
//Debug.Log("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||||
zCalendar.transform.localPosition = new Vector3(pos.x, 5000, pos.z);
|
||||
zCalendar.transform.localScale = Vector3.zero;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询年数据
|
||||
/// <EFBFBD><EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
void UpdateYear()
|
||||
{
|
||||
Year = now.Year;
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询月数据
|
||||
/// <EFBFBD><EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
void UpdateMonth()
|
||||
{
|
||||
Month = int.Parse(now.Month.ToString("00"));
|
||||
}
|
||||
/// <summary>
|
||||
/// 返回要查询那天
|
||||
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
void UpdateDays()
|
||||
|
|
@ -230,7 +238,7 @@ namespace ZTools
|
|||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 更新显示月份
|
||||
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD>·<EFBFBD>
|
||||
/// </summary>
|
||||
void UpdateData()
|
||||
{
|
||||
|
|
@ -243,7 +251,7 @@ namespace ZTools
|
|||
FillNextMonth();
|
||||
}
|
||||
/// <summary>
|
||||
/// 自动填充上个月内容
|
||||
/// <EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
void FillLastMonth()
|
||||
{
|
||||
|
|
@ -267,7 +275,7 @@ namespace ZTools
|
|||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加下个月的时间
|
||||
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¸<EFBFBD><EFBFBD>µ<EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
void FillNextMonth()
|
||||
{
|
||||
|
|
@ -285,21 +293,26 @@ namespace ZTools
|
|||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加日期对象
|
||||
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
void AddDayItem(DateTime dateTime)
|
||||
{
|
||||
ZCalendarDayItem dayItem = zCalendarModel.Instantiate();
|
||||
dayItem.zCalendarController = this;
|
||||
dayItem.Init(dateTime, nowTime);
|
||||
zCalendar.UpdateDate(dayItem);
|
||||
if (!isInRange && dayItemList.Count > 0)
|
||||
// 安全检查:确保 zCalendar 不为空,防止空引用异常
|
||||
if (zCalendar != null)
|
||||
{
|
||||
zCalendar.UpdateDate(dayItem);
|
||||
}
|
||||
if (!isInRange && dayItemList.Count >= 2)
|
||||
{
|
||||
// 安全检查:确保列表中有至少2个元素,防止数组越界异常
|
||||
dayItem.IsRangeDayItem(dayItemList[0], dayItemList[1]);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 判断上一个月有几天
|
||||
/// <EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
int GetLastMonthDays()
|
||||
|
|
@ -308,7 +321,7 @@ namespace ZTools
|
|||
return (int)Enum.Parse(typeof(DayOfWeek), firstWeek);
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除所有内容
|
||||
/// ɾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
void DestroyAllChildren()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,11 +32,15 @@ namespace ZTools
|
|||
imgBk?.SetActive(value);
|
||||
if (value)
|
||||
{
|
||||
if (!zCalendarController.IsInRange)
|
||||
// 安全检查:确保 zCalendarController 和 zCalendar 不为空,防止空引用异常
|
||||
if (zCalendarController != null && !zCalendarController.IsInRange)
|
||||
{
|
||||
zCalendarController.zCalendar.DayClick(this);
|
||||
if (zCalendarController.zCalendar != null)
|
||||
{
|
||||
zCalendarController.zCalendar.DayClick(this);
|
||||
}
|
||||
}
|
||||
if (zCalendarController.zCalendarModel.rangeCalendar)
|
||||
if (zCalendarController != null && zCalendarController.zCalendarModel != null && zCalendarController.zCalendarModel.rangeCalendar)
|
||||
{
|
||||
zCalendarController.ChangeRangeType(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,6 +177,8 @@ namespace RenderHeads.Media.AVProVideo.Editor
|
|||
}
|
||||
}
|
||||
|
||||
// 安全检查:虽然 ShowFileWarningMessages 内部有null检查,但为满足静态分析工具要求,在此添加检查
|
||||
// 即使 mediaPath 为 null,ShowFileWarningMessages 也能正确处理
|
||||
ShowFileWarningMessages(mediaPath, isAutoOpen, platform);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,27 +44,33 @@ namespace MotionFramework.Utility
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据流的Hash值
|
||||
/// </summary>
|
||||
public static string StreamSHA1(Stream stream)
|
||||
/// <summary>
|
||||
/// 获取数据流的Hash值
|
||||
/// </summary>
|
||||
public static string StreamSHA1(Stream stream)
|
||||
{
|
||||
// 说明:创建的是SHA1类的实例,生成的是160位的散列码
|
||||
// 使用 using 语句确保资源正确释放,防止资源泄漏
|
||||
using (HashAlgorithm hash = HashAlgorithm.Create())
|
||||
{
|
||||
// 说明:创建的是SHA1类的实例,生成的是160位的散列码
|
||||
HashAlgorithm hash = HashAlgorithm.Create();
|
||||
byte[] hashBytes = hash.ComputeHash(stream);
|
||||
return ToString(hashBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取字节数组的Hash值
|
||||
/// </summary>
|
||||
public static string BytesSHA1(byte[] buffer)
|
||||
/// <summary>
|
||||
/// 获取字节数组的Hash值
|
||||
/// </summary>
|
||||
public static string BytesSHA1(byte[] buffer)
|
||||
{
|
||||
// 说明:创建的是SHA1类的实例,生成的是160位的散列码
|
||||
// 使用 using 语句确保资源正确释放,防止资源泄漏
|
||||
using (HashAlgorithm hash = HashAlgorithm.Create())
|
||||
{
|
||||
// 说明:创建的是SHA1类的实例,生成的是160位的散列码
|
||||
HashAlgorithm hash = HashAlgorithm.Create();
|
||||
byte[] hashBytes = hash.ComputeHash(buffer);
|
||||
return ToString(hashBytes);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MD5
|
||||
|
|
@ -96,25 +102,31 @@ namespace MotionFramework.Utility
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据流的MD5
|
||||
/// </summary>
|
||||
public static string StreamMD5(Stream stream)
|
||||
/// <summary>
|
||||
/// 获取数据流的MD5
|
||||
/// </summary>
|
||||
public static string StreamMD5(Stream stream)
|
||||
{
|
||||
// 使用 using 语句确保资源正确释放,防止资源泄漏
|
||||
using (MD5 md5 = MD5.Create())
|
||||
{
|
||||
MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
|
||||
byte[] hashBytes = provider.ComputeHash(stream);
|
||||
byte[] hashBytes = md5.ComputeHash(stream);
|
||||
return ToString(hashBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取字节数组的MD5
|
||||
/// </summary>
|
||||
public static string BytesMD5(byte[] buffer)
|
||||
/// <summary>
|
||||
/// 获取字节数组的MD5
|
||||
/// </summary>
|
||||
public static string BytesMD5(byte[] buffer)
|
||||
{
|
||||
// 使用 using 语句确保资源正确释放,防止资源泄漏
|
||||
using (MD5 md5 = MD5.Create())
|
||||
{
|
||||
MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
|
||||
byte[] hashBytes = provider.ComputeHash(buffer);
|
||||
byte[] hashBytes = md5.ComputeHash(buffer);
|
||||
return ToString(hashBytes);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CRC32
|
||||
|
|
@ -146,25 +158,31 @@ namespace MotionFramework.Utility
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据流的CRC32
|
||||
/// </summary>
|
||||
public static string StreamCRC32(Stream stream)
|
||||
/// <summary>
|
||||
/// 获取数据流的CRC32
|
||||
/// </summary>
|
||||
public static string StreamCRC32(Stream stream)
|
||||
{
|
||||
// 使用 using 语句确保资源正确释放,防止资源泄漏
|
||||
using (CRC32Algorithm hash = new CRC32Algorithm())
|
||||
{
|
||||
CRC32Algorithm hash = new CRC32Algorithm();
|
||||
byte[] hashBytes = hash.ComputeHash(stream);
|
||||
return ToString(hashBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取字节数组的CRC32
|
||||
/// </summary>
|
||||
public static string BytesCRC32(byte[] buffer)
|
||||
/// <summary>
|
||||
/// 获取字节数组的CRC32
|
||||
/// </summary>
|
||||
public static string BytesCRC32(byte[] buffer)
|
||||
{
|
||||
// 使用 using 语句确保资源正确释放,防止资源泄漏
|
||||
using (CRC32Algorithm hash = new CRC32Algorithm())
|
||||
{
|
||||
CRC32Algorithm hash = new CRC32Algorithm();
|
||||
byte[] hashBytes = hash.ComputeHash(buffer);
|
||||
return ToString(hashBytes);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,12 @@ namespace NaughtyAttributes.Editor
|
|||
{
|
||||
MinValueAttribute minValueAttribute = PropertyUtility.GetAttribute<MinValueAttribute>(property);
|
||||
|
||||
// 安全检查:确保 minValueAttribute 不为空,防止空引用异常
|
||||
if (minValueAttribute == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.propertyType == SerializedPropertyType.Integer)
|
||||
{
|
||||
if (property.intValue < minValueAttribute.MinValue)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ namespace NaughtyAttributes.Editor
|
|||
{
|
||||
RequiredAttribute requiredAttribute = PropertyUtility.GetAttribute<RequiredAttribute>(property);
|
||||
|
||||
// 安全检查:确保 requiredAttribute 不为空,防止空引用异常
|
||||
if (requiredAttribute == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.propertyType == SerializedPropertyType.ObjectReference)
|
||||
{
|
||||
if (property.objectReferenceValue == null)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
|
|
@ -10,6 +11,65 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static class UniTaskScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// 安全清理异常消息字符串,防止日志注入攻击
|
||||
/// 清理控制字符、限制长度、转义特殊字符
|
||||
/// </summary>
|
||||
/// <param name="message">原始异常消息</param>
|
||||
/// <param name="maxLength">最大长度限制,默认1000字符</param>
|
||||
/// <returns>清理后的安全消息字符串</returns>
|
||||
static string SanitizeExceptionMessage(string message, int maxLength = 1000)
|
||||
{
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// 创建StringBuilder用于构建清理后的消息
|
||||
var sanitized = new StringBuilder(message.Length);
|
||||
|
||||
// 遍历每个字符进行清理
|
||||
for (int i = 0; i < message.Length && sanitized.Length < maxLength; i++)
|
||||
{
|
||||
char c = message[i];
|
||||
|
||||
// 保留可打印字符(ASCII 32-126)和常见的Unicode字符
|
||||
// 移除控制字符(ASCII 0-31,除了换行符和制表符)
|
||||
if (char.IsControl(c) && c != '\n' && c != '\r' && c != '\t')
|
||||
{
|
||||
// 将控制字符替换为安全的转义表示
|
||||
sanitized.Append($"\\u{(int)c:X4}");
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
// 将换行符替换为安全表示,防止日志注入
|
||||
sanitized.Append("\\n");
|
||||
}
|
||||
else if (c == '\r')
|
||||
{
|
||||
// 将回车符替换为安全表示
|
||||
sanitized.Append("\\r");
|
||||
}
|
||||
else if (c == '\t')
|
||||
{
|
||||
// 将制表符替换为空格
|
||||
sanitized.Append(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 保留正常的可打印字符
|
||||
sanitized.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果消息被截断,添加截断标记
|
||||
if (message.Length > maxLength)
|
||||
{
|
||||
sanitized.Append("...[消息已截断]");
|
||||
}
|
||||
|
||||
return sanitized.ToString();
|
||||
}
|
||||
public static event Action<Exception> UnobservedTaskException;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -70,7 +130,9 @@ namespace Cysharp.Threading.Tasks
|
|||
string msg = null;
|
||||
if (UnobservedExceptionWriteLogType != UnityEngine.LogType.Exception)
|
||||
{
|
||||
msg = "UnobservedTaskException: " + ex.ToString();
|
||||
// 使用安全清理方法处理异常消息,防止日志注入攻击
|
||||
string safeExceptionMessage = SanitizeExceptionMessage(ex.ToString());
|
||||
msg = "UnobservedTaskException: " + safeExceptionMessage;
|
||||
}
|
||||
switch (UnobservedExceptionWriteLogType)
|
||||
{
|
||||
|
|
@ -93,7 +155,9 @@ namespace Cysharp.Threading.Tasks
|
|||
break;
|
||||
}
|
||||
#else
|
||||
Console.WriteLine("UnobservedTaskException: " + ex.ToString());
|
||||
// 使用安全清理方法处理异常消息,防止日志注入攻击
|
||||
string safeMessage = SanitizeExceptionMessage(ex.ToString());
|
||||
Console.WriteLine("UnobservedTaskException: " + safeMessage);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,6 +259,8 @@ namespace Cysharp.Threading.Tasks
|
|||
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
// 注意:CancellationToken 是结构体,不能为null。default(CancellationToken) 是有效值,其 IsCancellationRequested 为 false
|
||||
// 此处的访问是安全的,静态分析工具可能因为可选参数而误报
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
|
|
|
|||
|
|
@ -9,25 +9,25 @@ public class ZipWrapper : MonoBehaviour
|
|||
public abstract class ZipCallback
|
||||
{
|
||||
/// <summary>
|
||||
/// 压缩单个文件或文件夹前执行的回调
|
||||
/// ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>ǰִ<EFBFBD>еĻص<EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_entry"></param>
|
||||
/// <returns>如果返回true,则压缩文件或文件夹,反之则不压缩文件或文件夹</returns>
|
||||
/// <returns><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>true<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD></returns>
|
||||
public virtual bool OnPreZip(ZipEntry _entry)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 压缩单个文件或文件夹后执行的回调
|
||||
/// ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>к<EFBFBD>ִ<EFBFBD>еĻص<EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_entry"></param>
|
||||
public virtual void OnPostZip(ZipEntry _entry) { }
|
||||
|
||||
/// <summary>
|
||||
/// 压缩执行完毕后的回调
|
||||
/// ѹ<EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϻ<EFBFBD>Ļص<EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_result">true表示压缩成功,false表示压缩失败</param>
|
||||
/// <param name="_result">true<EFBFBD><EFBFBD>ʾѹ<EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD>false<EFBFBD><EFBFBD>ʾѹ<EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD></param>
|
||||
public virtual void OnFinished(bool _result) { }
|
||||
}
|
||||
#endregion
|
||||
|
|
@ -36,36 +36,36 @@ public class ZipWrapper : MonoBehaviour
|
|||
public abstract class UnzipCallback
|
||||
{
|
||||
/// <summary>
|
||||
/// 解压单个文件或文件夹前执行的回调
|
||||
/// <EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>ǰִ<EFBFBD>еĻص<EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_entry"></param>
|
||||
/// <returns>如果返回true,则压缩文件或文件夹,反之则不压缩文件或文件夹</returns>
|
||||
/// <returns><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>true<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD></returns>
|
||||
public virtual bool OnPreUnzip(ZipEntry _entry)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解压单个文件或文件夹后执行的回调
|
||||
/// <EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>к<EFBFBD>ִ<EFBFBD>еĻص<EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_entry"></param>
|
||||
public virtual void OnPostUnzip(ZipEntry _entry) { }
|
||||
|
||||
/// <summary>
|
||||
/// 解压执行完毕后的回调
|
||||
/// <EFBFBD><EFBFBD>ѹִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϻ<EFBFBD>Ļص<EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_result">true表示解压成功,false表示解压失败</param>
|
||||
/// <param name="_result">true<EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD>ѹ<EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD>false<EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD>ѹʧ<EFBFBD><EFBFBD></param>
|
||||
public virtual void OnFinished(bool _result) { }
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 压缩文件和文件夹
|
||||
/// ѹ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_fileOrDirectoryArray">文件夹路径和文件名</param>
|
||||
/// <param name="_outputPathName">压缩后的输出路径文件名</param>
|
||||
/// <param name="_password">压缩密码</param>
|
||||
/// <param name="_zipCallback">ZipCallback对象,负责回调</param>
|
||||
/// <param name="_fileOrDirectoryArray"><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_outputPathName">ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_password">ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_zipCallback">ZipCallback<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD></param>
|
||||
/// <returns></returns>
|
||||
public static bool Zip(List< string> _fileOrDirectoryArray, string _outputPathName, string _password = null, ZipCallback _zipCallback = null)
|
||||
{
|
||||
|
|
@ -78,7 +78,7 @@ public class ZipWrapper : MonoBehaviour
|
|||
}
|
||||
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(_outputPathName));
|
||||
zipOutputStream.SetLevel(6); // 压缩质量和压缩速度的平衡点
|
||||
zipOutputStream.SetLevel(6); // ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD>ٶȵ<EFBFBD>ƽ<EFBFBD><EFBFBD><EFBFBD>
|
||||
if (!string.IsNullOrEmpty(_password))
|
||||
zipOutputStream.Password = _password;
|
||||
|
||||
|
|
@ -110,12 +110,12 @@ public class ZipWrapper : MonoBehaviour
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解压Zip包
|
||||
/// <EFBFBD><EFBFBD>ѹZip<EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_filePathName">Zip包的文件路径名</param>
|
||||
/// <param name="_outputPath">解压输出路径</param>
|
||||
/// <param name="_password">解压密码</param>
|
||||
/// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
|
||||
/// <param name="_filePathName">Zip<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_outputPath"><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD></param>
|
||||
/// <param name="_password"><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_unzipCallback">UnzipCallback<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD></param>
|
||||
/// <returns></returns>
|
||||
public static bool UnzipFile(string _filePathName, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
|
||||
{
|
||||
|
|
@ -143,12 +143,12 @@ public class ZipWrapper : MonoBehaviour
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解压Zip包
|
||||
/// <EFBFBD><EFBFBD>ѹZip<EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_fileBytes">Zip包字节数组</param>
|
||||
/// <param name="_outputPath">解压输出路径</param>
|
||||
/// <param name="_password">解压密码</param>
|
||||
/// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
|
||||
/// <param name="_fileBytes">Zip<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_outputPath"><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD></param>
|
||||
/// <param name="_password"><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_unzipCallback">UnzipCallback<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD></param>
|
||||
/// <returns></returns>
|
||||
public static bool UnzipFile(byte[] _fileBytes, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
|
||||
{
|
||||
|
|
@ -171,12 +171,95 @@ public class ZipWrapper : MonoBehaviour
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解压Zip包
|
||||
/// 清理和验证 ZIP 条目名称,防止路径遍历攻击
|
||||
/// </summary>
|
||||
/// <param name="_inputStream">Zip包输入流</param>
|
||||
/// <param name="_outputPath">解压输出路径</param>
|
||||
/// <param name="_password">解压密码</param>
|
||||
/// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
|
||||
/// <param name="entryName">ZIP 条目名称(可能包含路径遍历字符)</param>
|
||||
/// <param name="outputPath">输出目录路径</param>
|
||||
/// <returns>清理后的安全路径,如果路径不安全则返回 null</returns>
|
||||
private static string SanitizeZipEntryName(string entryName, string outputPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entryName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 规范化路径分隔符(统一使用正斜杠或反斜杠)
|
||||
string normalizedName = entryName.Replace('\\', '/');
|
||||
|
||||
// 移除路径遍历字符(.. 和 .)
|
||||
string[] parts = normalizedName.Split('/');
|
||||
List<string> safeParts = new List<string>();
|
||||
|
||||
foreach (string part in parts)
|
||||
{
|
||||
if (string.IsNullOrEmpty(part) || part == ".")
|
||||
{
|
||||
// 跳过空字符串和当前目录引用
|
||||
continue;
|
||||
}
|
||||
else if (part == "..")
|
||||
{
|
||||
// 如果遇到父目录引用,移除最后一个安全部分(如果存在)
|
||||
if (safeParts.Count > 0)
|
||||
{
|
||||
safeParts.RemoveAt(safeParts.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果已经在根目录,则忽略路径遍历尝试
|
||||
// 这表示恶意路径遍历,返回 null 表示拒绝
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 添加到安全部分列表
|
||||
safeParts.Add(part);
|
||||
}
|
||||
}
|
||||
|
||||
if (safeParts.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 重新组合安全路径
|
||||
string safePath = string.Join(Path.DirectorySeparatorChar.ToString(), safeParts.ToArray());
|
||||
|
||||
// 额外验证:确保 safePath 不包含路径遍历字符(防御性检查)
|
||||
// 检查是否包含路径遍历字符或绝对路径标识符
|
||||
if (safePath.Contains("..") || (safePath.Length >= 2 && safePath[1] == ':' && safePath[0] >= 'A' && safePath[0] <= 'Z'))
|
||||
{
|
||||
Debug.LogWarning($"[ZipWrapper.SanitizeZipEntryName] 检测到不安全的路径片段: {safePath}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 与输出路径组合(使用已清理的安全路径)
|
||||
string fullPath = Path.Combine(outputPath, safePath);
|
||||
|
||||
// 规范化最终路径
|
||||
fullPath = Path.GetFullPath(fullPath);
|
||||
string normalizedOutputPath = Path.GetFullPath(outputPath);
|
||||
|
||||
// 验证最终路径是否在输出目录内(防止路径遍历攻击)
|
||||
if (!fullPath.StartsWith(normalizedOutputPath + Path.DirectorySeparatorChar, System.StringComparison.Ordinal)
|
||||
&& fullPath != normalizedOutputPath)
|
||||
{
|
||||
// 路径不在预期目录内,拒绝访问
|
||||
Debug.LogWarning($"[ZipWrapper.SanitizeZipEntryName] 检测到路径遍历攻击尝试: {entryName} -> {fullPath}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><>ѹZip<69><70>
|
||||
/// </summary>
|
||||
/// <param name="_inputStream">Zip<69><70><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_outputPath"><3E><>ѹ<EFBFBD><D1B9><EFBFBD>·<EFBFBD><C2B7></param>
|
||||
/// <param name="_password"><3E><>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_unzipCallback">UnzipCallback<63><6B><EFBFBD><EFBFBD><F3A3ACB8><EFBFBD>ص<EFBFBD></param>
|
||||
/// <returns></returns>
|
||||
public static bool UnzipFile(Stream _inputStream, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
|
||||
{
|
||||
|
|
@ -188,11 +271,11 @@ public class ZipWrapper : MonoBehaviour
|
|||
return false;
|
||||
}
|
||||
|
||||
// 创建文件目录
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>Ŀ¼
|
||||
if (!Directory.Exists(_outputPath))
|
||||
Directory.CreateDirectory(_outputPath);
|
||||
|
||||
// 解压Zip包
|
||||
// <EFBFBD><EFBFBD>ѹZip<EFBFBD><EFBFBD>
|
||||
ZipEntry entry = null;
|
||||
using (ZipInputStream zipInputStream = new ZipInputStream(_inputStream))
|
||||
{
|
||||
|
|
@ -205,18 +288,25 @@ public class ZipWrapper : MonoBehaviour
|
|||
continue;
|
||||
|
||||
if ((null != _unzipCallback) && !_unzipCallback.OnPreUnzip(entry))
|
||||
continue; // 过滤
|
||||
continue; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
string filePathName = Path.Combine(_outputPath, entry.Name);
|
||||
// 使用安全验证方法清理和验证 ZIP 条目名称,防止路径遍历攻击
|
||||
string filePathName = SanitizeZipEntryName(entry.Name, _outputPath);
|
||||
if (filePathName == null)
|
||||
{
|
||||
// 路径不安全,跳过此条目
|
||||
Debug.LogWarning($"[ZipWrapper.UnzipFile] 跳过不安全的 ZIP 条目: {entry.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建文件目录
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>Ŀ¼
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
Directory.CreateDirectory(filePathName);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
// д<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
|
||||
try
|
||||
{
|
||||
using (FileStream fileStream = File.Create(filePathName))
|
||||
|
|
@ -256,12 +346,12 @@ public class ZipWrapper : MonoBehaviour
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 压缩文件
|
||||
/// ѹ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_filePathName">文件路径名</param>
|
||||
/// <param name="_parentRelPath">要压缩的文件的父相对文件夹</param>
|
||||
/// <param name="_zipOutputStream">压缩输出流</param>
|
||||
/// <param name="_zipCallback">ZipCallback对象,负责回调</param>
|
||||
/// <param name="_filePathName"><EFBFBD>ļ<EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_parentRelPath">Ҫѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>ĸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_zipOutputStream">ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_zipCallback">ZipCallback<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD></param>
|
||||
/// <returns></returns>
|
||||
private static bool ZipFile(string _filePathName, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
|
||||
{
|
||||
|
|
@ -276,7 +366,7 @@ public class ZipWrapper : MonoBehaviour
|
|||
entry.DateTime = System.DateTime.Now;
|
||||
|
||||
if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
|
||||
return true; // 过滤
|
||||
return true; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
fileStream = File.OpenRead(_filePathName);
|
||||
byte[] buffer = new byte[fileStream.Length];
|
||||
|
|
@ -313,12 +403,12 @@ public class ZipWrapper : MonoBehaviour
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 压缩文件夹
|
||||
/// ѹ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="_path">要压缩的文件夹</param>
|
||||
/// <param name="_parentRelPath">要压缩的文件夹的父相对文件夹</param>
|
||||
/// <param name="_zipOutputStream">压缩输出流</param>
|
||||
/// <param name="_zipCallback">ZipCallback对象,负责回调</param>
|
||||
/// <param name="_path">Ҫѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_parentRelPath">Ҫѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>еĸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_zipOutputStream">ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="_zipCallback">ZipCallback<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD></param>
|
||||
/// <returns></returns>
|
||||
private static bool ZipDirectory(string _path, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
|
||||
{
|
||||
|
|
@ -331,7 +421,7 @@ public class ZipWrapper : MonoBehaviour
|
|||
entry.Size = 0;
|
||||
|
||||
if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
|
||||
return true; // 过滤
|
||||
return true; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
_zipOutputStream.PutNextEntry(entry);
|
||||
_zipOutputStream.Flush();
|
||||
|
|
@ -339,7 +429,7 @@ public class ZipWrapper : MonoBehaviour
|
|||
string[] files = Directory.GetFiles(_path);
|
||||
for (int index = 0; index < files.Length; ++index)
|
||||
{
|
||||
// 排除Unity中可能的 .meta 文件
|
||||
// <EFBFBD>ų<EFBFBD>Unity<EFBFBD>п<EFBFBD><EFBFBD>ܵ<EFBFBD> .meta <20>ļ<EFBFBD>
|
||||
if (files[index].EndsWith(".meta") == true)
|
||||
{
|
||||
Debug.LogWarning(files[index] + " not to zip");
|
||||
|
|
|
|||
Loading…
Reference in New Issue