Move SSD input stream guards to typed Kotlin

ober

69a9fe807049d70872a651cb19be0a7ba6eb0e68

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 640ec14..7d57e53 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -6052,7 +6052,7 @@
         (export normalizeRemoteEndpointValue normalizeRemoteEndpoint urlEncode
                 contentEncodingIsGzip responseInputStream
                 connectionContentLengthExceedsLimit
-                localTruthHttpAllowed)
+                inputStreamPresent localTruthHttpAllowed)
         (type InputStream)
         (type URLConnection)
         (extern (bufferedInputStream (input : InputStream)) : InputStream
@@ -6088,6 +6088,8 @@
           (if (contentEncodingIsGzip contentEncoding)
               (gzipInputStream (bufferedInputStream raw))
               raw))
+        (def (inputStreamPresent (input : (Nullable InputStream))) : Bool
+          (not (nullable-null? input)))
         (def (connectionContentLengthExceedsLimit (connection : URLConnection)
                                                   (limit : Int)) : Bool
           (> (connectionContentLength connection) limit))
@@ -7544,7 +7546,8 @@
        "        setStatus(hashingPdfStatus(pdfName))"
        "        thread {"
        "            try {"
-       "                val hash = contentResolver.openInputStream(uri)?.use { sha1Hex(it) } ?: \"\""
+       "                val pdfInput = contentResolver.openInputStream(uri)"
+       "                val hash = if (inputStreamPresent(pdfInput)) checkNotNull(pdfInput).use { sha1Hex(it) } else \"\""
        "                val count = pdfPageCount(uri)"
        "                runOnUiThread {"
        "                    pdfSha1 = hash"
@@ -9284,10 +9287,11 @@
        "                if (safeLeafInvalid(name)) return@forEach"
        "                val remaining = MAX_ZIP_TOTAL_BYTES - budget.expandedBytes"
        "                if (nonPositiveByteCount(remaining)) throw IllegalStateException(\"Import tree exceeds byte limit\")"
-       "                val bytes = context.contentResolver.openInputStream(child.uri)?.use {"
+       "                val childInput = context.contentResolver.openInputStream(child.uri)"
+       "                if (!inputStreamPresent(childInput)) return@forEach"
+       "                val bytes = checkNotNull(childInput).use {"
        "                    readBoundedBytes(it, boundedTreeReadLimit(MAX_ZIP_ENTRY_BYTES, remaining))"
        "                }"
-       "                    ?: return@forEach"
        "                budget.expandedBytes += byteArraySizeBytes(bytes)"
        "                validateImportedText(name, bytes.decodeToString())"
        "                val dest = containedImportPath(root.toPath().relativize(File(localDir, name).toPath()).toString())"