byte-streams.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. module.metadata = {
  6. "stability": "experimental"
  7. };
  8. exports.ByteReader = ByteReader;
  9. exports.ByteWriter = ByteWriter;
  10. const {Cc, Ci} = require("chrome");
  11. // This just controls the maximum number of bytes we read in at one time.
  12. const BUFFER_BYTE_LEN = 0x8000;
  13. function ByteReader(inputStream) {
  14. const self = this;
  15. let stream = Cc["@mozilla.org/binaryinputstream;1"].
  16. createInstance(Ci.nsIBinaryInputStream);
  17. stream.setInputStream(inputStream);
  18. let manager = new StreamManager(this, stream);
  19. this.read = function ByteReader_read(numBytes) {
  20. manager.ensureOpened();
  21. if (typeof(numBytes) !== "number")
  22. numBytes = Infinity;
  23. let data = "";
  24. let read = 0;
  25. try {
  26. while (true) {
  27. let avail = stream.available();
  28. let toRead = Math.min(numBytes - read, avail, BUFFER_BYTE_LEN);
  29. if (toRead <= 0)
  30. break;
  31. data += stream.readBytes(toRead);
  32. read += toRead;
  33. }
  34. }
  35. catch (err) {
  36. throw new Error("Error reading from stream: " + err);
  37. }
  38. return data;
  39. };
  40. }
  41. function ByteWriter(outputStream) {
  42. const self = this;
  43. let stream = Cc["@mozilla.org/binaryoutputstream;1"].
  44. createInstance(Ci.nsIBinaryOutputStream);
  45. stream.setOutputStream(outputStream);
  46. let manager = new StreamManager(this, stream);
  47. this.write = function ByteWriter_write(str) {
  48. manager.ensureOpened();
  49. try {
  50. stream.writeBytes(str, str.length);
  51. }
  52. catch (err) {
  53. throw new Error("Error writing to stream: " + err);
  54. }
  55. };
  56. }
  57. // This manages the lifetime of stream, a ByteReader or ByteWriter. It defines
  58. // closed and close() on stream and registers an unload listener that closes
  59. // rawStream if it's still opened. It also provides ensureOpened(), which
  60. // throws an exception if the stream is closed.
  61. function StreamManager(stream, rawStream) {
  62. const self = this;
  63. this.rawStream = rawStream;
  64. this.opened = true;
  65. stream.__defineGetter__("closed", function stream_closed() {
  66. return !self.opened;
  67. });
  68. stream.close = function stream_close() {
  69. self.ensureOpened();
  70. self.unload();
  71. };
  72. require("../system/unload").ensure(this);
  73. }
  74. StreamManager.prototype = {
  75. ensureOpened: function StreamManager_ensureOpened() {
  76. if (!this.opened)
  77. throw new Error("The stream is closed and cannot be used.");
  78. },
  79. unload: function StreamManager_unload() {
  80. this.rawStream.close();
  81. this.opened = false;
  82. }
  83. };