about summary refs log tree commit diff stats
path: root/src/types/blob.nim
blob: 4a5627c3addab3c1f4a4e4603166b5d91e85d9c7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import options

import js/javascript
import types/mime
import utils/twtstr

type
  DeallocFun = proc(buffer: pointer) {.noconv.}

  Blob* = ref object of RootObj
    isfile*: bool
    size* {.jsget.}: uint64
    ctype* {.jsget: "type".}: string
    buffer*: pointer
    deallocFun*: DeallocFun

  WebFile* = ref object of Blob
    webkitRelativePath {.jsget.}: string
    path*: string
    file: File #TODO maybe use fd?

proc newBlob*(buffer: pointer, size: int, ctype: string,
    deallocFun: DeallocFun): Blob =
  return Blob(
    buffer: buffer,
    size: uint64(size),
    ctype: ctype,
    deallocFun: deallocFun
  )

proc finalize(blob: Blob) {.jsfin.} =
  if blob.deallocFun != nil and blob.buffer != nil:
    blob.deallocFun(blob.buffer)

proc newWebFile*(path: string, webkitRelativePath = ""): WebFile =
  var file: File
  doAssert open(file, path, fmRead) #TODO bleh
  return WebFile(
    isfile: true,
    path: path,
    file: file,
    ctype: guessContentType(path),
    webkitRelativePath: webkitRelativePath
  )

proc newWebFile(ctx: JSContext, fileBits: seq[string], fileName: string,
    options = none(JSValue)): WebFile {.jsctor.} =
  let file = WebFile(
    isfile: false,
    path: fileName,
    deallocFun: dealloc
  )
  var len = 0
  for blobPart in fileBits:
    len += blobPart.len
  file.buffer = alloc(len)
  var buf = cast[ptr UncheckedArray[uint8]](file.buffer)
  var i = 0
  for blobPart in fileBits:
    if blobPart.len > 0:
      copyMem(addr buf[i], unsafeAddr blobPart[0], blobPart.len)
      i += blobPart.len
  file.size = uint64(len)
  if options.isSome:
    block ctype:
      let t = fromJS[string](ctx, JS_GetPropertyStr(ctx, options.get, "type"))
      if t.isNone:
        break ctype
      for c in t.get:
        if c notin char(0x20)..char(0x7E):
          break ctype
        file.ctype &= c.tolower()
    #TODO lastmodified
  return file

#TODO File, Blob constructors

func size*(this: WebFile): uint64 {.jsfget.} =
  #TODO use stat instead
  if this.isfile:
    return uint64(this.file.getFileSize())
  return this.size

func name*(this: WebFile): string {.jsfget.} =
  if this.path.len > 0 and this.path[^1] != '/':
    return this.path.afterLast('/')
  return this.path.afterLast('/', 2)

#TODO lastModified

proc addBlobModule*(ctx: JSContext) =
  let blobCID = ctx.registerType(Blob)
  ctx.registerType(WebFile, parent = blobCID, name = "File")