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