[SignalingServer] Optimize dependent modules
[platform/framework/web/wrtjs.git] / signaling_server / service / node_modules / pngjs / lib / parser.js
1 'use strict';
2
3 var constants = require('./constants');
4 var CrcCalculator = require('./crc');
5
6
7 var Parser = module.exports = function(options, dependencies) {
8
9   this._options = options;
10   options.checkCRC = options.checkCRC !== false;
11
12   this._hasIHDR = false;
13   this._hasIEND = false;
14   this._emittedHeadersFinished = false;
15
16   // input flags/metadata
17   this._palette = [];
18   this._colorType = 0;
19
20   this._chunks = {};
21   this._chunks[constants.TYPE_IHDR] = this._handleIHDR.bind(this);
22   this._chunks[constants.TYPE_IEND] = this._handleIEND.bind(this);
23   this._chunks[constants.TYPE_IDAT] = this._handleIDAT.bind(this);
24   this._chunks[constants.TYPE_PLTE] = this._handlePLTE.bind(this);
25   this._chunks[constants.TYPE_tRNS] = this._handleTRNS.bind(this);
26   this._chunks[constants.TYPE_gAMA] = this._handleGAMA.bind(this);
27
28   this.read = dependencies.read;
29   this.error = dependencies.error;
30   this.metadata = dependencies.metadata;
31   this.gamma = dependencies.gamma;
32   this.transColor = dependencies.transColor;
33   this.palette = dependencies.palette;
34   this.parsed = dependencies.parsed;
35   this.inflateData = dependencies.inflateData;
36   this.finished = dependencies.finished;
37   this.simpleTransparency = dependencies.simpleTransparency;
38   this.headersFinished = dependencies.headersFinished || function() {};
39 };
40
41 Parser.prototype.start = function() {
42   this.read(constants.PNG_SIGNATURE.length,
43     this._parseSignature.bind(this)
44   );
45 };
46
47 Parser.prototype._parseSignature = function(data) {
48
49   var signature = constants.PNG_SIGNATURE;
50
51   for (var i = 0; i < signature.length; i++) {
52     if (data[i] !== signature[i]) {
53       this.error(new Error('Invalid file signature'));
54       return;
55     }
56   }
57   this.read(8, this._parseChunkBegin.bind(this));
58 };
59
60 Parser.prototype._parseChunkBegin = function(data) {
61
62   // chunk content length
63   var length = data.readUInt32BE(0);
64
65   // chunk type
66   var type = data.readUInt32BE(4);
67   var name = '';
68   for (var i = 4; i < 8; i++) {
69     name += String.fromCharCode(data[i]);
70   }
71
72   //console.log('chunk ', name, length);
73
74   // chunk flags
75   var ancillary = Boolean(data[4] & 0x20); // or critical
76   //    priv = Boolean(data[5] & 0x20), // or public
77   //    safeToCopy = Boolean(data[7] & 0x20); // or unsafe
78
79   if (!this._hasIHDR && type !== constants.TYPE_IHDR) {
80     this.error(new Error('Expected IHDR on beggining'));
81     return;
82   }
83
84   this._crc = new CrcCalculator();
85   this._crc.write(new Buffer(name));
86
87   if (this._chunks[type]) {
88     return this._chunks[type](length);
89   }
90
91   if (!ancillary) {
92     this.error(new Error('Unsupported critical chunk type ' + name));
93     return;
94   }
95
96   this.read(length + 4, this._skipChunk.bind(this));
97 };
98
99 Parser.prototype._skipChunk = function(/*data*/) {
100   this.read(8, this._parseChunkBegin.bind(this));
101 };
102
103 Parser.prototype._handleChunkEnd = function() {
104   this.read(4, this._parseChunkEnd.bind(this));
105 };
106
107 Parser.prototype._parseChunkEnd = function(data) {
108
109   var fileCrc = data.readInt32BE(0);
110   var calcCrc = this._crc.crc32();
111
112   // check CRC
113   if (this._options.checkCRC && calcCrc !== fileCrc) {
114     this.error(new Error('Crc error - ' + fileCrc + ' - ' + calcCrc));
115     return;
116   }
117
118   if (!this._hasIEND) {
119     this.read(8, this._parseChunkBegin.bind(this));
120   }
121 };
122
123 Parser.prototype._handleIHDR = function(length) {
124   this.read(length, this._parseIHDR.bind(this));
125 };
126 Parser.prototype._parseIHDR = function(data) {
127
128   this._crc.write(data);
129
130   var width = data.readUInt32BE(0);
131   var height = data.readUInt32BE(4);
132   var depth = data[8];
133   var colorType = data[9]; // bits: 1 palette, 2 color, 4 alpha
134   var compr = data[10];
135   var filter = data[11];
136   var interlace = data[12];
137
138   // console.log('    width', width, 'height', height,
139   //     'depth', depth, 'colorType', colorType,
140   //     'compr', compr, 'filter', filter, 'interlace', interlace
141   // );
142
143   if (depth !== 8 && depth !== 4 && depth !== 2 && depth !== 1 && depth !== 16) {
144     this.error(new Error('Unsupported bit depth ' + depth));
145     return;
146   }
147   if (!(colorType in constants.COLORTYPE_TO_BPP_MAP)) {
148     this.error(new Error('Unsupported color type'));
149     return;
150   }
151   if (compr !== 0) {
152     this.error(new Error('Unsupported compression method'));
153     return;
154   }
155   if (filter !== 0) {
156     this.error(new Error('Unsupported filter method'));
157     return;
158   }
159   if (interlace !== 0 && interlace !== 1) {
160     this.error(new Error('Unsupported interlace method'));
161     return;
162   }
163
164   this._colorType = colorType;
165
166   var bpp = constants.COLORTYPE_TO_BPP_MAP[this._colorType];
167
168   this._hasIHDR = true;
169
170   this.metadata({
171     width: width,
172     height: height,
173     depth: depth,
174     interlace: Boolean(interlace),
175     palette: Boolean(colorType & constants.COLORTYPE_PALETTE),
176     color: Boolean(colorType & constants.COLORTYPE_COLOR),
177     alpha: Boolean(colorType & constants.COLORTYPE_ALPHA),
178     bpp: bpp,
179     colorType: colorType
180   });
181
182   this._handleChunkEnd();
183 };
184
185
186 Parser.prototype._handlePLTE = function(length) {
187   this.read(length, this._parsePLTE.bind(this));
188 };
189 Parser.prototype._parsePLTE = function(data) {
190
191   this._crc.write(data);
192
193   var entries = Math.floor(data.length / 3);
194   // console.log('Palette:', entries);
195
196   for (var i = 0; i < entries; i++) {
197     this._palette.push([
198       data[i * 3],
199       data[i * 3 + 1],
200       data[i * 3 + 2],
201       0xff
202     ]);
203   }
204
205   this.palette(this._palette);
206
207   this._handleChunkEnd();
208 };
209
210 Parser.prototype._handleTRNS = function(length) {
211   this.simpleTransparency();
212   this.read(length, this._parseTRNS.bind(this));
213 };
214 Parser.prototype._parseTRNS = function(data) {
215
216   this._crc.write(data);
217
218   // palette
219   if (this._colorType === constants.COLORTYPE_PALETTE_COLOR) {
220     if (this._palette.length === 0) {
221       this.error(new Error('Transparency chunk must be after palette'));
222       return;
223     }
224     if (data.length > this._palette.length) {
225       this.error(new Error('More transparent colors than palette size'));
226       return;
227     }
228     for (var i = 0; i < data.length; i++) {
229       this._palette[i][3] = data[i];
230     }
231     this.palette(this._palette);
232   }
233
234   // for colorType 0 (grayscale) and 2 (rgb)
235   // there might be one gray/color defined as transparent
236   if (this._colorType === constants.COLORTYPE_GRAYSCALE) {
237     // grey, 2 bytes
238     this.transColor([data.readUInt16BE(0)]);
239   }
240   if (this._colorType === constants.COLORTYPE_COLOR) {
241     this.transColor([data.readUInt16BE(0), data.readUInt16BE(2), data.readUInt16BE(4)]);
242   }
243
244   this._handleChunkEnd();
245 };
246
247 Parser.prototype._handleGAMA = function(length) {
248   this.read(length, this._parseGAMA.bind(this));
249 };
250 Parser.prototype._parseGAMA = function(data) {
251
252   this._crc.write(data);
253   this.gamma(data.readUInt32BE(0) / constants.GAMMA_DIVISION);
254
255   this._handleChunkEnd();
256 };
257
258 Parser.prototype._handleIDAT = function(length) {
259   if (!this._emittedHeadersFinished) {
260     this._emittedHeadersFinished = true;
261     this.headersFinished();
262   }
263   this.read(-length, this._parseIDAT.bind(this, length));
264 };
265 Parser.prototype._parseIDAT = function(length, data) {
266
267   this._crc.write(data);
268
269   if (this._colorType === constants.COLORTYPE_PALETTE_COLOR && this._palette.length === 0) {
270     throw new Error('Expected palette not found');
271   }
272
273   this.inflateData(data);
274   var leftOverLength = length - data.length;
275
276   if (leftOverLength > 0) {
277     this._handleIDAT(leftOverLength);
278   }
279   else {
280     this._handleChunkEnd();
281   }
282 };
283
284 Parser.prototype._handleIEND = function(length) {
285   this.read(length, this._parseIEND.bind(this));
286 };
287 Parser.prototype._parseIEND = function(data) {
288
289   this._crc.write(data);
290
291   this._hasIEND = true;
292   this._handleChunkEnd();
293
294   if (this.finished) {
295     this.finished();
296   }
297 };