aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cli/internal/encoding/gitoutput/validators.go
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
commitdd84b9d64fb98746a230cd24233ff50a562c39c9 (patch)
treeb583261ef00b3afe72ec4d6dacb31e57779a6faf /cli/internal/encoding/gitoutput/validators.go
parent0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff)
downloadHydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz
HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip
Diffstat (limited to 'cli/internal/encoding/gitoutput/validators.go')
-rw-r--r--cli/internal/encoding/gitoutput/validators.go148
1 files changed, 148 insertions, 0 deletions
diff --git a/cli/internal/encoding/gitoutput/validators.go b/cli/internal/encoding/gitoutput/validators.go
new file mode 100644
index 0000000..e13c2d5
--- /dev/null
+++ b/cli/internal/encoding/gitoutput/validators.go
@@ -0,0 +1,148 @@
+package gitoutput
+
+import "bytes"
+
+var _allowedObjectType = []byte(" blob tree commit ")
+var _allowedStatusChars = []byte(" MTADRCU?!")
+
+// checkValid provides a uniform interface for calling `gitoutput` validators.
+func checkValid(fieldType Field, value []byte) error {
+ switch fieldType {
+ case ObjectMode:
+ return checkObjectMode(value)
+ case ObjectType:
+ return checkObjectType(value)
+ case ObjectName:
+ return CheckObjectName(value)
+ case ObjectStage:
+ return checkObjectStage(value)
+ case StatusX:
+ return checkStatusX(value)
+ case StatusY:
+ return checkStatusY(value)
+ case Path:
+ return checkPath(value)
+ default:
+ return ErrUnknownField
+ }
+}
+
+// checkObjectMode asserts that a byte slice is a six digit octal string (100644).
+// It does not attempt to ensure that the values in particular positions are reasonable.
+func checkObjectMode(value []byte) error {
+ if len(value) != 6 {
+ return ErrInvalidObjectMode
+ }
+
+ // 0-7 are 0x30 - 0x37
+ for _, currentByte := range value {
+ if (currentByte ^ 0x30) > 7 {
+ return ErrInvalidObjectMode
+ }
+ }
+
+ // length of 6, 0-7
+ return nil
+}
+
+// checkObjectType asserts that a byte slice is a valid possibility (blob, tree, commit).
+func checkObjectType(value []byte) error {
+ typeLength := len(value)
+ // Based upon:
+ // min(len("blob"), len("tree"), len("commit"))
+ // max(len("blob"), len("tree"), len("commit"))
+ if typeLength < 4 || typeLength > 6 {
+ return ErrInvalidObjectType
+ }
+
+ // Because of the space separator there is no way to pass in a space.
+ // We use that trick to enable fast lookups in _allowedObjectType.
+ index := bytes.Index(_allowedObjectType, value)
+
+ // Impossible to match at 0, not found is -1.
+ if index < 1 {
+ return ErrInvalidObjectType
+ }
+
+ // Followed by a space.
+ if _allowedObjectType[index-1] != byte(_space) {
+ return ErrInvalidObjectType
+ }
+
+ // Preceded by a space.
+ if _allowedObjectType[index+typeLength] != byte(_space) {
+ return ErrInvalidObjectType
+ }
+ return nil
+}
+
+// CheckObjectName asserts that a byte slice looks like a SHA hash.
+func CheckObjectName(value []byte) error {
+ if len(value) != 40 {
+ return ErrInvalidObjectName
+ }
+
+ // 0-9 are 0x30 - 0x39
+ // a-f are 0x61 - 0x66
+ for _, currentByte := range value {
+ isNumber := (currentByte ^ 0x30) < 10
+ numericAlpha := (currentByte ^ 0x60)
+ isAlpha := (numericAlpha < 7) && (numericAlpha > 0)
+ if !(isNumber || isAlpha) {
+ return ErrInvalidObjectName
+ }
+ }
+
+ // length of 40, hex
+ return nil
+}
+
+// checkObjectStage asserts that a byte slice is a valid possibility (0-3).
+func checkObjectStage(value []byte) error {
+ // 0-3 are 0x30 - 0x33
+ if len(value) != 1 {
+ return ErrInvalidObjectStage
+ }
+
+ currentByte := value[0]
+ if (currentByte ^ 0x30) >= 4 {
+ return ErrInvalidObjectStage
+ }
+
+ return nil
+}
+
+// checkStatusX asserts that a byte slice is a valid possibility (" MTADRCU?!").
+func checkStatusX(value []byte) error {
+ if len(value) != 1 {
+ return ErrInvalidObjectStatusX
+ }
+
+ index := bytes.Index(_allowedStatusChars, value)
+ if index == -1 {
+ return ErrInvalidObjectStatusX
+ }
+ return nil
+}
+
+// checkStatusY asserts that a byte slice is a valid possibility (" MTADRCU?!").
+func checkStatusY(value []byte) error {
+ if len(value) != 1 {
+ return ErrInvalidObjectStatusY
+ }
+
+ index := bytes.Index(_allowedStatusChars, value)
+ if index == -1 {
+ return ErrInvalidObjectStatusY
+ }
+ return nil
+}
+
+// checkPath asserts that a byte slice is non-empty.
+func checkPath(value []byte) error {
+ // Exists at all. This is best effort as trying to be fully-compatible is silly.
+ if len(value) == 0 {
+ return ErrInvalidPath
+ }
+ return nil
+}