mirror of
https://github.com/beefytech/Beef.git
synced 2025-07-08 01:05:59 +02:00
Added MD5 file hashes to Beef
This commit is contained in:
parent
32c09bf94b
commit
61468d818f
33 changed files with 598 additions and 143 deletions
|
@ -92,7 +92,7 @@ namespace System
|
|||
return type;
|
||||
}
|
||||
|
||||
#if BF_ALLOW_HOT_SWAPPING
|
||||
#if BF_DYNAMIC_CAST_CHECK || BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
[NoShow]
|
||||
public virtual Object DynamicCastToTypeId(int32 typeId)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ using Beefy;
|
|||
using Beefy.utils;
|
||||
using IDE.Util;
|
||||
using IDE.ui;
|
||||
using IDE.util;
|
||||
|
||||
namespace IDE.Compiler
|
||||
{
|
||||
|
@ -373,13 +374,19 @@ namespace IDE.Compiler
|
|||
bfProject = mBfSystem.GetBfProject(projectSource.mProject);
|
||||
}
|
||||
|
||||
bool wantsHash = !mIsResolveOnly;
|
||||
|
||||
bool canMoveSourceString = true;
|
||||
IdSpan char8IdData = projectSourceCommand.mSourceCharIdData;
|
||||
String data = projectSourceCommand.mSourceString;
|
||||
SourceHash hash = .None;
|
||||
if (wantsHash)
|
||||
hash = projectSourceCommand.mSourceHash;
|
||||
if (char8IdData.IsEmpty)
|
||||
{
|
||||
data = scope:ProjectSourceCommandBlock String();
|
||||
if (gApp.LoadTextFile(sourceFilePath, data) case .Err)
|
||||
|
||||
if (gApp.LoadTextFile(sourceFilePath, data, true, scope [&] () => { if (wantsHash) hash = SourceHash.Create(.MD5, data); } ) case .Err)
|
||||
data = null;
|
||||
if (data != null)
|
||||
{
|
||||
|
@ -390,6 +397,8 @@ namespace IDE.Compiler
|
|||
using (gApp.mMonitor.Enter())
|
||||
{
|
||||
editData.SetSavedData(data, char8IdData);
|
||||
if (hash case .MD5(let md5Hash))
|
||||
editData.mMD5Hash = md5Hash;
|
||||
}
|
||||
canMoveSourceString = false;
|
||||
}
|
||||
|
@ -419,6 +428,9 @@ namespace IDE.Compiler
|
|||
bfParser.SetSource("", sourceFilePath);
|
||||
bfParser.SetCharIdData(ref char8IdData);
|
||||
|
||||
if (hash case .MD5(let md5Hash))
|
||||
bfParser.SetHashMD5(md5Hash);
|
||||
|
||||
//passInstance.SetProject(bfProject);
|
||||
worked &= bfParser.Parse(passInstance, false);
|
||||
worked &= bfParser.Reduce(passInstance);
|
||||
|
|
|
@ -9,6 +9,7 @@ using IDE.ui;
|
|||
using System.IO;
|
||||
using System.Threading;
|
||||
using Beefy;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace IDE.Compiler
|
||||
{
|
||||
|
@ -94,6 +95,9 @@ namespace IDE.Compiler
|
|||
[StdCall, CLink]
|
||||
static extern void BfParser_SetCharIdData(void* bfParser, uint8* data, int32 length);
|
||||
|
||||
[StdCall, CLink]
|
||||
static extern void BfParser_SetHashMD5(void* bfParser, ref MD5Hash md5Hash);
|
||||
|
||||
[StdCall, CLink]
|
||||
static extern void BfParser_SetNextRevision(void* bfParser, void* nextParser);
|
||||
|
||||
|
@ -352,5 +356,11 @@ namespace IDE.Compiler
|
|||
{
|
||||
BfParser_SetCompleteParse(mNativeBfParser);
|
||||
}
|
||||
|
||||
public void SetHashMD5(MD5Hash md5Hash)
|
||||
{
|
||||
var md5Hash;
|
||||
BfParser_SetHashMD5(mNativeBfParser, ref md5Hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ namespace IDE.Compiler
|
|||
projectSource.GetFullImportPath(fullPath);
|
||||
if (Path.Equals(fullPath, entry.mFilePath))
|
||||
{
|
||||
app.mBfResolveCompiler.QueueProjectSource(projectSource);
|
||||
app.mBfResolveCompiler.QueueProjectSource(projectSource, false);
|
||||
needsResolveAll = true;
|
||||
DeferRefreshVisibleViews(entry.mExludeSourceViewPanel);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
|||
using Beefy.utils;
|
||||
using Beefy;
|
||||
using System.IO;
|
||||
using IDE.util;
|
||||
|
||||
namespace IDE.Compiler
|
||||
{
|
||||
|
@ -36,6 +37,7 @@ namespace IDE.Compiler
|
|||
public ProjectSource mProjectSource;
|
||||
public IdSpan mSourceCharIdData ~ _.Dispose();
|
||||
public String mSourceString ~ delete _;
|
||||
public SourceHash mSourceHash;
|
||||
}
|
||||
|
||||
protected class CompileCommand : Command
|
||||
|
@ -55,12 +57,12 @@ namespace IDE.Compiler
|
|||
mResolveAllWait = 2;
|
||||
}
|
||||
|
||||
public virtual void QueueProjectSource(ProjectSource projectSource)
|
||||
public virtual void QueueProjectSource(ProjectSource projectSource, bool wantsHash)
|
||||
{
|
||||
ProjectSourceCommand command = new ProjectSourceCommand();
|
||||
command.mProjectSource = projectSource;
|
||||
command.mSourceString = new String();
|
||||
IDEApp.sApp.FindProjectSourceContent(projectSource, out command.mSourceCharIdData, false, command.mSourceString);
|
||||
IDEApp.sApp.FindProjectSourceContent(projectSource, out command.mSourceCharIdData, false, command.mSourceString, wantsHash ? &command.mSourceHash : null);
|
||||
if (gApp.mBfBuildCompiler == this)
|
||||
{
|
||||
if (gApp.mDbgVersionedCompileDir != null)
|
||||
|
|
|
@ -349,6 +349,7 @@ namespace IDE.Debugger
|
|||
public String mRunningPath ~ delete _;
|
||||
public bool mIsRunning;
|
||||
public bool mIsRunningCompiled;
|
||||
public bool mIsRunningWithHotSwap;
|
||||
//public RunState mLastUpdatedRunState;
|
||||
public bool mCallStackDirty;
|
||||
public int32 mActiveCallStackIdx;
|
||||
|
@ -400,12 +401,13 @@ namespace IDE.Debugger
|
|||
Debugger_FullReportMemory();
|
||||
}
|
||||
|
||||
public bool OpenFile(String launchPath, String targetPath, String args, String workingDir, Span<char8> envBlock, bool isCompiled)
|
||||
public bool OpenFile(String launchPath, String targetPath, String args, String workingDir, Span<char8> envBlock, bool isCompiled, bool hotSwapEnabled)
|
||||
{
|
||||
DeleteAndNullify!(mRunningPath);
|
||||
mRunningPath = new String(launchPath);
|
||||
|
||||
mIsRunningCompiled = isCompiled;
|
||||
mIsRunningWithHotSwap = hotSwapEnabled;
|
||||
return Debugger_OpenFile(launchPath, targetPath, args, workingDir, envBlock.Ptr, (int32)envBlock.Length);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,14 @@ using System.IO;
|
|||
using Beefy.utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using IDE.util;
|
||||
|
||||
namespace IDE
|
||||
{
|
||||
[AllowDuplicates]
|
||||
public enum LineEndingKind
|
||||
{
|
||||
Unknown,
|
||||
Lf, // \n
|
||||
CrLf, // \r\n
|
||||
Cr, // \r
|
||||
|
|
|
@ -382,6 +382,7 @@ namespace IDE
|
|||
class StartDebugCmd : ExecutionCmd
|
||||
{
|
||||
public bool mWasCompiled;
|
||||
public bool mHotCompileEnabled;
|
||||
|
||||
public this()
|
||||
{
|
||||
|
@ -1298,6 +1299,8 @@ namespace IDE
|
|||
|
||||
StringView useText = text;
|
||||
|
||||
Debug.Assert(!text.Contains('\r'));
|
||||
|
||||
if (lineEndingKind != .Lf)
|
||||
{
|
||||
var str = scope:: String()..Append(text);
|
||||
|
@ -6372,6 +6375,8 @@ namespace IDE
|
|||
if ((aliasFilePath != null) && (sourceViewPanel.mAliasFilePath == null))
|
||||
String.NewOrSet!(sourceViewPanel.mAliasFilePath, aliasFilePath);
|
||||
|
||||
|
||||
|
||||
if (sourceViewPanel.mLoadFailed)
|
||||
{
|
||||
sourceViewPanel.mWantHash = hash;
|
||||
|
@ -6380,11 +6385,16 @@ namespace IDE
|
|||
sourceViewPanel.SetLoadCmd(loadCmd);
|
||||
}
|
||||
}
|
||||
else if ((hash != .None) && (sourceViewPanel.mEditData != null) && (!sourceViewPanel.mEditData.CheckHash(hash)))
|
||||
else if ((gApp.mDebugger.mIsRunningWithHotSwap) && (sourceViewPanel.mIsBeefSource))
|
||||
{
|
||||
// No 'wrong hash' warnings
|
||||
}
|
||||
else if (((hash != .None) && (sourceViewPanel.mEditData != null) && (!sourceViewPanel.mEditData.CheckHash(hash))) ||
|
||||
(sourceViewPanel.mHasChangedSinceLastCompile))
|
||||
{
|
||||
sourceViewPanel.ShowWrongHash();
|
||||
}
|
||||
|
||||
|
||||
int showHotIdx = -1;
|
||||
if (!onlyShowCurrent)
|
||||
{
|
||||
|
@ -7774,12 +7784,12 @@ namespace IDE
|
|||
return worked;
|
||||
}
|
||||
|
||||
public bool FindProjectSourceContent(ProjectSource projectSource, out IdSpan char8IdData, bool loadOnFail, String sourceContent)
|
||||
public bool FindProjectSourceContent(ProjectSource projectSource, out IdSpan char8IdData, bool loadOnFail, String sourceContent, SourceHash* sourceHash)
|
||||
{
|
||||
char8IdData = IdSpan();
|
||||
var fullPath = scope String();
|
||||
projectSource.GetFullImportPath(fullPath);
|
||||
|
||||
|
||||
//SourceViewPanel sourceViewPanel = null;
|
||||
|
||||
using (mMonitor.Enter())
|
||||
|
@ -7798,6 +7808,12 @@ namespace IDE
|
|||
{
|
||||
char8IdData = projectSource.mEditData.mEditWidget.mEditWidgetContent.mData.mTextIdData.Duplicate();
|
||||
projectSource.mEditData.mEditWidget.GetText(sourceContent);
|
||||
if (sourceHash != null)
|
||||
{
|
||||
*sourceHash = SourceHash.Create(.MD5, sourceContent, projectSource.mEditData.mLineEndingKind);
|
||||
if (*sourceHash case .MD5(let md5Hash))
|
||||
projectSource.mEditData.mMD5Hash = md5Hash;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -7806,6 +7822,8 @@ namespace IDE
|
|||
{
|
||||
char8IdData = projectSource.mEditData.mSavedCharIdData.Duplicate();
|
||||
sourceContent.Set(projectSource.mEditData.mSavedContent);
|
||||
if ((!projectSource.mEditData.mMD5Hash.IsZero) && (sourceHash != null))
|
||||
*sourceHash = .MD5(projectSource.mEditData.mMD5Hash);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -7815,8 +7833,8 @@ namespace IDE
|
|||
{
|
||||
String text = scope String();
|
||||
bool isValid = false;
|
||||
if (LoadTextFile(fullPath, text) case .Ok)
|
||||
{
|
||||
if (LoadTextFile(fullPath, text, true, scope [&] () => { if (sourceHash != null) *sourceHash = SourceHash.Create(.MD5, text); } ) case .Ok)
|
||||
{
|
||||
mFileWatcher.FileIsValid(fullPath);
|
||||
isValid = true;
|
||||
}
|
||||
|
@ -7835,6 +7853,11 @@ namespace IDE
|
|||
editData.SetSavedData(null, IdSpan());
|
||||
editData.mFileDeleted = true;
|
||||
}
|
||||
if (sourceHash != null)
|
||||
{
|
||||
if (*sourceHash case .MD5(let md5Hash))
|
||||
editData.mMD5Hash = md5Hash;
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
@ -7931,7 +7954,7 @@ namespace IDE
|
|||
if (bfCompiler != null)
|
||||
{
|
||||
// Process change in resolve compiler
|
||||
bfCompiler.QueueProjectSource(projectSource);
|
||||
bfCompiler.QueueProjectSource(projectSource, !bfCompiler.mIsResolveOnly);
|
||||
}
|
||||
}
|
||||
else // Actual build
|
||||
|
@ -7941,7 +7964,7 @@ namespace IDE
|
|||
// mHasChangedSinceLastCompile is safe to set 'false' here since it just determines whether or not
|
||||
// we rebuild the TypeDefs from the sources. It isn't affected by any compilation errors.
|
||||
projectSource.mHasChangedSinceLastCompile = false;
|
||||
bfCompiler.QueueProjectSource(projectSource);
|
||||
bfCompiler.QueueProjectSource(projectSource, !bfCompiler.mIsResolveOnly);
|
||||
hadBeef = true;
|
||||
}
|
||||
}
|
||||
|
@ -9428,9 +9451,12 @@ namespace IDE
|
|||
|
||||
if ((runAfter) && (success))
|
||||
{
|
||||
var options = GetCurWorkspaceOptions();
|
||||
|
||||
var startDebugCmd = new StartDebugCmd();
|
||||
startDebugCmd.mWasCompiled = true;
|
||||
startDebugCmd.mOnlyIfNotFailed = true;
|
||||
startDebugCmd.mHotCompileEnabled = options.mAllowHotSwapping;
|
||||
mExecutionQueue.Add(startDebugCmd);
|
||||
}
|
||||
|
||||
|
@ -9963,7 +9989,7 @@ namespace IDE
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!mDebugger.OpenFile(launchPath, targetPath, arguments, workingDir, envBlock, wasCompiled))
|
||||
if (!mDebugger.OpenFile(launchPath, targetPath, arguments, workingDir, envBlock, wasCompiled, workspaceOptions.mAllowHotSwapping))
|
||||
{
|
||||
DeleteAndNullify!(mCompileAndRunStopwatch);
|
||||
return false;
|
||||
|
@ -10877,7 +10903,7 @@ namespace IDE
|
|||
return;
|
||||
var resolveCompiler = GetProjectCompilerForFile(projectSource.mPath);
|
||||
if (resolveCompiler == mBfResolveCompiler)
|
||||
resolveCompiler.QueueProjectSource(projectSource);
|
||||
resolveCompiler.QueueProjectSource(projectSource, false);
|
||||
projectSource.mHasChangedSinceLastCompile = true;
|
||||
}
|
||||
});
|
||||
|
@ -11773,8 +11799,8 @@ namespace IDE
|
|||
{
|
||||
if (IsBeefFile(newPath))
|
||||
{
|
||||
mBfResolveCompiler.QueueProjectSource(projectSource);
|
||||
mBfBuildCompiler.QueueProjectSource(projectSource);
|
||||
mBfResolveCompiler.QueueProjectSource(projectSource, false);
|
||||
mBfBuildCompiler.QueueProjectSource(projectSource, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -12053,7 +12079,7 @@ namespace IDE
|
|||
{
|
||||
if (mBfResolveCompiler != null)
|
||||
{
|
||||
mBfResolveCompiler.QueueProjectSource(projectSource);
|
||||
mBfResolveCompiler.QueueProjectSource(projectSource, false);
|
||||
mBfResolveCompiler.QueueDeferredResolveAll();
|
||||
mBfResolveCompiler.QueueRefreshViewCommand();
|
||||
}
|
||||
|
|
|
@ -477,7 +477,7 @@ namespace IDE
|
|||
|
||||
var envBlock = scope List<char8>();
|
||||
Environment.EncodeEnvironmentVariables(envVars, envBlock);
|
||||
if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true))
|
||||
if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true, false))
|
||||
{
|
||||
QueueOutputLine("ERROR: Failed debug '{0}'", curProjectInfo.mTestExePath);
|
||||
TestFailed();
|
||||
|
|
|
@ -261,7 +261,7 @@ namespace IDE.ui
|
|||
{
|
||||
IdSpan liveCharIdData;
|
||||
String liveText = scope:: String();
|
||||
app.FindProjectSourceContent(projectSource, out liveCharIdData, true, liveText);
|
||||
app.FindProjectSourceContent(projectSource, out liveCharIdData, true, liveText, null);
|
||||
defer(stack) liveCharIdData.Dispose();
|
||||
|
||||
var compileInstance = IDEApp.sApp.mWorkspace.GetProjectSourceCompileInstance(projectSource, mHotIdx);
|
||||
|
|
|
@ -708,7 +708,7 @@ namespace IDE.ui
|
|||
if ((IDEApp.IsBeefFile(filePath)) && (gApp.mBfResolveCompiler != null))
|
||||
{
|
||||
for (var projectSource in editData.mProjectSources)
|
||||
gApp.mBfResolveCompiler.QueueProjectSource(projectSource);
|
||||
gApp.mBfResolveCompiler.QueueProjectSource(projectSource, false);
|
||||
gApp.mBfResolveCompiler.QueueDeferredResolveAll();
|
||||
}
|
||||
|
||||
|
|
|
@ -332,7 +332,7 @@ namespace IDE.ui
|
|||
var envBlock = scope List<char8>();
|
||||
Environment.EncodeEnvironmentVariables(envVars, envBlock);
|
||||
|
||||
if (!gApp.mDebugger.OpenFile(targetPath, targetPath, arguments, workingDir, envBlock, false))
|
||||
if (!gApp.mDebugger.OpenFile(targetPath, targetPath, arguments, workingDir, envBlock, false, false))
|
||||
{
|
||||
gApp.Fail(scope String()..AppendF("Unable to open executable for debugging: {0}", targetPath));
|
||||
return;
|
||||
|
|
|
@ -352,7 +352,7 @@ namespace IDE.ui
|
|||
var resolveCompiler = gApp.GetProjectCompilerForFile(projectSource.mName);
|
||||
if (resolveCompiler != null)
|
||||
{
|
||||
resolveCompiler.QueueProjectSource(projectSource);
|
||||
resolveCompiler.QueueProjectSource(projectSource, false);
|
||||
resolveCompiler.QueueDeferredResolveAll();
|
||||
}
|
||||
projectSource.mHasChangedSinceLastCompile = true;
|
||||
|
|
|
@ -740,7 +740,7 @@ namespace IDE.ui
|
|||
if ((mKind == Kind.Rename) && (IDEApp.IsBeefFile(editData.mFilePath)))
|
||||
{
|
||||
for (var projectSource in editData.mProjectSources)
|
||||
app.mBfResolveCompiler.QueueProjectSource(projectSource);
|
||||
app.mBfResolveCompiler.QueueProjectSource(projectSource, false);
|
||||
app.mBfResolveCompiler.QueueDeferredResolveAll();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -453,6 +453,7 @@ namespace IDE.ui
|
|||
}
|
||||
|
||||
Debug.Assert(endingText == text);
|
||||
Debug.Assert(!endingText.Contains('\r'));
|
||||
|
||||
//mClangSourceChanged = false;
|
||||
//mLastFileTextVersion = mEditWidget.Content.mData.mCurTextVersionId;
|
||||
|
|
|
@ -262,83 +262,6 @@ namespace IDE.ui
|
|||
}
|
||||
}
|
||||
|
||||
public enum SourceHash
|
||||
{
|
||||
public enum Kind
|
||||
{
|
||||
None,
|
||||
MD5,
|
||||
SHA256
|
||||
}
|
||||
|
||||
case None;
|
||||
case MD5(MD5Hash hash);
|
||||
case SHA256(SHA256Hash hash);
|
||||
|
||||
public Kind GetKind()
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case .MD5:
|
||||
return .MD5;
|
||||
case .SHA256:
|
||||
return .SHA256;
|
||||
default:
|
||||
return .None;
|
||||
}
|
||||
}
|
||||
|
||||
public static SourceHash Create(StringView hashStr)
|
||||
{
|
||||
if (hashStr.Length == 32)
|
||||
{
|
||||
if (MD5Hash.Parse(hashStr) case .Ok(let parsedHash))
|
||||
{
|
||||
return .MD5(parsedHash);
|
||||
}
|
||||
}
|
||||
else if (hashStr.Length == 64)
|
||||
{
|
||||
if (SHA256Hash.Parse(hashStr) case .Ok(let parsedHash))
|
||||
{
|
||||
return .SHA256(parsedHash);
|
||||
}
|
||||
}
|
||||
|
||||
return .None;
|
||||
}
|
||||
|
||||
public static SourceHash Create(Kind kind, StringView str)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case .MD5:
|
||||
return .MD5(Security.Cryptography.MD5.Hash(.((uint8*)str.Ptr, str.Length)));
|
||||
case .SHA256:
|
||||
return .SHA256(Security.Cryptography.SHA256.Hash(.((uint8*)str.Ptr, str.Length)));
|
||||
default:
|
||||
return .None;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator==(SourceHash lhs, SourceHash rhs)
|
||||
{
|
||||
switch (lhs)
|
||||
{
|
||||
case .None:
|
||||
return rhs case .None;
|
||||
case .MD5(let lhsMD5):
|
||||
if (rhs case .MD5(let rhsMD5))
|
||||
return lhsMD5 == rhsMD5;
|
||||
case .SHA256(let lhsSHA256):
|
||||
if (rhs case .SHA256(let rhsSHA256))
|
||||
return lhsSHA256 == rhsSHA256;
|
||||
default:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class QueuedAutoComplete
|
||||
{
|
||||
public char32 mKeyChar;
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace IDE.Util
|
|||
for (var projectSource in editData.mProjectSources)
|
||||
{
|
||||
projectSource.HasChangedSinceLastCompile = true;
|
||||
IDEApp.sApp.mBfResolveCompiler.QueueProjectSource(projectSource);
|
||||
IDEApp.sApp.mBfResolveCompiler.QueueProjectSource(projectSource, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ namespace IDE.Util
|
|||
for (var projectSource in editData.mProjectSources)
|
||||
{
|
||||
projectSource.HasChangedSinceLastCompile = true;
|
||||
IDEApp.sApp.mBfResolveCompiler.QueueProjectSource(projectSource);
|
||||
IDEApp.sApp.mBfResolveCompiler.QueueProjectSource(projectSource, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
92
IDE/src/util/SourceHash.bf
Normal file
92
IDE/src/util/SourceHash.bf
Normal file
|
@ -0,0 +1,92 @@
|
|||
using System.Security.Cryptography;
|
||||
using System;
|
||||
|
||||
namespace IDE.util
|
||||
{
|
||||
public enum SourceHash
|
||||
{
|
||||
public enum Kind
|
||||
{
|
||||
None,
|
||||
MD5,
|
||||
SHA256
|
||||
}
|
||||
|
||||
case None;
|
||||
case MD5(MD5Hash hash);
|
||||
case SHA256(SHA256Hash hash);
|
||||
|
||||
public Kind GetKind()
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case .MD5:
|
||||
return .MD5;
|
||||
case .SHA256:
|
||||
return .SHA256;
|
||||
default:
|
||||
return .None;
|
||||
}
|
||||
}
|
||||
|
||||
public static SourceHash Create(StringView hashStr)
|
||||
{
|
||||
if (hashStr.Length == 32)
|
||||
{
|
||||
if (MD5Hash.Parse(hashStr) case .Ok(let parsedHash))
|
||||
{
|
||||
return .MD5(parsedHash);
|
||||
}
|
||||
}
|
||||
else if (hashStr.Length == 64)
|
||||
{
|
||||
if (SHA256Hash.Parse(hashStr) case .Ok(let parsedHash))
|
||||
{
|
||||
return .SHA256(parsedHash);
|
||||
}
|
||||
}
|
||||
|
||||
return .None;
|
||||
}
|
||||
|
||||
public static SourceHash Create(Kind kind, StringView str, LineEndingKind lineEndingKind = .Unknown)
|
||||
{
|
||||
if ((lineEndingKind != .Unknown) && (lineEndingKind != .Lf))
|
||||
{
|
||||
if (lineEndingKind == .CrLf)
|
||||
{
|
||||
String newStr = scope .(str);
|
||||
newStr.Replace("\n", "\r\n");
|
||||
return Create(kind, newStr);
|
||||
}
|
||||
}
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case .MD5:
|
||||
return .MD5(Security.Cryptography.MD5.Hash(.((uint8*)str.Ptr, str.Length)));
|
||||
case .SHA256:
|
||||
return .SHA256(Security.Cryptography.SHA256.Hash(.((uint8*)str.Ptr, str.Length)));
|
||||
default:
|
||||
return .None;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator==(SourceHash lhs, SourceHash rhs)
|
||||
{
|
||||
switch (lhs)
|
||||
{
|
||||
case .None:
|
||||
return rhs case .None;
|
||||
case .MD5(let lhsMD5):
|
||||
if (rhs case .MD5(let rhsMD5))
|
||||
return lhsMD5 == rhsMD5;
|
||||
case .SHA256(let lhsSHA256):
|
||||
if (rhs case .SHA256(let rhsSHA256))
|
||||
return lhsSHA256 == rhsSHA256;
|
||||
default:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue