]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/chrome/content/util/file.js
LP#1641208: util.file no longer mangles UTF8 when writing JSON
[Evergreen.git] / Open-ILS / xul / staff_client / chrome / content / util / file.js
1 dump('entering util/file.js\n');
2
3 if (typeof util == 'undefined') util = {};
4 util.file = function (fname) {
5
6     JSAN.use('util.error'); this.error = new util.error();
7
8     this.dirService = Components.classes["@mozilla.org/file/directory_service;1"].
9         getService( Components.interfaces.nsIProperties );
10
11     if (fname) this.get(fname);
12
13     return this;
14 };
15
16 util.file.prototype = {
17
18     'myPackageDir' : 'open_ils_staff_client',
19
20     'name' : '',
21     '_file' : null,
22     '_input_stream' : null,
23     '_output_stream' : null,
24
25     'get' : function( fname, path ) {
26         try {
27             if (!fname) { fname = this.name; } else { this.name = fname; }
28             if (!fname) throw('Must specify a filename.');
29
30             try {
31                 var pref = Components.classes["@mozilla.org/preferences-service;1"]
32                     .getService(Components.interfaces.nsIPrefBranch);
33                 if (!path && pref.getBoolPref("open-ils.write_in_user_chrome_directory")) path = 'uchrome';
34             } catch(E) {
35                 // getBoolPref throws an exception if "open-ils.write_in_user_chrome_directory" is not defined at all
36                 // in defaults/preferences/prefs.js
37             }
38
39             switch(path) {
40                 case 'uchrome' :
41                     this._file = this.dirService.get( "UChrm",  Components.interfaces.nsIFile );
42                     //this._file = this.dirService.get( "ProfD",  Components.interfaces.nsIFile );
43                 break;
44                 default:
45                 case 'chrome' : 
46                     this._file = this.dirService.get( "AChrom",  Components.interfaces.nsIFile );
47                     this._file.append(myPackageDir); 
48                     this._file.append("content"); 
49                     this._file.append("conf"); 
50                 break;
51             }
52             this._file.append(fname);
53     
54             dump('file: ' + this._file.path + '\n');
55             this.error.sdump('D_FILE',this._file.path);
56
57             return this._file;
58
59         } catch(E) {
60             this.error.standard_unexpected_error_alert('error in util.file.get('+fname+','+path+')',E);
61             throw(E);
62         }
63     },
64
65     'close' : function() {
66         try {
67             if (!this._file) throw('Must .get() a file first.');
68             if (this._input_stream) { this._input_stream.close(); this._input_stream = null; }
69             if (this._output_stream) { this._output_stream.close(); this._output_stream = null; }
70             if (this._istream) { this._istream.close(); this._istream = null; }
71             if (this._f) { this._f = null; }
72
73         } catch(E) {
74             this.error.sdump('D_ERROR',this._file.path + '\nutil.file.close(): ' + E);
75             throw(E);
76         }
77     },
78
79     'append_object' : function(obj) {
80         try {
81             this.write_object('append',obj);
82         } catch(E) {
83             this.error.sdump('D_ERROR',this._file.path + '\nutil.file.append_object(): ' + E);
84             throw(E);
85         }
86     },
87
88     'set_object' : function(obj) {
89         try {
90             this.write_object('truncate',obj);
91             this.close();
92         } catch(E) {
93             this.error.sdump('D_ERROR',this._file.path + '\nutil.file.set_object(): ' + E);
94             throw(E);
95         }
96     },
97
98     'write_object' : function(write_type,obj) {
99         try {
100             if (!this._file) throw('Must .get() a file first.');
101             if (!obj) throw('Must specify an object.');
102
103             var obj_json; 
104             try { obj_json = js2JSON( obj ) + '\n'; } catch(E) { throw('Could not JSONify the object: ' + E); }
105
106             var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
107                 .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
108             converter.charset = "UTF-8";
109             var converted = converter.ConvertFromUnicode(obj_json);
110
111             this.write_content(write_type,converted);
112
113         } catch(E) {
114             this.error.sdump('D_ERROR',this._file.path + '\nutil.file.write_object(): ' + E);
115             throw(E);
116         }
117     },
118
119     'write_content' : function(write_type,content) {
120         try {
121             if (!this._output_stream) this._create_output_stream(write_type);
122             this._output_stream.write( content, String( content ).length );
123         } catch(E) {
124             this.error.sdump('D_ERROR',this._file.path + '\nutil.file.write_content(): ' + E);
125             //dump('write_type = ' + write_type + '\n');
126             //dump('content = ' + content + '\n');
127             throw(E);
128         }
129     },
130
131     'get_object' : function() {
132         try {
133             var data = this.get_content();
134             var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
135                 .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
136             converter.charset = "UTF-8";
137             var converted = converter.ConvertToUnicode(data);
138             var obj; try { obj = JSON2js( converted ); } catch(E) { throw('Could not js-ify the JSON: '+E); }
139             return obj;
140         } catch(E) {
141             this.error.sdump('D_ERROR',this._file.path + '\nutil.file.get_object(): ' + E);
142             throw(E);
143         }
144     },
145
146     'get_content' : function() {
147         try {
148             if (!this._file) throw('Must .get() a file first.');
149             if (!this._file.exists()) throw('File does not exist.');
150             
151             if (!this._input_stream) this._create_input_stream();
152             var data = this._input_stream.read(-1);
153             //var data = {}; this._istream.readLine(data);
154             return data;
155         } catch(E) {
156             this.error.sdump('D_ERROR',this._file.path + '\nutil.file.get_content(): ' + E);
157             throw(E);
158         }
159     },
160
161     '_create_input_stream' : function() {
162         try {
163             //dump('_create_input_stream()\n');
164             
165             if (!this._file) throw('Must .get() a file first.');
166             if (!this._file.exists()) throw('File does not exist.');
167
168             this._f = Components.classes["@mozilla.org/network/file-input-stream;1"]
169                 .createInstance(Components.interfaces.nsIFileInputStream);
170             this._f.init(this._file, MODE_RDONLY, 0, 0);
171             /*
172             this._f.QueryInterface(Components.interfaces.nsILineInputStream);
173             this._istream = this._f;
174             */
175             this._input_stream = Components.classes["@mozilla.org/scriptableinputstream;1"]
176                 .createInstance(Components.interfaces.nsIScriptableInputStream);
177             if (this._f) {
178                 this._input_stream.init(this._f);
179             } else {
180                 throw('Could not instantiate input stream.');
181             }
182             return this._input_stream;
183
184         } catch(E) {
185             this.error.sdump('D_ERROR',this._file.path + '\nutil.file._create_input_stream(): ' + E);
186             throw(E);
187         }
188     },
189
190     '_create_output_stream' : function(param) {
191         try {
192             //dump('_create_output_stream('+param+') for '+this._file.path+'\n');
193             
194             if (!this._file) throw('Must .get() a file first.');
195
196             if (! this._file.exists()) {
197                 if (param == 'truncate+exec') {
198                     this._file.create( 0, 0777 );
199                 } else {
200                     this._file.create( 0, PERMS_FILE );
201                 }
202             }
203             this._output_stream = Components.classes["@mozilla.org/network/file-output-stream;1"]
204                 .createInstance(Components.interfaces.nsIFileOutputStream);
205             switch(param){
206                 case 'append' :
207                     this._output_stream.init(this._file, MODE_WRONLY | MODE_APPEND, PERMS_FILE, 0);
208                 break;
209                 case 'truncate+exec' :
210                     this._output_stream.init(this._file, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0);
211                 break;
212                 case 'truncate' :
213                 default:
214                     this._output_stream.init(this._file, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0);
215                 break;
216             }
217
218             return this._output_stream;
219
220         } catch(E) {
221             this.error.sdump('D_ERROR',this._file.path + '\nutil.file._create_output_stream(): ' + E);
222             throw(E);
223         }
224     },
225
226     'pick_file' : function(params) {
227         try {
228             if (typeof params == 'undefined') params = {};
229             if (typeof params.mode == 'undefined') params.mode = 'open';
230             var nsIFilePicker = Components.interfaces.nsIFilePicker;
231             var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance( nsIFilePicker );
232             fp.init( 
233                 window, 
234                 typeof params.title == 'undefined' ? params.mode : params.title,
235                 params.mode == 'open' ? nsIFilePicker.modeOpen : nsIFilePicker.modeSave
236             );
237             if (params.defaultFileName) {
238                 fp.defaultString = params.defaultFileName;
239             }
240             fp.appendFilters( nsIFilePicker.filterAll );
241             var fp_result = fp.show();
242             if ( ( fp_result == nsIFilePicker.returnOK || fp_result == nsIFilePicker.returnReplace ) && fp.file ) {
243                 return fp.file;
244             } else {
245                 return null;
246             }
247         } catch(E) {
248             this.error.standard_unexpected_error_alert('error picking file',E);
249         }
250     },
251
252     'export_file' : function(params) {
253         try {
254             var obj = this;
255             if (typeof params == 'undefined') params = {};
256             params.mode = 'save';
257             if (typeof params.data == 'undefined') throw('Need a .data field to export');
258             var f = obj.pick_file( params );
259             if (f) {
260                 obj._file = f;
261                 var temp = params.data;
262                 if (typeof params.not_json == 'undefined') {
263                     temp = js2JSON( temp );
264                 }
265                 obj.write_content( 'truncate', temp );
266                 obj.close();
267                 alert('Exported ' + f.leafName);
268                 return obj._file;
269             } else {
270                 alert('File not chosen for export.');
271                 return null;
272             }
273
274         } catch(E) {
275             this.error.standard_unexpected_error_alert('Error exporting file',E);
276                 return null;
277         }
278     },
279
280     'import_file' : function(params) {
281         try {
282             var obj = this;
283             if (typeof params == 'undefined') params = {};
284             params.mode = 'open';
285             var f = obj.pick_file(params);
286             if (f && f.exists()) {
287                 obj._file = f;
288                 var temp = obj.get_content();
289                 obj.close();
290                 if (typeof params.not_json == 'undefined') {
291                     temp = JSON2js( obj.get_content() );
292                 }
293                 return temp;
294             } else {
295                 alert('File not chosen for import.');
296                 return null;
297             }
298         } catch(E) {
299             this.error.standard_unexpected_error_alert('Error importing file',E);
300             return null;
301         }
302     }
303
304 }
305
306 dump('exiting util/file.js\n');