| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/extras/importer/jszip.html"> |
| <link rel="import" href="/importer/importer.html"> |
| <link rel="import" href="/model/model.html"> |
| |
| <script> |
| 'use strict'; |
| |
| /** |
| * @fileoverview GzipImporter inflates gzip compressed data and passes it along |
| * to an actual importer. |
| */ |
| tr.exportTo('tr.e.importer', function() { |
| var Importer = tr.importer.Importer; |
| |
| var GZIP_MEMBER_HEADER_ID_SIZE = 3; |
| |
| var GZIP_HEADER_ID1 = 0x1f; |
| var GZIP_HEADER_ID2 = 0x8b; |
| var GZIP_DEFLATE_COMPRESSION = 8; |
| |
| function GzipImporter(model, eventData) { |
| // Normalize the data into an Uint8Array. |
| if (typeof(eventData) === 'string' || eventData instanceof String) { |
| eventData = JSZip.utils.transformTo('uint8array', eventData); |
| } else if (eventData instanceof ArrayBuffer) { |
| eventData = new Uint8Array(eventData); |
| } else |
| throw new Error('Unknown gzip data format'); |
| this.model_ = model; |
| this.gzipData_ = eventData; |
| } |
| |
| /** |
| * @param {eventData} Possibly gzip compressed data as a string or an |
| * ArrayBuffer. |
| * @return {boolean} Whether obj looks like gzip compressed data. |
| */ |
| GzipImporter.canImport = function(eventData) { |
| var header; |
| if (eventData instanceof ArrayBuffer) |
| header = new Uint8Array(eventData.slice(0, GZIP_MEMBER_HEADER_ID_SIZE)); |
| else if (typeof(eventData) === 'string' || eventData instanceof String) { |
| header = eventData.substring(0, GZIP_MEMBER_HEADER_ID_SIZE); |
| // Convert the string to a byteArray for correct value comparison. |
| header = JSZip.utils.transformTo('uint8array', header); |
| } else |
| return false; |
| return header[0] == GZIP_HEADER_ID1 && |
| header[1] == GZIP_HEADER_ID2 && |
| header[2] == GZIP_DEFLATE_COMPRESSION; |
| }; |
| |
| /** |
| * Inflates (decompresses) the data stored in the given gzip bitstream. |
| * @return {string} Inflated data. |
| */ |
| GzipImporter.inflateGzipData_ = function(data) { |
| var position = 0; |
| |
| function getByte() { |
| if (position >= data.length) |
| throw new Error('Unexpected end of gzip data'); |
| return data[position++]; |
| } |
| |
| function getWord() { |
| var low = getByte(); |
| var high = getByte(); |
| return (high << 8) + low; |
| } |
| |
| function skipBytes(amount) { |
| position += amount; |
| } |
| |
| function skipZeroTerminatedString() { |
| while (getByte() != 0) {} |
| } |
| |
| var id1 = getByte(); |
| var id2 = getByte(); |
| if (id1 !== GZIP_HEADER_ID1 || id2 !== GZIP_HEADER_ID2) |
| throw new Error('Not gzip data'); |
| var compression_method = getByte(); |
| if (compression_method !== GZIP_DEFLATE_COMPRESSION) |
| throw new Error('Unsupported compression method: ' + compression_method); |
| var flags = getByte(); |
| var have_header_crc = flags & (1 << 1); |
| var have_extra_fields = flags & (1 << 2); |
| var have_file_name = flags & (1 << 3); |
| var have_comment = flags & (1 << 4); |
| |
| // Skip modification time, extra flags and OS. |
| skipBytes(4 + 1 + 1); |
| |
| // Skip remaining fields before compressed data. |
| if (have_extra_fields) { |
| var bytes_to_skip = getWord(); |
| skipBytes(bytes_to_skip); |
| } |
| if (have_file_name) |
| skipZeroTerminatedString(); |
| if (have_comment) |
| skipZeroTerminatedString(); |
| if (have_header_crc) |
| getWord(); |
| |
| // Inflate the data using jszip. |
| var inflated_data = |
| JSZip.compressions['DEFLATE'].uncompress(data.subarray(position)); |
| return JSZip.utils.transformTo('string', inflated_data); |
| }, |
| |
| GzipImporter.prototype = { |
| __proto__: Importer.prototype, |
| |
| /** |
| * Called by the Model to check whether the importer just encapsulates |
| * the actual trace data which needs to be imported by another importer. |
| */ |
| isTraceDataContainer: function() { |
| return true; |
| }, |
| |
| /** |
| * Called by the Model to extract subtraces from the event data. The |
| * subtraces are passed on to other importers that can recognize them. |
| */ |
| extractSubtraces: function() { |
| var eventData = GzipImporter.inflateGzipData_(this.gzipData_); |
| return eventData ? [eventData] : []; |
| } |
| }; |
| |
| tr.importer.Importer.register(GzipImporter); |
| |
| return { |
| GzipImporter: GzipImporter |
| }; |
| }); |
| </script> |