Repository: gabriel-vasile/mimetype
Pull request #218 (2021-12-13 14:54:40)

Check for null bytes for Cabinet files


Patch:
diff --git a/internal/magic/archive.go b/internal/magic/archive.go
index f83fcd5..8f5ff87 100644
--- a/internal/magic/archive.go
+++ b/internal/magic/archive.go
@@ -32,7 +32,7 @@ var (
 	// Warc matches a Web ARChive file.
 	Warc = prefix([]byte("WARC/"))
 	// Cab matches a Cabinet archive file.
-	Cab = prefix([]byte("MSCF"))
+	Cab = prefix([]byte("MSCF\x00\x00\x00\x00"))
 	// Xz matches an xz compressed stream based on https://tukaani.org/xz/xz-file-format.txt.
 	Xz = prefix([]byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00})
 	// Lzip matches an Lzip compressed file.
diff --git a/internal/magic/text.go b/internal/magic/text.go
index 40bfb19..dff756c 100644
--- a/internal/magic/text.go
+++ b/internal/magic/text.go
@@ -228,9 +228,11 @@ func GeoJSON(raw []byte, limit uint32) bool {
 	return false
 }
 
-// NdJSON matches a Newline delimited JSON file.
+// NdJSON matches a Newline delimited JSON file. All complete lines from raw
+// must be valid JSON documents meaning they contain one of the valid JSON data
+// types.
 func NdJSON(raw []byte, limit uint32) bool {
-	lCount := 0
+	lCount, hasObjOrArr := 0, false
 	sc := bufio.NewScanner(dropLastLine(raw, limit))
 	for sc.Scan() {
 		l := sc.Bytes()
@@ -242,10 +244,13 @@ func NdJSON(raw []byte, limit uint32) bool {
 		if err != nil {
 			return false
 		}
+		if l[0] == '[' || l[0] == '{' {
+			hasObjOrArr = true
+		}
 		lCount++
 	}
 
-	return lCount > 1
+	return lCount > 1 && hasObjOrArr
 }
 
 // Har matches a HAR Spec file.


Test patch:
diff --git a/internal/json/json_test.go b/internal/json/json_test.go
index 38422ba..39ae2cb 100644
--- a/internal/json/json_test.go
+++ b/internal/json/json_test.go
@@ -19,6 +19,12 @@ func TestScan(t *testing.T) {
 		{`}{`, 1, false},
 		{`{]`, 2, false},
 		{`{}`, 2, true},
+		{`[]`, 2, true},
+		{`"foo"`, 5, true},
+		{`120`, 3, true},
+		{`1e20`, 4, true},
+		{`0.120`, 5, true},
+		{`null`, 4, true},
 		{`{"foo":"bar"}`, 13, true},
 		{`{"foo":"21\t\u0009 \u1234","bar":{"baz":["qux"]}`, 48, false},
 		{`{"foo":"bar","bar":{"baz":["qux"]}}`, 35, true},
diff --git a/internal/magic/magic_test.go b/internal/magic/magic_test.go
index 6dd5c0b..d0a5d8a 100644
--- a/internal/magic/magic_test.go
+++ b/internal/magic/magic_test.go
@@ -27,6 +27,55 @@ func TestMagic(t *testing.T) {
 			limit:    10,
 			res:      true,
 		},
+		{
+			name:     "basic JSON data type null",
+			detector: JSON,
+			raw:      `null`,
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "basic JSON data type string",
+			detector: JSON,
+			raw:      `"abc"`,
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "basic JSON data type integer",
+			detector: JSON,
+			raw:      `120`,
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "basic JSON data type float",
+			detector: JSON,
+			raw:      `.120`,
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "NdJSON with basic data types",
+			detector: NdJSON,
+			raw:      "1\nnull\n\"foo\"\n0.1",
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "NdJSON with basic data types and empty object",
+			detector: NdJSON,
+			raw:      "1\n2\n3\n{}",
+			limit:    10,
+			res:      true,
+		},
+		{
+			name:     "NdJSON with empty objects types",
+			detector: NdJSON,
+			raw:      "{}\n{}\n{}",
+			limit:    10,
+			res:      true,
+		},
 	}
 	for _, tt := range tCases {
 		t.Run(tt.name, func(t *testing.T) {