1 | var fs = require('fs');
|
2 |
|
3 | var iconv = null;
|
4 | try {
|
5 | iconv = require('iconv-lite');
|
6 | } catch (err) {
|
7 |
|
8 | iconv = null;
|
9 | }
|
10 |
|
11 | var bufferWrapper = require('./bufferwrapper');
|
12 | var MarcRecord = require('./record').MarcRecord;
|
13 |
|
14 | var field = require('./field');
|
15 | var MarcVariableField = field.MarcVariableField;
|
16 | var MarcControlField = field.MarcControlField;
|
17 | var MarcDataField = field.MarcDataField;
|
18 | var MarcSubfield = field.MarcSubfield;
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | function MarcIsoWriter(options) {
|
24 | if (!(this instanceof MarcIsoWriter)) {
|
25 | return new MarcIsoWriter(options);
|
26 | }
|
27 |
|
28 |
|
29 | this.recordsFile = null;
|
30 |
|
31 | this.readyToWrite = false;
|
32 |
|
33 | this.position = null;
|
34 |
|
35 |
|
36 | options = options || {};
|
37 | this.options = {
|
38 |
|
39 | encoding: options.encoding || null
|
40 | }
|
41 | }
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | MarcIsoWriter.ISO_LEADER_SIZE = 24;
|
47 | MarcIsoWriter.ISO_DIR_ENTRY_SIZE = 12;
|
48 |
|
49 | MarcIsoWriter.ISO_RECORD_DELIMITER = '\x1D';
|
50 | MarcIsoWriter.ISO_FIELD_DELIMITER = '\x1E';
|
51 | MarcIsoWriter.ISO_CODE_PREFIX = '\x1F';
|
52 |
|
53 |
|
54 |
|
55 |
|
56 | MarcIsoWriter.prototype.openFile = function(recordsFile, options) {
|
57 | this.recordsFile = recordsFile;
|
58 | this.readyToWrite = true;
|
59 | this.position = 0;
|
60 |
|
61 | options = options || {};
|
62 | if (options.hasOwnProperty('encoding')) {
|
63 | if (options.encoding && options.encoding !== 'utf-8'
|
64 | && iconv && iconv.encodingExists(options.encoding))
|
65 | {
|
66 | this.options.encoding = options.encoding;
|
67 | } else {
|
68 | this.options.encoding = null;
|
69 | }
|
70 | }
|
71 | }
|
72 |
|
73 |
|
74 |
|
75 |
|
76 | MarcIsoWriter.prototype.open = function(recordsFileName) {
|
77 | var self = this;
|
78 | var options = arguments.length === 3 ? arguments[1] : undefined;
|
79 | var callback = arguments.length === 3 ? arguments[2] : arguments[1];
|
80 |
|
81 | var flags = (options || {}).flags || 'w';
|
82 | var mode = (options || {}).mode || '0666';
|
83 | fs.open(recordsFileName, flags, mode, function(err, recordsFile) {
|
84 | if (err) { return callback(err); }
|
85 | self.openFile(recordsFile, options);
|
86 | callback();
|
87 | });
|
88 | }
|
89 |
|
90 |
|
91 |
|
92 |
|
93 | MarcIsoWriter.prototype.openSync = function(recordsFileName, options) {
|
94 | var flags = (options || {}).flags || 'w';
|
95 | var mode = (options || {}).mode || '0666';
|
96 | var recordsFile = fs.openSync(recordsFileName, flags, mode);
|
97 | this.openFile(recordsFile, options);
|
98 | }
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | MarcIsoWriter.prototype.close = function(callback) {
|
104 | var self = this;
|
105 | if (self.recordsFile !== null) {
|
106 | fs.close(self.recordsFile, function(err) {
|
107 | self.readyToWrite = false;
|
108 | self.recordsFile = null;
|
109 | self.position = null;
|
110 | callback(err);
|
111 | });
|
112 | }
|
113 | }
|
114 |
|
115 |
|
116 |
|
117 |
|
118 | MarcIsoWriter.prototype.closeSync = function() {
|
119 | if (this.recordsFile !== null) {
|
120 | fs.closeSync(this.recordsFile);
|
121 | this.readyToWrite = false;
|
122 | this.recordsFile = null;
|
123 | this.position = null;
|
124 | }
|
125 | }
|
126 |
|
127 |
|
128 |
|
129 |
|
130 | MarcIsoWriter.prototype.write = function(record, callback) {
|
131 | var self = this;
|
132 | if (self.recordsFile === null) {
|
133 | return callback(new Error('records file must be opened'));
|
134 | }
|
135 |
|
136 | recordBuffer = bufferWrapper.allocUnsafe(100000);
|
137 | var recordBufferSize =
|
138 | MarcIsoWriter.recordToIso2709(record, recordBuffer, self.options);
|
139 | fs.write(self.recordsFile, recordBuffer, 0, recordBufferSize, null,
|
140 | function(err, written) {
|
141 | self.position += written;
|
142 | callback(err);
|
143 | }
|
144 | );
|
145 | }
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | MarcIsoWriter.prototype.writeSync = function(record) {
|
151 | if (this.recordsFile === null) {
|
152 | throw new Error('records file must be opened');
|
153 | }
|
154 |
|
155 | recordBuffer = bufferWrapper.allocUnsafe(100000);
|
156 | var recordBufferSize =
|
157 | MarcIsoWriter.recordToIso2709(record, recordBuffer, this.options);
|
158 | var written = fs.writeSync(this.recordsFile, recordBuffer, 0,
|
159 | recordBufferSize, null);
|
160 | this.position += written;
|
161 | }
|
162 |
|
163 |
|
164 |
|
165 |
|
166 | MarcIsoWriter.prototype.getPosition = function() {
|
167 | return this.position;
|
168 | }
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | MarcIsoWriter.recordToIso2709 = function(record, buffer, options) {
|
174 |
|
175 | var leader = record.getLeader();
|
176 | if (leader.length !== MarcIsoWriter.ISO_LEADER_SIZE) {
|
177 | throw new Error('wrong leader size');
|
178 | }
|
179 | buffer.write(leader, 0);
|
180 |
|
181 |
|
182 | var fields = record.getVariableFields();
|
183 |
|
184 |
|
185 | var baseAddress = MarcIsoWriter.ISO_LEADER_SIZE
|
186 | + fields.length * MarcIsoWriter.ISO_DIR_ENTRY_SIZE + 1;
|
187 | buffer.write(String('00000' + baseAddress).slice(-5), 12);
|
188 |
|
189 |
|
190 | buffer.write(MarcIsoWriter.ISO_FIELD_DELIMITER, baseAddress - 1);
|
191 |
|
192 |
|
193 | var bufferPos = baseAddress;
|
194 | for (var i = 0; i < fields.length; i++) {
|
195 | var field = fields[i];
|
196 |
|
197 |
|
198 | var fieldBufferSize = MarcIsoWriter.fieldToIso2709(
|
199 | field, buffer.slice(bufferPos), options);
|
200 |
|
201 |
|
202 | var fieldOffset = bufferPos - baseAddress;
|
203 | var directoryEntry = String('000' + field.tag).slice(-3)
|
204 | + String('0000' + fieldBufferSize).slice(-4)
|
205 | + String('00000' + fieldOffset).slice(-5);
|
206 | buffer.write(directoryEntry,
|
207 | MarcIsoWriter.ISO_LEADER_SIZE + MarcIsoWriter.ISO_DIR_ENTRY_SIZE * i);
|
208 |
|
209 |
|
210 | bufferPos += fieldBufferSize;
|
211 | }
|
212 |
|
213 |
|
214 | buffer.write(MarcIsoWriter.ISO_RECORD_DELIMITER, bufferPos++);
|
215 |
|
216 |
|
217 | buffer.write(String('00000' + bufferPos).slice(-5), 0);
|
218 |
|
219 | return bufferPos;
|
220 | }
|
221 |
|
222 |
|
223 |
|
224 |
|
225 | MarcIsoWriter.fieldToIso2709 = function(field, buffer, options, isEmbedded) {
|
226 | if (field.isControlField()) {
|
227 | var fieldData;
|
228 | if (!options || !options.encoding) {
|
229 | fieldData = bufferWrapper.from(field.data, 'utf-8');
|
230 | } else {
|
231 | fieldData = iconv.encode(field.data, options.encoding);
|
232 | }
|
233 |
|
234 | fieldData.copy(buffer);
|
235 | buffer.write(MarcIsoWriter.ISO_FIELD_DELIMITER, fieldData.length);
|
236 | return fieldData.length + 1;
|
237 | }
|
238 |
|
239 |
|
240 | var bufferPos = 0;
|
241 | if (!isEmbedded) {
|
242 | buffer.write(field.ind1 + field.ind2, 'ascii');
|
243 | bufferPos += 2;
|
244 | }
|
245 |
|
246 |
|
247 | var subfields = field.getSubfields();
|
248 | for (var i = 0; i < subfields.length; i++) {
|
249 | var subfield = subfields[i];
|
250 |
|
251 | var subfieldBufferSize = MarcIsoWriter.subfieldToIso2709(
|
252 | subfield, buffer.slice(bufferPos), options);
|
253 | bufferPos += subfieldBufferSize;
|
254 | }
|
255 |
|
256 | buffer.write(MarcIsoWriter.ISO_FIELD_DELIMITER, bufferPos++);
|
257 | return bufferPos;
|
258 | }
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | MarcIsoWriter.subfieldToIso2709 = function(subfield, buffer, options) {
|
264 | buffer.write(MarcIsoWriter.ISO_CODE_PREFIX + subfield.code);
|
265 | if (!subfield.isEmbeddedField()) {
|
266 | if (!options || !options.encoding) {
|
267 | var subfieldData = bufferWrapper.from(subfield.data, 'utf-8');
|
268 | } else {
|
269 | var subfieldData = iconv.encode(subfield.data, options.encoding);
|
270 | }
|
271 |
|
272 | subfieldData.copy(buffer, 2);
|
273 | return 2 + subfieldData.length;
|
274 | }
|
275 |
|
276 | var embeddedHeader = subfield.data.tag;
|
277 | if (!subfield.data.isControlField()) {
|
278 | embeddedHeader += subfield.data.ind1 + subfield.data.ind2;
|
279 | }
|
280 | if (!options || !options.encoding) {
|
281 | var embeddedHeaderData = bufferWrapper.from(embeddedHeader, 'utf-8');
|
282 | } else {
|
283 | var embeddedHeaderData = iconv.encode(embeddedHeader, options.encoding);
|
284 | }
|
285 | embeddedHeaderData.copy(buffer, 2);
|
286 |
|
287 | var fieldBufferSize = MarcIsoWriter.fieldToIso2709(
|
288 | subfield.data, buffer.slice(2 + embeddedHeaderData.length), options, true);
|
289 |
|
290 |
|
291 | return 1 + embeddedHeaderData.length + fieldBufferSize;
|
292 | }
|
293 |
|
294 | module.exports = {
|
295 | MarcIsoWriter: MarcIsoWriter
|
296 | };
|