B2G/gecko/browser/components/sessionstore/src/SessionStore.jsm
/**
   * expands serialized history data into a session-history-entry instance
   * @param aEntry
   *        Object containing serialized history data for a URL
   * @param aIdMap
   *        Hash for ensuring unique frame IDs
   * @returns nsISHEntry
   */
expands serialized history data into a session-history-entry instance
@param aEntry
Object containing serialized history data for a URL
@param aIdMap
Hash for ensuring unique frame IDs
@returns nsISHEntry
expands serialized history data into a session - history - entry instance @param aEntry Object containing serialized history data for a URL @param aIdMap Hash for ensuring unique frame IDs @returns nsISHEntry
function ssi_deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) {
    var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
                  createInstance(Ci.nsISHEntry);
    shEntry.setURI(this._getURIFromString(aEntry.url));
    shEntry.setTitle(aEntry.title || aEntry.url);
    if (aEntry.subframe)
      shEntry.setIsSubFrame(aEntry.subframe || false);
    shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
    if (aEntry.contentType)
      shEntry.contentType = aEntry.contentType;
    if (aEntry.referrer)
      shEntry.referrerURI = this._getURIFromString(aEntry.referrer);
    if (aEntry.cacheKey) {
      var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
                     createInstance(Ci.nsISupportsPRUint32);
      cacheKey.data = aEntry.cacheKey;
      shEntry.cacheKey = cacheKey;
    }
    if (aEntry.ID) {
      var id = aIdMap[aEntry.ID] || 0;
      if (!id) {
        for (id = Date.now(); id in aIdMap.used; id++);
        aIdMap[aEntry.ID] = id;
        aIdMap.used[id] = true;
      }
      shEntry.ID = id;
    }
    if (aEntry.docshellID)
      shEntry.docshellID = aEntry.docshellID;
    if (aEntry.structuredCloneState && aEntry.structuredCloneVersion) {
      shEntry.stateData =
        Cc["@mozilla.org/docshell/structured-clone-container;1"].
        createInstance(Ci.nsIStructuredCloneContainer);
      shEntry.stateData.initFromBase64(aEntry.structuredCloneState,
                                       aEntry.structuredCloneVersion);
    }
    if (aEntry.scroll) {
      var scrollPos = (aEntry.scroll || "0,0").split(",");
      scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
      shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
    }
    if (aEntry.postdata_b64) {
      var postdata = atob(aEntry.postdata_b64);
      var stream = Cc["@mozilla.org/io/string-input-stream;1"].
                   createInstance(Ci.nsIStringInputStream);
      stream.setData(postdata, postdata.length);
      shEntry.postData = stream;
    }
    let childDocIdents = {};
    if (aEntry.docIdentifier) {
      let matchingEntry = aDocIdentMap[aEntry.docIdentifier];
      if (!matchingEntry) {
        matchingEntry = {shEntry: shEntry, childDocIdents: childDocIdents};
        aDocIdentMap[aEntry.docIdentifier] = matchingEntry;
      }
      else {
        shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
        childDocIdents = matchingEntry.childDocIdents;
      }
    }
    if (aEntry.owner_b64) {
      var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
                       createInstance(Ci.nsIStringInputStream);
      var binaryData = atob(aEntry.owner_b64);
      ownerInput.setData(binaryData, binaryData.length);
      var binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
                         createInstance(Ci.nsIObjectInputStream);
      binaryStream.setInputStream(ownerInput);
      try { 
        shEntry.owner = binaryStream.readObject(true);
      } catch (ex) { debug(ex); }
    }
    if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
      for (var i = 0; i < aEntry.children.length; i++) {
        if (!aEntry.children[i].url)
          continue;
         If we were to respect these doc identifiers, we'd create a cycle in
         the SHEntries themselves, which causes the docshell to loop forever
         when it looks for the root SHEntry.
         So as a hack to fix this, we restrict the scope of a doc identifier
         to be a node's siblings and cousins, and pass childDocIdents, not
         aDocIdents, to _deserializeHistoryEntry.  That is, we say that two
         SHEntries with the same doc identifier have the same document iff
         they have the same parent or their parents have the same document.
        shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap,
                                                       childDocIdents), i);
      }
    }
    return shEntry;
  }
