browser/extensions/shumway/content/web/preview.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
     2 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
     3 /*
     4  * Copyright 2013 Mozilla Foundation
     5  *
     6  * Licensed under the Apache License, Version 2.0 (the "License");
     7  * you may not use this file except in compliance with the License.
     8  * You may obtain a copy of the License at
     9  *
    10  *     http://www.apache.org/licenses/LICENSE-2.0
    11  *
    12  * Unless required by applicable law or agreed to in writing, software
    13  * distributed under the License is distributed on an "AS IS" BASIS,
    14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  * See the License for the specific language governing permissions and
    16  * limitations under the License.
    17  */
    20 // Extenstion communication object
    21 var FirefoxCom = (function FirefoxComClosure() {
    22   return {
    23     /**
    24      * Creates an event that the extension is listening for and will
    25      * synchronously respond to.
    26      * NOTE: It is reccomended to use request() instead since one day we may not
    27      * be able to synchronously reply.
    28      * @param {String} action The action to trigger.
    29      * @param {String} data Optional data to send.
    30      * @return {*} The response.
    31      */
    32     requestSync: function(action, data) {
    33       var request = document.createTextNode('');
    34       document.documentElement.appendChild(request);
    36       var sender = document.createEvent('CustomEvent');
    37       sender.initCustomEvent('shumway.message', true, false,
    38           {action: action, data: data, sync: true});
    39       request.dispatchEvent(sender);
    40       var response = sender.detail.response;
    41       document.documentElement.removeChild(request);
    42       return response;
    43     },
    44     /**
    45      * Creates an event that the extension is listening for and will
    46      * asynchronously respond by calling the callback.
    47      * @param {String} action The action to trigger.
    48      * @param {String} data Optional data to send.
    49      * @param {Function} callback Optional response callback that will be called
    50      * with one data argument.
    51      */
    52     request: function(action, data, callback) {
    53       var request = document.createTextNode('');
    54       request.setUserData('action', action, null);
    55       request.setUserData('data', data, null);
    56       request.setUserData('sync', false, null);
    57       if (callback) {
    58         request.setUserData('callback', callback, null);
    60         document.addEventListener('shumway.response', function listener(event) {
    61           var node = event.target,
    62               response = event.detail.response;
    64           document.documentElement.removeChild(node);
    66           document.removeEventListener('shumway.response', listener, false);
    67           return callback(response);
    68         }, false);
    69       }
    70       document.documentElement.appendChild(request);
    72       var sender = document.createEvent('CustomEvent');
    73       sender.initCustomEvent('shumway.message', true, false,
    74           {action: action, data: data, sync: false});
    75       return request.dispatchEvent(sender);
    76     }
    77   };
    78 })();
    80 function fallback() {
    81   FirefoxCom.requestSync('fallback', null)
    82 }
    84 var BYTES_TO_LOAD = 32768;
    85 var BYTES_TO_PARSE = 32768;
    87 function runSniffer() {
    88   var flashParams = JSON.parse(FirefoxCom.requestSync('getPluginParams', null));
    89   document.head.getElementsByTagName('base')[0].href = flashParams.baseUrl;
    90   movieUrl = flashParams.url;
    91   document.getElementById('playbutton').addEventListener('click', function() {
    92     switchToFullMode();
    93   });
    94   document.getElementById('fullmode').addEventListener('click', function() {
    95     switchToFullMode();
    96     return false;
    97   });
    98   document.getElementById('fallback').addEventListener('click', function() {
    99     fallback();
   100     return false;
   101   });
   102   FirefoxCom.requestSync('loadFile', {url: movieUrl, sessionId: 0, limit: BYTES_TO_LOAD});
   103 }
   105 var subscription, movieUrl, buffers = [];;
   107 addEventListener("message", function handlerMessage(e) {
   108   var args = e.data;
   109   switch (args.callback) {
   110     case "loadFile":
   111       if (args.sessionId != 0) {
   112         return;
   113       }
   114       switch (args.topic) {
   115         case "progress":
   116           buffers.push(args.array);
   117           break;
   118         case "error":
   119           console.error('Unable to download ' + movieUrl + ': ' + args.error);
   120           break;
   121         case "close":
   122           parseSwf();
   123           break;
   124       }
   125       break;
   126   }
   127 }, true);
   129 function inflateData(bytes, outputLength) {
   130   verifyDeflateHeader(bytes);
   131   var stream = new Stream(bytes, 2);
   132   var output = {
   133     data: new Uint8Array(outputLength),
   134     available: 0,
   135     completed: false
   136   };
   137   var state = {};
   138   // inflate while we can
   139   try {
   140     do {
   141       inflateBlock(stream, output, state);
   142     } while (!output.completed && stream.pos < stream.end
   143         && output.available < outputLength);
   144   } catch (e) {
   145     console.log('inflate aborted: ' + e);
   146   }
   147   return new Stream(output.data, 0, Math.min(output.available, outputLength));
   148 }
   150 function parseSwf() {
   151   var sum = 0;
   152   for (var i = 0; i < buffers.length; i++)
   153     sum += buffers[i].length;
   154   var data = new Uint8Array(sum), j = 0;
   155   for (var i = 0; i < buffers.length; i++) {
   156     data.set(buffers[i], j); j += buffers[i].length;
   157   }
   159   var backgroundColor;
   160   try {
   161     var magic1 = data[0];
   162     var magic2 = data[1];
   163     var magic3 = data[2];
   164     if ((magic1 !== 70 && magic1 !== 67) || magic2 !== 87 || magic3 !== 83)
   165       throw new Error('unsupported file format');
   167     var compressed = magic1 === 67;
   168     var stream = compressed ? inflateData(data.subarray(8), BYTES_TO_PARSE) :
   169         new Stream(data, 8, data.length - 8);
   170     var bytes = stream.bytes;
   172     var SWF_TAG_CODE_SET_BACKGROUND_COLOR = 9;
   173     var PREFETCH_SIZE = 17 /* RECT */ +
   174         4  /* Frames rate and count */;;
   175     stream.ensure(PREFETCH_SIZE);
   176     var rectFieldSize = bytes[stream.pos] >> 3;
   177     stream.pos += ((5 + 4 * rectFieldSize + 7) >> 3) + 4; // skipping other header fields
   179     // for now just sniffing background color
   180     while (stream.pos < stream.end &&
   181         !backgroundColor) {
   182       stream.ensure(2);
   183       var tagCodeAndLength = stream.getUint16(stream.pos, true);
   184       stream.pos += 2;
   185       var tagCode = tagCodeAndLength >> 6;
   186       var length = tagCodeAndLength & 0x3F;
   187       if (length == 0x3F) {
   188         stream.ensure(4);
   189         length = stream.getInt32(stream.pos, true);
   190         stream.pos += 4;
   191         if (length < 0) throw new Error('invalid length');
   192       }
   193       stream.ensure(length);
   194       switch (tagCode) {
   195         case SWF_TAG_CODE_SET_BACKGROUND_COLOR:
   196           backgroundColor = 'rgb(' + bytes[stream.pos] + ', ' +
   197               bytes[stream.pos + 1] + ', ' +
   198               bytes[stream.pos + 2] + ')';
   199           break;
   200       }
   201       stream.pos += length;
   202     }
   203   } catch (e) {
   204     console.log('parsing aborted: ' + e);
   205   }
   206   if (backgroundColor) {
   207     document.body.style.backgroundColor = backgroundColor;
   208   }
   209 }
   211 document.addEventListener('keydown', function (e) {
   212   if (e.keyCode == 119 && e.ctrlKey) { // Ctrl+F8
   213     window.location.replace("data:application/x-moz-playpreview;,application/x-shockwave-flash,full,paused=true");
   214   }
   215 }, false);
   217 function switchToFullMode() {
   218   window.location.replace("data:application/x-moz-playpreview;,application/x-shockwave-flash,full");
   219 }

mercurial