about summary refs log tree commit diff stats
path: root/adapter/img/jebp.nim
diff options
context:
space:
mode:
Diffstat (limited to 'adapter/img/jebp.nim')
-rw-r--r--adapter/img/jebp.nim67
1 files changed, 46 insertions, 21 deletions
diff --git a/adapter/img/jebp.nim b/adapter/img/jebp.nim
index ec3c9073..03d72d59 100644
--- a/adapter/img/jebp.nim
+++ b/adapter/img/jebp.nim
@@ -1,5 +1,6 @@
 import std/options
 import std/os
+import std/posix
 import std/strutils
 
 import utils/sandbox
@@ -17,6 +18,9 @@ else:
 
 {.passc: "-I" & currentSourcePath().parentDir().}
 
+const STDIN_FILENO = 0
+const STDOUT_FILENO = 1
+
 {.push header: "jebp.h".}
 type
   jebp_io_callbacks {.importc.} = object
@@ -48,13 +52,36 @@ proc jebp_free_image(image: ptr jebp_image_t) {.importc.}
 {.pop.}
 
 proc myRead(data: pointer; size: csize_t; user: pointer): csize_t {.cdecl.} =
-  return csize_t(stdin.readBuffer(data, size))
+  var n = csize_t(0)
+  while n < size:
+    let i = read(STDIN_FILENO, addr cast[ptr UncheckedArray[char]](data)[n],
+      int(size - n))
+    if i == 0:
+      break
+    n += csize_t(i)
+  return n
 
 proc stbir_resize_uint8(input_pixels: ptr uint8;
   input_w, input_h, input_stride_in_bytes: cint; output_pixels: ptr uint8;
   output_w, output_h, output_stride_in_bytes, num_channels: cint): cint
   {.importc.}
 
+proc writeAll(data: pointer; size: int) =
+  var n = 0
+  while n < size:
+    let i = write(STDOUT_FILENO, addr cast[ptr UncheckedArray[uint8]](data)[n],
+      int(size) - n)
+    assert i >= 0
+    n += i
+
+proc puts(s: string) =
+  if s.len > 0:
+    writeAll(unsafeAddr s[0], s.len)
+
+proc die(s: string) {.noreturn.} =
+  puts(s)
+  quit(1)
+
 proc main() =
   enterNetworkSandbox()
   let scheme = getEnv("MAPPED_URI_SCHEME")
@@ -62,8 +89,7 @@ proc main() =
   case getEnv("MAPPED_URI_PATH")
   of "decode":
     if f != "webp":
-      stdout.write("Cha-Control: ConnectionError 1 unknown format " & f)
-      return
+      die("Cha-Control: ConnectionError 1 unknown format " & f)
     let headers = getEnv("REQUEST_HEADERS")
     var targetWidth = cint(-1)
     var targetHeight = cint(-1)
@@ -76,13 +102,11 @@ proc main() =
       of "Cha-Image-Target-Dimensions":
         let s = v.split('x')
         if s.len != 2:
-          stdout.write("Cha-Control: ConnectionError 1 wrong dimensions")
-          return
+          die("Cha-Control: ConnectionError 1 wrong dimensions\n")
         let w = parseUInt32(s[0], allowSign = false)
         let h = parseUInt32(s[1], allowSign = false)
         if w.isNone or w.isNone:
-          stdout.write("Cha-Control: ConnectionError 1 wrong dimensions")
-          return
+          die("Cha-Control: ConnectionError 1 wrong dimensions\n")
         targetWidth = cint(w.get)
         targetHeight = cint(h.get)
     var image = jebp_image_t()
@@ -90,32 +114,33 @@ proc main() =
     if infoOnly:
       let res = jebp_read_size_from_callbacks(addr image, addr cb, nil)
       if res == 0:
-        stdout.write("Cha-Image-Dimensions: " & $image.width & "x" &
+        puts("Cha-Image-Dimensions: " & $image.width & "x" &
           $image.height & "\n\n")
+        quit(0)
       else:
-        stdout.write("Cha-Control: ConnectionError 1 jepb error " &
+        die("Cha-Control: ConnectionError 1 jepb error " &
           $jebp_error_string(res))
-      return
     let res = jebp_read_from_callbacks(addr image, addr cb, nil)
     if res != 0:
-      stdout.write("Cha-Control: ConnectionError 1 jebp error " &
+      die("Cha-Control: ConnectionError 1 jebp error " &
         $jebp_error_string(res))
     elif targetWidth != -1 and targetHeight != -1:
-      let p2 = cast[ptr uint8](alloc(targetWidth * targetHeight * 4))
+      let hdr = "Cha-Image-Dimensions: " & $targetWidth & "x" & $targetHeight &
+        "\n\n"
+      let p2 = cast[ptr UncheckedArray[uint8]](alloc(hdr.len +
+        targetWidth * targetHeight * 4))
+      copyMem(addr p2[0], unsafeAddr hdr[0], hdr.len)
       doAssert stbir_resize_uint8(cast[ptr uint8](image.pixels), image.width,
-        image.height, 0, p2, targetWidth, targetHeight, 0, 4) == 1
-      stdout.write("Cha-Image-Dimensions: " & $targetWidth & "x" &
-        $targetHeight & "\n\n")
-      discard stdout.writeBuffer(p2, targetWidth * targetHeight * 4)
+        image.height, 0, addr p2[hdr.len], targetWidth, targetHeight, 0, 4) == 1
+      writeAll(p2, hdr.len + targetWidth * targetHeight * 4)
       dealloc(p2)
       jebp_free_image(addr image)
     else:
-      stdout.write("Cha-Image-Dimensions: " & $image.width & "x" &
-        $image.height & "\n\n")
-      discard stdout.writeBuffer(cast[ptr uint8](image.pixels), image.width *
-        image.height * 4)
+      puts("Cha-Image-Dimensions: " & $image.width & "x" & $image.height &
+        "\n\n")
+      writeAll(image.pixels, image.width * image.height * 4)
       jebp_free_image(addr image)
   of "encode":
-    stdout.write("Cha-Control: ConnectionError 1 not supported")
+    die("Cha-Control: ConnectionError 1 not supported")
 
 main()