1 <!DOCTYPE html> 2 <!-- 3 Copyright (c) 2013 The Chromium Authors. All rights reserved. 4 Use of this source code is governed by a BSD-style license that can be 5 found in the LICENSE file. 6 --> 7 8 <link rel="import" href="/extras/importer/jszip.html"> 9 <link rel="import" href="/importer/importer.html"> 10 <link rel="import" href="/model/model.html"> 11 12 <script> 13 'use strict'; 14 15 /** 16 * @fileoverview GzipImporter inflates gzip compressed data and passes it along 17 * to an actual importer. 18 */ 19 tr.exportTo('tr.e.importer', function() { 20 var Importer = tr.importer.Importer; 21 22 var GZIP_MEMBER_HEADER_ID_SIZE = 3; 23 24 var GZIP_HEADER_ID1 = 0x1f; 25 var GZIP_HEADER_ID2 = 0x8b; 26 var GZIP_DEFLATE_COMPRESSION = 8; 27 28 function GzipImporter(model, eventData) { 29 // Normalize the data into an Uint8Array. 30 if (typeof(eventData) === 'string' || eventData instanceof String) { 31 eventData = JSZip.utils.transformTo('uint8array', eventData); 32 } else if (eventData instanceof ArrayBuffer) { 33 eventData = new Uint8Array(eventData); 34 } else 35 throw new Error('Unknown gzip data format'); 36 this.model_ = model; 37 this.gzipData_ = eventData; 38 } 39 40 /** 41 * @param {eventData} Possibly gzip compressed data as a string or an 42 * ArrayBuffer. 43 * @return {boolean} Whether obj looks like gzip compressed data. 44 */ 45 GzipImporter.canImport = function(eventData) { 46 var header; 47 if (eventData instanceof ArrayBuffer) 48 header = new Uint8Array(eventData.slice(0, GZIP_MEMBER_HEADER_ID_SIZE)); 49 else if (typeof(eventData) === 'string' || eventData instanceof String) { 50 header = eventData.substring(0, GZIP_MEMBER_HEADER_ID_SIZE); 51 // Convert the string to a byteArray for correct value comparison. 52 header = JSZip.utils.transformTo('uint8array', header); 53 } else 54 return false; 55 return header[0] == GZIP_HEADER_ID1 && 56 header[1] == GZIP_HEADER_ID2 && 57 header[2] == GZIP_DEFLATE_COMPRESSION; 58 }; 59 60 /** 61 * Inflates (decompresses) the data stored in the given gzip bitstream. 62 * @return {string} Inflated data. 63 */ 64 GzipImporter.inflateGzipData_ = function(data) { 65 var position = 0; 66 67 function getByte() { 68 if (position >= data.length) 69 throw new Error('Unexpected end of gzip data'); 70 return data[position++]; 71 } 72 73 function getWord() { 74 var low = getByte(); 75 var high = getByte(); 76 return (high << 8) + low; 77 } 78 79 function skipBytes(amount) { 80 position += amount; 81 } 82 83 function skipZeroTerminatedString() { 84 while (getByte() != 0) {} 85 } 86 87 var id1 = getByte(); 88 var id2 = getByte(); 89 if (id1 !== GZIP_HEADER_ID1 || id2 !== GZIP_HEADER_ID2) 90 throw new Error('Not gzip data'); 91 var compression_method = getByte(); 92 if (compression_method !== GZIP_DEFLATE_COMPRESSION) 93 throw new Error('Unsupported compression method: ' + compression_method); 94 var flags = getByte(); 95 var have_header_crc = flags & (1 << 1); 96 var have_extra_fields = flags & (1 << 2); 97 var have_file_name = flags & (1 << 3); 98 var have_comment = flags & (1 << 4); 99 100 // Skip modification time, extra flags and OS. 101 skipBytes(4 + 1 + 1); 102 103 // Skip remaining fields before compressed data. 104 if (have_extra_fields) { 105 var bytes_to_skip = getWord(); 106 skipBytes(bytes_to_skip); 107 } 108 if (have_file_name) 109 skipZeroTerminatedString(); 110 if (have_comment) 111 skipZeroTerminatedString(); 112 if (have_header_crc) 113 getWord(); 114 115 // Inflate the data using jszip. 116 var inflated_data = 117 JSZip.compressions['DEFLATE'].uncompress(data.subarray(position)); 118 return JSZip.utils.transformTo('string', inflated_data); 119 }, 120 121 GzipImporter.prototype = { 122 __proto__: Importer.prototype, 123 124 /** 125 * Called by the Model to check whether the importer just encapsulates 126 * the actual trace data which needs to be imported by another importer. 127 */ 128 isTraceDataContainer: function() { 129 return true; 130 }, 131 132 /** 133 * Called by the Model to extract subtraces from the event data. The 134 * subtraces are passed on to other importers that can recognize them. 135 */ 136 extractSubtraces: function() { 137 var eventData = GzipImporter.inflateGzipData_(this.gzipData_); 138 return eventData ? [eventData] : []; 139 } 140 }; 141 142 tr.importer.Importer.register(GzipImporter); 143 144 return { 145 GzipImporter: GzipImporter 146 }; 147 }); 148 </script> 149