UNPKG

8.13 kBJavaScriptView Raw
1var fs = require('fs');
2
3var iconv = null;
4try {
5 iconv = require('iconv-lite');
6} catch (err) {
7 // If module iconv-lite is not present then use only utf-8 encoding.
8 iconv = null;
9}
10
11var bufferWrapper = require('./bufferwrapper');
12var MarcRecord = require('./record').MarcRecord;
13
14var field = require('./field');
15var MarcVariableField = field.MarcVariableField;
16var MarcControlField = field.MarcControlField;
17var MarcDataField = field.MarcDataField;
18var MarcSubfield = field.MarcSubfield;
19
20/*
21 * The constructor of MARC ISO2709 writer.
22 */
23function MarcIsoWriter(options) {
24 if (!(this instanceof MarcIsoWriter)) {
25 return new MarcIsoWriter(options);
26 }
27
28 // File with records in ISO2709 format.
29 this.recordsFile = null;
30 // Flag is true when write() can be performed.
31 this.readyToWrite = false;
32 // Position in file.
33 this.position = null;
34
35 // File options.
36 options = options || {};
37 this.options = {
38 // Output data encoding.
39 encoding: options.encoding || null
40 }
41}
42
43/*
44 * Constants.
45 */
46MarcIsoWriter.ISO_LEADER_SIZE = 24;
47MarcIsoWriter.ISO_DIR_ENTRY_SIZE = 12;
48
49MarcIsoWriter.ISO_RECORD_DELIMITER = '\x1D';
50MarcIsoWriter.ISO_FIELD_DELIMITER = '\x1E';
51MarcIsoWriter.ISO_CODE_PREFIX = '\x1F';
52
53/*
54 * Opens records file by descriptor.
55 */
56MarcIsoWriter.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 * Opens records file by name.
75 */
76MarcIsoWriter.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 * Opens records file by name (sync version).
92 */
93MarcIsoWriter.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 * Closes records file.
102 */
103MarcIsoWriter.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 * Closes records file (sync version).
117 */
118MarcIsoWriter.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 * Writes record to the file.
129 */
130MarcIsoWriter.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 * Writes record to the file (sync version).
149 */
150MarcIsoWriter.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 * Returns current position in file.
165 */
166MarcIsoWriter.prototype.getPosition = function() {
167 return this.position;
168}
169
170/*
171 * Converts record to ISO2709 buffer.
172 */
173MarcIsoWriter.recordToIso2709 = function(record, buffer, options) {
174 // Copy leader to the buffer.
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 // Get all fields.
182 var fields = record.getVariableFields();
183
184 // Calculate base address of data and copy it to record buffer.
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 // Append field delimiter after directory.
190 buffer.write(MarcIsoWriter.ISO_FIELD_DELIMITER, baseAddress - 1);
191
192 // Iterate fields.
193 var bufferPos = baseAddress;
194 for (var i = 0; i < fields.length; i++) {
195 var field = fields[i];
196
197 // Append field to the buffer.
198 var fieldBufferSize = MarcIsoWriter.fieldToIso2709(
199 field, buffer.slice(bufferPos), options);
200
201 // Fill directory entry.
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 // Move buffer position.
210 bufferPos += fieldBufferSize;
211 }
212
213 // Append record delimiter.
214 buffer.write(MarcIsoWriter.ISO_RECORD_DELIMITER, bufferPos++);
215
216 // Write record length to the buffer.
217 buffer.write(String('00000' + bufferPos).slice(-5), 0);
218
219 return bufferPos;
220}
221
222/*
223 * Converts field to ISO2709 buffer.
224 */
225MarcIsoWriter.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 // Append indicators to the buffer.
240 var bufferPos = 0;
241 if (!isEmbedded) {
242 buffer.write(field.ind1 + field.ind2, 'ascii');
243 bufferPos += 2;
244 }
245
246 // Append subfields to the field buffer.
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 * Converts subfield to ISO2709 buffer.
262 */
263MarcIsoWriter.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 // Decrease length by 1 due to ISO_FIELD_DELIMITER.
291 return 1 + embeddedHeaderData.length + fieldBufferSize;
292}
293
294module.exports = {
295 MarcIsoWriter: MarcIsoWriter
296};