Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(476)

Side by Side Diff: chrome/browser/resources/file_manager/js/metadata/byte_reader.js

Issue 39123003: [Files.app] Split the JavaScript files into subdirectories: common, background, and foreground (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed test failure. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 /**
8 * @constructor
9 * @param {ArrayBuffer} arrayBuffer // TODO(JSDOC).
10 * @param {number=} opt_offset // TODO(JSDOC).
11 * @param {number=} opt_length // TODO(JSDOC).
12 */
13 function ByteReader(arrayBuffer, opt_offset, opt_length) {
14 opt_offset = opt_offset || 0;
15 opt_length = opt_length || (arrayBuffer.byteLength - opt_offset);
16 this.view_ = new DataView(arrayBuffer, opt_offset, opt_length);
17 this.pos_ = 0;
18 this.seekStack_ = [];
19 this.setByteOrder(ByteReader.BIG_ENDIAN);
20 }
21
22 // Static constants and methods.
23
24 /**
25 * Intel, 0x1234 is [0x34, 0x12]
26 * @const
27 * @type {number}
28 */
29 ByteReader.LITTLE_ENDIAN = 0;
30 /**
31 * Motorola, 0x1234 is [0x12, 0x34]
32 * @const
33 * @type {number}
34 */
35 ByteReader.BIG_ENDIAN = 1;
36
37 /**
38 * Seek relative to the beginning of the buffer.
39 * @const
40 * @type {number}
41 */
42 ByteReader.SEEK_BEG = 0;
43 /**
44 * Seek relative to the current position.
45 * @const
46 * @type {number}
47 */
48 ByteReader.SEEK_CUR = 1;
49 /**
50 * Seek relative to the end of the buffer.
51 * @const
52 * @type {number}
53 */
54 ByteReader.SEEK_END = 2;
55
56 /**
57 * Throw an error if (0 > pos >= end) or if (pos + size > end).
58 *
59 * Static utility function.
60 *
61 * @param {number} pos // TODO(JSDOC).
62 * @param {number} size // TODO(JSDOC).
63 * @param {number} end // TODO(JSDOC).
64 */
65 ByteReader.validateRead = function(pos, size, end) {
66 if (pos < 0 || pos >= end)
67 throw new Error('Invalid read position');
68
69 if (pos + size > end)
70 throw new Error('Read past end of buffer');
71 };
72
73 /**
74 * Read as a sequence of characters, returning them as a single string.
75 *
76 * This is a static utility function. There is a member function with the
77 * same name which side-effects the current read position.
78 *
79 * @param {DataView} dataView // TODO(JSDOC).
80 * @param {number} pos // TODO(JSDOC).
81 * @param {number} size // TODO(JSDOC).
82 * @param {number=} opt_end // TODO(JSDOC).
83 * @return {string} // TODO(JSDOC).
84 */
85 ByteReader.readString = function(dataView, pos, size, opt_end) {
86 ByteReader.validateRead(pos, size, opt_end || dataView.byteLength);
87
88 var codes = [];
89
90 for (var i = 0; i < size; ++i)
91 codes.push(dataView.getUint8(pos + i));
92
93 return String.fromCharCode.apply(null, codes);
94 };
95
96 /**
97 * Read as a sequence of characters, returning them as a single string.
98 *
99 * This is a static utility function. There is a member function with the
100 * same name which side-effects the current read position.
101 *
102 * @param {DataView} dataView // TODO(JSDOC).
103 * @param {number} pos // TODO(JSDOC).
104 * @param {number} size // TODO(JSDOC).
105 * @param {number=} opt_end // TODO(JSDOC).
106 * @return {string} // TODO(JSDOC).
107 */
108 ByteReader.readNullTerminatedString = function(dataView, pos, size, opt_end) {
109 ByteReader.validateRead(pos, size, opt_end || dataView.byteLength);
110
111 var codes = [];
112
113 for (var i = 0; i < size; ++i) {
114 var code = dataView.getUint8(pos + i);
115 if (code == 0) break;
116 codes.push(code);
117 }
118
119 return String.fromCharCode.apply(null, codes);
120 };
121
122 /**
123 * Read as a sequence of UTF16 characters, returning them as a single string.
124 *
125 * This is a static utility function. There is a member function with the
126 * same name which side-effects the current read position.
127 *
128 * @param {DataView} dataView // TODO(JSDOC).
129 * @param {number} pos // TODO(JSDOC).
130 * @param {boolean} bom // TODO(JSDOC).
131 * @param {number} size // TODO(JSDOC).
132 * @param {number=} opt_end // TODO(JSDOC).
133 * @return {string} // TODO(JSDOC).
134 */
135 ByteReader.readNullTerminatedStringUTF16 = function(
136 dataView, pos, bom, size, opt_end) {
137 ByteReader.validateRead(pos, size, opt_end || dataView.byteLength);
138
139 var littleEndian = false;
140 var start = 0;
141
142 if (bom) {
143 littleEndian = (dataView.getUint8(pos) == 0xFF);
144 start = 2;
145 }
146
147 var codes = [];
148
149 for (var i = start; i < size; i += 2) {
150 var code = dataView.getUint16(pos + i, littleEndian);
151 if (code == 0) break;
152 codes.push(code);
153 }
154
155 return String.fromCharCode.apply(null, codes);
156 };
157
158 /**
159 * @const
160 * @type {Array.<string>}
161 * @private
162 */
163 ByteReader.base64Alphabet_ =
164 ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/').
165 split('');
166
167 /**
168 * Read as a sequence of bytes, returning them as a single base64 encoded
169 * string.
170 *
171 * This is a static utility function. There is a member function with the
172 * same name which side-effects the current read position.
173 *
174 * @param {DataView} dataView // TODO(JSDOC).
175 * @param {number} pos // TODO(JSDOC).
176 * @param {number} size // TODO(JSDOC).
177 * @param {number=} opt_end // TODO(JSDOC).
178 * @return {string} // TODO(JSDOC).
179 */
180 ByteReader.readBase64 = function(dataView, pos, size, opt_end) {
181 ByteReader.validateRead(pos, size, opt_end || dataView.byteLength);
182
183 var rv = [];
184 var chars = [];
185 var padding = 0;
186
187 for (var i = 0; i < size; /* incremented inside */) {
188 var bits = dataView.getUint8(pos + (i++)) << 16;
189
190 if (i < size) {
191 bits |= dataView.getUint8(pos + (i++)) << 8;
192
193 if (i < size) {
194 bits |= dataView.getUint8(pos + (i++));
195 } else {
196 padding = 1;
197 }
198 } else {
199 padding = 2;
200 }
201
202 chars[3] = ByteReader.base64Alphabet_[bits & 63];
203 chars[2] = ByteReader.base64Alphabet_[(bits >> 6) & 63];
204 chars[1] = ByteReader.base64Alphabet_[(bits >> 12) & 63];
205 chars[0] = ByteReader.base64Alphabet_[(bits >> 18) & 63];
206
207 rv.push.apply(rv, chars);
208 }
209
210 if (padding > 0)
211 rv[rv.length - 1] = '=';
212 if (padding > 1)
213 rv[rv.length - 2] = '=';
214
215 return rv.join('');
216 };
217
218 /**
219 * Read as an image encoded in a data url.
220 *
221 * This is a static utility function. There is a member function with the
222 * same name which side-effects the current read position.
223 *
224 * @param {DataView} dataView // TODO(JSDOC).
225 * @param {number} pos // TODO(JSDOC).
226 * @param {number} size // TODO(JSDOC).
227 * @param {number=} opt_end // TODO(JSDOC).
228 * @return {string} // TODO(JSDOC).
229 */
230 ByteReader.readImage = function(dataView, pos, size, opt_end) {
231 opt_end = opt_end || dataView.byteLength;
232 ByteReader.validateRead(pos, size, opt_end);
233
234 // Two bytes is enough to identify the mime type.
235 var prefixToMime = {
236 '\x89P' : 'png',
237 '\xFF\xD8' : 'jpeg',
238 'BM' : 'bmp',
239 'GI' : 'gif'
240 };
241
242 var prefix = ByteReader.readString(dataView, pos, 2, opt_end);
243 var mime = prefixToMime[prefix] ||
244 dataView.getUint16(pos, false).toString(16); // For debugging.
245
246 var b64 = ByteReader.readBase64(dataView, pos, size, opt_end);
247 return 'data:image/' + mime + ';base64,' + b64;
248 };
249
250 // Instance methods.
251
252 /**
253 * Return true if the requested number of bytes can be read from the buffer.
254 *
255 * @param {number} size // TODO(JSDOC).
256 * @return {boolean} // TODO(JSDOC).
257 */
258 ByteReader.prototype.canRead = function(size) {
259 return this.pos_ + size <= this.view_.byteLength;
260 };
261
262 /**
263 * Return true if the current position is past the end of the buffer.
264 * @return {boolean} // TODO(JSDOC).
265 */
266 ByteReader.prototype.eof = function() {
267 return this.pos_ >= this.view_.byteLength;
268 };
269
270 /**
271 * Return true if the current position is before the beginning of the buffer.
272 * @return {boolean} // TODO(JSDOC).
273 */
274 ByteReader.prototype.bof = function() {
275 return this.pos_ < 0;
276 };
277
278 /**
279 * Return true if the current position is outside the buffer.
280 * @return {boolean} // TODO(JSDOC).
281 */
282 ByteReader.prototype.beof = function() {
283 return this.pos_ >= this.view_.byteLength || this.pos_ < 0;
284 };
285
286 /**
287 * Set the expected byte ordering for future reads.
288 * @param {number} order // TODO(JSDOC).
289 */
290 ByteReader.prototype.setByteOrder = function(order) {
291 this.littleEndian_ = order == ByteReader.LITTLE_ENDIAN;
292 };
293
294 /**
295 * Throw an error if the reader is at an invalid position, or if a read a read
296 * of |size| would put it in one.
297 *
298 * You may optionally pass opt_end to override what is considered to be the
299 * end of the buffer.
300 *
301 * @param {number} size // TODO(JSDOC).
302 * @param {number=} opt_end // TODO(JSDOC).
303 */
304 ByteReader.prototype.validateRead = function(size, opt_end) {
305 if (typeof opt_end == 'undefined')
306 opt_end = this.view_.byteLength;
307
308 ByteReader.validateRead(this.view_, this.pos_, size, opt_end);
309 };
310
311 /**
312 * @param {number} width // TODO(JSDOC).
313 * @param {boolean=} opt_signed // TODO(JSDOC).
314 * @param {number=} opt_end // TODO(JSDOC).
315 * @return {string} // TODO(JSDOC).
316 */
317 ByteReader.prototype.readScalar = function(width, opt_signed, opt_end) {
318 var method = opt_signed ? 'getInt' : 'getUint';
319
320 switch (width) {
321 case 1:
322 method += '8';
323 break;
324
325 case 2:
326 method += '16';
327 break;
328
329 case 4:
330 method += '32';
331 break;
332
333 case 8:
334 method += '64';
335 break;
336
337 default:
338 throw new Error('Invalid width: ' + width);
339 break;
340 }
341
342 this.validateRead(width, opt_end);
343 var rv = this.view_[method](this.pos_, this.littleEndian_);
344 this.pos_ += width;
345 return rv;
346 };
347
348 /**
349 * Read as a sequence of characters, returning them as a single string.
350 *
351 * Adjusts the current position on success. Throws an exception if the
352 * read would go past the end of the buffer.
353 *
354 * @param {number} size // TODO(JSDOC).
355 * @param {number=} opt_end // TODO(JSDOC).
356 * @return {string} // TODO(JSDOC).
357 */
358 ByteReader.prototype.readString = function(size, opt_end) {
359 var rv = ByteReader.readString(this.view_, this.pos_, size, opt_end);
360 this.pos_ += size;
361 return rv;
362 };
363
364
365 /**
366 * Read as a sequence of characters, returning them as a single string.
367 *
368 * Adjusts the current position on success. Throws an exception if the
369 * read would go past the end of the buffer.
370 *
371 * @param {number} size // TODO(JSDOC).
372 * @param {number=} opt_end // TODO(JSDOC).
373 * @return {string} // TODO(JSDOC).
374 */
375 ByteReader.prototype.readNullTerminatedString = function(size, opt_end) {
376 var rv = ByteReader.readNullTerminatedString(this.view_,
377 this.pos_,
378 size,
379 opt_end);
380 this.pos_ += rv.length;
381
382 if (rv.length < size) {
383 // If we've stopped reading because we found '0' but didn't hit size limit
384 // then we should skip additional '0' character
385 this.pos_++;
386 }
387
388 return rv;
389 };
390
391
392 /**
393 * Read as a sequence of UTF16 characters, returning them as a single string.
394 *
395 * Adjusts the current position on success. Throws an exception if the
396 * read would go past the end of the buffer.
397 *
398 * @param {boolean} bom // TODO(JSDOC).
399 * @param {number} size // TODO(JSDOC).
400 * @param {number=} opt_end // TODO(JSDOC).
401 * @return {string} // TODO(JSDOC).
402 */
403 ByteReader.prototype.readNullTerminatedStringUTF16 =
404 function(bom, size, opt_end) {
405 var rv = ByteReader.readNullTerminatedStringUTF16(
406 this.view_, this.pos_, bom, size, opt_end);
407
408 if (bom) {
409 // If the BOM word was present advance the position.
410 this.pos_ += 2;
411 }
412
413 this.pos_ += rv.length;
414
415 if (rv.length < size) {
416 // If we've stopped reading because we found '0' but didn't hit size limit
417 // then we should skip additional '0' character
418 this.pos_ += 2;
419 }
420
421 return rv;
422 };
423
424
425 /**
426 * Read as an array of numbers.
427 *
428 * Adjusts the current position on success. Throws an exception if the
429 * read would go past the end of the buffer.
430 *
431 * @param {number} size // TODO(JSDOC).
432 * @param {number=} opt_end // TODO(JSDOC).
433 * @param {function(new:Array.<*>)=} opt_arrayConstructor // TODO(JSDOC).
434 * @return {Array.<*>} // TODO(JSDOC).
435 */
436 ByteReader.prototype.readSlice = function(size, opt_end,
437 opt_arrayConstructor) {
438 this.validateRead(size, opt_end);
439
440 var arrayConstructor = opt_arrayConstructor || Uint8Array;
441 var slice = new arrayConstructor(
442 this.view_.buffer, this.view_.byteOffset + this.pos, size);
443 this.pos_ += size;
444
445 return slice;
446 };
447
448 /**
449 * Read as a sequence of bytes, returning them as a single base64 encoded
450 * string.
451 *
452 * Adjusts the current position on success. Throws an exception if the
453 * read would go past the end of the buffer.
454 *
455 * @param {number} size // TODO(JSDOC).
456 * @param {number=} opt_end // TODO(JSDOC).
457 * @return {string} // TODO(JSDOC).
458 */
459 ByteReader.prototype.readBase64 = function(size, opt_end) {
460 var rv = ByteReader.readBase64(this.view_, this.pos_, size, opt_end);
461 this.pos_ += size;
462 return rv;
463 };
464
465 /**
466 * Read an image returning it as a data url.
467 *
468 * Adjusts the current position on success. Throws an exception if the
469 * read would go past the end of the buffer.
470 *
471 * @param {number} size // TODO(JSDOC).
472 * @param {number=} opt_end // TODO(JSDOC).
473 * @return {string} // TODO(JSDOC).
474 */
475 ByteReader.prototype.readImage = function(size, opt_end) {
476 var rv = ByteReader.readImage(this.view_, this.pos_, size, opt_end);
477 this.pos_ += size;
478 return rv;
479 };
480
481 /**
482 * Seek to a give position relative to opt_seekStart.
483 *
484 * @param {number} pos // TODO(JSDOC).
485 * @param {number=} opt_seekStart // TODO(JSDOC).
486 * @param {number=} opt_end // TODO(JSDOC).
487 */
488 ByteReader.prototype.seek = function(pos, opt_seekStart, opt_end) {
489 opt_end = opt_end || this.view_.byteLength;
490
491 var newPos;
492 if (opt_seekStart == ByteReader.SEEK_CUR) {
493 newPos = this.pos_ + pos;
494 } else if (opt_seekStart == ByteReader.SEEK_END) {
495 newPos = opt_end + pos;
496 } else {
497 newPos = pos;
498 }
499
500 if (newPos < 0 || newPos > this.view_.byteLength)
501 throw new Error('Seek outside of buffer: ' + (newPos - opt_end));
502
503 this.pos_ = newPos;
504 };
505
506 /**
507 * Seek to a given position relative to opt_seekStart, saving the current
508 * position.
509 *
510 * Recover the current position with a call to seekPop.
511 *
512 * @param {number} pos // TODO(JSDOC).
513 * @param {number=} opt_seekStart // TODO(JSDOC).
514 */
515 ByteReader.prototype.pushSeek = function(pos, opt_seekStart) {
516 var oldPos = this.pos_;
517 this.seek(pos, opt_seekStart);
518 // Alter the seekStack_ after the call to seek(), in case it throws.
519 this.seekStack_.push(oldPos);
520 };
521
522 /**
523 * Undo a previous seekPush.
524 */
525 ByteReader.prototype.popSeek = function() {
526 this.seek(this.seekStack_.pop());
527 };
528
529 /**
530 * Return the current read position.
531 * @return {number} // TODO(JSDOC).
532 */
533 ByteReader.prototype.tell = function() {
534 return this.pos_;
535 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698