function ssi_deserializeHistoryEntry ( aEntry , aIdMap , aDocIdentMap ) { var shEntry = Cc [ "@mozilla.org/browser/session-history-entry;1" ] . createInstance ( Ci . nsISHEntry ) ; shEntry . setURI ( this . _getURIFromString ( aEntry . url ) ) ; shEntry . setTitle ( aEntry . title || aEntry . url ) ; if ( aEntry . subframe ) shEntry . setIsSubFrame ( aEntry . subframe || false ) ; shEntry . loadType = Ci . nsIDocShellLoadInfo . loadHistory ; if ( aEntry . contentType ) shEntry . contentType = aEntry . contentType ; if ( aEntry . referrer ) shEntry . referrerURI = this . _getURIFromString ( aEntry . referrer ) ; if ( aEntry . cacheKey ) { var cacheKey = Cc [ "@mozilla.org/supports-PRUint32;1" ] . createInstance ( Ci . nsISupportsPRUint32 ) ; cacheKey . data = aEntry . cacheKey ; shEntry . cacheKey = cacheKey ; } if ( aEntry . ID ) { var id = aIdMap [ aEntry . ID ] || 0 ; if ( ! id ) { for ( id = Date . now ( ) ; id in aIdMap . used ; id ++ ) ; aIdMap [ aEntry . ID ] = id ; aIdMap . used [ id ] = true ; } shEntry . ID = id ; } if ( aEntry . docshellID ) shEntry . docshellID = aEntry . docshellID ; if ( aEntry . structuredCloneState && aEntry . structuredCloneVersion ) { shEntry . stateData = Cc [ "@mozilla.org/docshell/structured-clone-container;1" ] . createInstance ( Ci . nsIStructuredCloneContainer ) ; shEntry . stateData . initFromBase64 ( aEntry . structuredCloneState , aEntry . structuredCloneVersion ) ; } if ( aEntry . scroll ) { var scrollPos = ( aEntry . scroll || "0,0" ) . split ( "," ) ; scrollPos = [ parseInt ( scrollPos [ 0 ] ) || 0 , parseInt ( scrollPos [ 1 ] ) || 0 ] ; shEntry . setScrollPosition ( scrollPos [ 0 ] , scrollPos [ 1 ] ) ; } if ( aEntry . postdata_b64 ) { var postdata = atob ( aEntry . postdata_b64 ) ; var stream = Cc [ "@mozilla.org/io/string-input-stream;1" ] . createInstance ( Ci . nsIStringInputStream ) ; stream . setData ( postdata , postdata . length ) ; shEntry . postData = stream ; } let childDocIdents = { } ; if ( aEntry . docIdentifier ) { let matchingEntry = aDocIdentMap [ aEntry . docIdentifier ] ; if ( ! matchingEntry ) { matchingEntry = { shEntry : shEntry , childDocIdents : childDocIdents } ; aDocIdentMap [ aEntry . docIdentifier ] = matchingEntry ; } else { shEntry . adoptBFCacheEntry ( matchingEntry . shEntry ) ; childDocIdents = matchingEntry . childDocIdents ; } } if ( aEntry . owner_b64 ) { var ownerInput = Cc [ "@mozilla.org/io/string-input-stream;1" ] . createInstance ( Ci . nsIStringInputStream ) ; var binaryData = atob ( aEntry . owner_b64 ) ; ownerInput . setData ( binaryData , binaryData . length ) ; var binaryStream = Cc [ "@mozilla.org/binaryinputstream;1" ] . createInstance ( Ci . nsIObjectInputStream ) ; binaryStream . setInputStream ( ownerInput ) ; try { shEntry . owner = binaryStream . readObject ( true ) ; } catch ( ex ) { debug ( ex ) ; } } if ( aEntry . children && shEntry instanceof Ci . nsISHContainer ) { for ( var i = 0 ; i < aEntry . children . length ; i ++ ) { if ( ! aEntry . children [ i ] . url ) continue ; shEntry . AddChild ( this . _deserializeHistoryEntry ( aEntry . children [ i ] , aIdMap , childDocIdents ) , i ) ; } } return shEntry ; }
expands serialized history data into a session-history-entry instance
 @param aEntry
        Object containing serialized history data for a URL
 @param aIdMap
        Hash for ensuring unique frame IDs
 @returns nsISHEntry
expands serialized history data into a session - history - entry instance @param aEntry Object containing serialized history data for a URL @param aIdMap Hash for ensuring unique frame IDs @returns nsISHEntry
// get a new unique ID for this frame (since the one from the last // start might already be in use) // If we have a serialized document identifier, try to find an SHEntry // which matches that doc identifier and adopt that SHEntry's // BFCacheEntry.  If we don't find a match, insert shEntry as the match // for the document identifier. // Catch possible deserialization exceptions //XXXzpao Wallpaper patch for bug 514751 // We're getting sessionrestore.js files with a cycle in the // doc-identifier graph, likely due to bug 698656.  (That is, we have // an entry where doc identifier A is an ancestor of doc identifier B, // and another entry where doc identifier B is an ancestor of A.) // // If we were to respect these doc identifiers, we'd create a cycle in // the SHEntries themselves, which causes the docshell to loop forever // when it looks for the root SHEntry. // // So as a hack to fix this, we restrict the scope of a doc identifier // to be a node's siblings and cousins, and pass childDocIdents, not // aDocIdents, to _deserializeHistoryEntry.  That is, we say that two // SHEntries with the same doc identifier have the same document iff // they have the same parent or their parents have the same document.