keywords.js: make write_keywords public and more flexible
[conkeror.git] / modules / io.js
blob2610f09a587a1d70ef99008c26f95487becf6ee1
1 /**
2  * (C) Copyright 2004 Shawn Betts
3  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
4  *
5  * Portions of this file were derived from the Venkman JavaScript debugger,
6  * (C) Copyright 1998 Netscape Communications Corporation.
7  *
8  * Use, modification, and distribution are subject to the terms specified in the
9  * COPYING file.
10 **/
12 const PERM_IWOTH = 00002;  /* write permission, others */
13 const PERM_IWGRP = 00020;  /* write permission, group */
15 const MODE_RDONLY   = 0x01;
16 const MODE_WRONLY   = 0x02;
17 const MODE_RDWR     = 0x04;
18 const MODE_CREATE   = 0x08;
19 const MODE_APPEND   = 0x10;
20 const MODE_TRUNCATE = 0x20;
21 const MODE_SYNC     = 0x40;
22 const MODE_EXCL     = 0x80;
23 const MODE_OUTPUT = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE;
24 const MODE_OUTPUT_APPEND = MODE_WRONLY | MODE_CREATE | MODE_APPEND;
25 const MODE_INPUT = MODE_RDONLY;
27 define_keywords("$charset");
28 function read_text_file(file)
30     keywords(arguments, $charset = "UTF-8");
32     var ifstream = null, icstream = null;
34     try {
35         ifstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
36         icstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream);
38         ifstream.init(file, -1, 0, 0);
39         const replacementChar = Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
40         icstream.init(ifstream, arguments.$charset, 4096, replacementChar); // 4096 bytes buffering
42         var buffer = "";
43         var str = {};
44         while (icstream.readString(4096, str) != 0)
45             buffer += str.value;
46         return buffer;
47     } finally  {
48         if (icstream)
49             icstream.close();
50         if (ifstream)
51             ifstream.close();
52     }
55 define_keywords("$mode", "$perms", "$charset");
56 function write_text_file(file, buf)
58     keywords(arguments, $charset = "UTF-8", $perms = 0644, $mode = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE);
60     var ofstream, ocstream;
61     try {
62         ofstream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
63         ocstream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream);
65         ofstream.init(file, arguments.$mode, arguments.$perms, 0);
66         ocstream.init(ofstream, arguments.$charset, 0, 0x0000);
67         ocstream.writeString(buf);
68     } finally {
69         if (ocstream)
70             ocstream.close();
71         if (ofstream)
72             ofstream.close();
73     }
76 define_keywords("$mode", "$perms");
77 function write_binary_file(file, buf)
79     keywords(arguments, $perms = 0644, $mode = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE);
80     var stream = null, bstream = null;
82     try {
83         stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
84         stream.init(file, arguments.$mode, arguments.$perms, 0);
86         bstream = binary_output_stream(stream);
87         bstream.writeBytes(buf, buf.length);
88     } finally {
89         if (bstream)
90             bstream.close();
91         if (stream)
92             stream.close();
93     }
96 function get_file(path) {
97     var f = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
98     f.initWithPath(path);
99     return f;
102 var thread_manager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
104 function input_stream_async_wait(stream, callback, requested_count) {
105     stream = stream.QueryInterface(Ci.nsIAsyncInputStream);
106     var flags = (requested_count === false) ? Ci.nsIAsyncInputStream.WAIT_CLOSURE_ONLY : 0;
107     if (requested_count == null || requested_count == false)
108         requested_count = 0;
109     stream.asyncWait({onInputStreamReady: callback}, flags, requested_count, thread_manager.mainThread);
112 function output_stream_async_wait(stream, callback, requested_count) {
113     stream = stream.QueryInterface(Ci.nsIAsyncOutputStream);
114     var flags = (requested_count === false) ? Ci.nsIAsyncOutputStream.WAIT_CLOSURE_ONLY : 0;
115     if (requested_count == null || requested_count == false)
116         requested_count = 0;
117     stream.asyncWait({onOutputStreamReady: callback}, flags, requested_count, thread_manager.mainThread);
120 function binary_output_stream(stream) {
121     var s = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
122     s.setOutputStream(stream);
123     return s;
126 function binary_input_stream(stream) {
127     var s = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
128     s.setInputStream(stream);
129     return s;
132 //  callback is called with null if the write succeeded, and an error otherwise
133 function async_binary_write(stream, data, callback) {
134     var data1 = data;
135     function attempt_write() {
136         try {
137             while (true) {
138                 if (data.length == 0) {
139                     stream.flush();
140                     if (callback != null)
141                         callback(null);
142                     return;
143                 }
144                 var len = stream.write(data, data.length);
145                 if (len == 0)
146                     break;
147                 data = data.substring(len);
148             }
149         }
150         catch (e if (e instanceof Components.Exception) && e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK) {}
151         catch (e) {
152             if (callback != null)
153                 callback(e);
154             return;
155         }
156         output_stream_async_wait(stream, attempt_write, data.length);
157     }
158     attempt_write();
162  * The `str' parameter should be a normal JavaScript string whose char codes specify Unicode code points.
163  * The return value is a byte string (all char codes are from 0 to 255) equal to the `str' encoded in the specified charset.
164  * If charset is not specified, it defaults to UTF-8.
165  */
166 function encode_string(str, charset) {
167     var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
168     converter.charset = charset || "UTF-8";
169     var output = converter.ConvertFromUnicode(str);
170     output += converter.Finish();
171     return output;
177  * The `bstr' parameter should be a byte string (all char codes are from 0 to 255).
178  * The return value is a normal JavaScript unicode sring equal to `bstr' decoded using the specified charset.
179  * If charset is not specified, it defaults to UTF-8.
180  */
181 function decode_string(bstr, charset) {
182     var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
183     converter.charset = charset  || "UTF-8";
184     return converter.ConvertToUnicode(bstr);
187 /* Calls callback when the write has completed.  If callback is null,
188    the stream is closed when the write completes. */
189 function async_binary_string_writer(bstr, callback) {
190     return function (stream) {
191         function modified_callback (e) {
192             if (callback == null) {
193                 stream.close();
194             } else {
195                 callback(stream, e);
196             }
197         }
198         async_binary_write(stream, bstr, modified_callback);
199     };
202 function async_binary_reader(callback) {
203     return function (stream) {
204         var bstream = binary_input_stream(stream);
205         function handler() {
206             try {
207                 let avail = stream.available();
208                 if (avail > 0) {
209                     callback(bstream.readBytes(avail));
210                 }
211                 input_stream_async_wait(stream, handler);
212             } catch (e) {
213                 callback(null);
214             }
215         }
216         input_stream_async_wait(stream, handler);
217     };
220 function string_input_stream(data) {
221     var string_stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
222     string_stream.data = data;
223     return string_stream;
226 function mime_input_stream(stream, headers) {
227     var mime_stream = Cc["@mozilla.org/network/mime-input-stream;1"].createInstance(Ci.nsIMIMEInputStream);
228     if (headers) {
229         for each (let [name,value] in headers) {
230             mime_stream.addHeader(name,value);
231         }
232     }
233     mime_stream.addContentLength = true;
234     mime_stream.setData(stream);
235     return mime_stream;