io/io-utils/Blob.js

  1. /*
  2. * Blob.js
  3. *
  4. * Node and Browserify Compatible
  5. *
  6. * Copyright (c) 2015 by Z3 Dev (@zdev/www.z3dev.jp)
  7. * License: MIT License
  8. *
  9. * This implementation uses the Buffer class for all storage.
  10. * See https://nodejs.org/api/buffer.html
  11. *
  12. * URL.createObjectURL(blob)
  13. *
  14. * History:
  15. * 2020/10/07: converted to class
  16. * 2015/07/02: contributed to OpenJSCAD.org CLI openjscad
  17. */
  18. /**
  19. * The Blob object represents a blob, which is a file-like object of immutable, raw data; they can be read as text or binary data.
  20. * @see https://developer.mozilla.org/en-US/docs/Web/API/Blob
  21. */
  22. class Blob {
  23. /**
  24. * Returns a newly created Blob object which contains a concatenation of all of the data in the given contents.
  25. * @param {Array} contents - an array of ArrayBuffer, or String objects that will be put inside the Blob.
  26. */
  27. constructor (contents, options) {
  28. // make the optional options non-optional
  29. options = options || {}
  30. // the size of the byte sequence in number of bytes
  31. this.size = 0 // contents, not allocation
  32. // the media type, as an ASCII-encoded string in lower case, and parsable as a MIME type
  33. this.type = ''
  34. // readability state (CLOSED: true, OPENED: false)
  35. this.isClosed = false
  36. // encoding of given strings
  37. this.encoding = 'utf8'
  38. // storage
  39. this.buffer = null
  40. this.length = 0 // allocation, not contents
  41. if (!contents) return
  42. if (!Array.isArray(contents)) return
  43. // Find content length
  44. contents.forEach((content) => {
  45. if (typeof (content) === 'string') {
  46. this.length += content.length
  47. } else if (content instanceof ArrayBuffer) {
  48. this.length += content.byteLength
  49. }
  50. })
  51. // process options if any
  52. if (options.type) {
  53. // TBD if type contains any chars outside range U+0020 to U+007E, then set type to the empty string
  54. // Convert every character in type to lowercase
  55. this.type = options.type.toLowerCase()
  56. }
  57. if (options.endings) {
  58. // convert the EOL on strings
  59. }
  60. if (options.encoding) {
  61. this.encoding = options.encoding.toLowerCase()
  62. }
  63. if (options.length) {
  64. this.length = options.length
  65. }
  66. let wbytes
  67. let object
  68. // convert the contents (String, ArrayBufferView, ArrayBuffer, Blob)
  69. // MAX_LENGTH : 2147483647
  70. this.buffer = Buffer.allocUnsafe(this.length) // new Buffer(this.length)
  71. for (let index = 0; index < contents.length; index++) {
  72. switch (typeof (contents[index])) {
  73. case 'string':
  74. wbytes = this.buffer.write(contents[index], this.size, this.encoding)
  75. this.size = this.size + wbytes
  76. break
  77. case 'object':
  78. object = contents[index] // this should be a reference to an object
  79. // FIXME if (Buffer.isBuffer(object)) { }
  80. if (object instanceof ArrayBuffer) {
  81. const view = new DataView(object)
  82. for (let bindex = 0; bindex < object.byteLength; bindex++) {
  83. const xbyte = view.getUint8(bindex)
  84. wbytes = this.buffer.writeUInt8(xbyte, this.size, false)
  85. this.size++
  86. }
  87. }
  88. break
  89. default:
  90. break
  91. }
  92. }
  93. }
  94. asBuffer () {
  95. // return a deep copy as blobs are written to files with full length, not size
  96. return this.buffer.slice(0, this.size)
  97. }
  98. arrayBuffer () {
  99. return this.buffer.slice(0, this.size)
  100. }
  101. slice (start, end, type) {
  102. start = start || 0
  103. end = end || this.size
  104. type = type || ''
  105. // TODO
  106. return new Blob()
  107. }
  108. stream () {
  109. // TODO
  110. return null
  111. }
  112. text () {
  113. // TODO
  114. return ''
  115. }
  116. close () {
  117. // if state of context objext is already CLOSED then return
  118. if (this.isClosed) return
  119. // set the readbility state of the context object to CLOSED and remove storage
  120. this.isClosed = true
  121. }
  122. toString () {
  123. // TODO
  124. return ''
  125. }
  126. }
  127. module.exports = Blob