mobile/android/base/favicons/decoders/IconDirectoryEntry.java

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 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 package org.mozilla.gecko.favicons.decoders;
     7 /**
     8  * Representation of an ICO file ICONDIRENTRY structure.
     9  */
    10 public class IconDirectoryEntry implements Comparable<IconDirectoryEntry> {
    12     public static int maxBPP;
    14     int width;
    15     int height;
    16     int paletteSize;
    17     int bitsPerPixel;
    18     int payloadSize;
    19     int payloadOffset;
    20     boolean payloadIsPNG;
    22     // Tracks the index in the Icon Directory of this entry. Useful only for pruning.
    23     int index;
    24     boolean isErroneous;
    26     public IconDirectoryEntry(int width, int height, int paletteSize, int bitsPerPixel, int payloadSize, int payloadOffset, boolean payloadIsPNG) {
    27         this.width = width;
    28         this.height = height;
    29         this.paletteSize = paletteSize;
    30         this.bitsPerPixel = bitsPerPixel;
    31         this.payloadSize = payloadSize;
    32         this.payloadOffset = payloadOffset;
    33         this.payloadIsPNG = payloadIsPNG;
    34     }
    36     /**
    37      * Method to get a dummy Icon Directory Entry with the Erroneous bit set.
    38      *
    39      * @return An erroneous placeholder Icon Directory Entry.
    40      */
    41     public static IconDirectoryEntry getErroneousEntry() {
    42         IconDirectoryEntry ret = new IconDirectoryEntry(-1, -1, -1, -1, -1, -1, false);
    43         ret.isErroneous = true;
    45         return ret;
    46     }
    48     /**
    49      * Create an IconDirectoryEntry object from a byte[]. Interprets the buffer starting at the given
    50      * offset as an IconDirectoryEntry and returns the result.
    51      *
    52      * @param buffer Byte array containing the icon directory entry to decode.
    53      * @param regionOffset Offset into the byte array of the valid region of the buffer.
    54      * @param regionLength Length of the valid region in the buffer.
    55      * @param entryOffset Offset of the icon directory entry to decode within the buffer.
    56      * @return An IconDirectoryEntry object representing the entry specified, or null if the entry
    57      *         is obviously invalid.
    58      */
    59     public static IconDirectoryEntry createFromBuffer(byte[] buffer, int regionOffset, int regionLength, int entryOffset) {
    60         // Verify that the reserved field is really zero.
    61         if (buffer[entryOffset + 3] != 0) {
    62             return getErroneousEntry();
    63         }
    65         // Verify that the entry points to a region that actually exists in the buffer, else bin it.
    66         int fieldPtr = entryOffset + 8;
    67         int entryLength = (buffer[fieldPtr] & 0xFF) |
    68                           (buffer[fieldPtr + 1] & 0xFF) << 8 |
    69                           (buffer[fieldPtr + 2] & 0xFF) << 16 |
    70                           (buffer[fieldPtr + 3] & 0xFF) << 24;
    72         // Advance to the offset field.
    73         fieldPtr += 4;
    75         int payloadOffset = (buffer[fieldPtr] & 0xFF) |
    76                             (buffer[fieldPtr + 1] & 0xFF) << 8 |
    77                             (buffer[fieldPtr + 2] & 0xFF) << 16 |
    78                             (buffer[fieldPtr + 3] & 0xFF) << 24;
    80         // Fail if the entry describes a region outside the buffer.
    81         if (payloadOffset < 0 || entryLength < 0 || payloadOffset + entryLength > regionOffset + regionLength) {
    82             return getErroneousEntry();
    83         }
    85         // Extract the image dimensions.
    86         int imageWidth = buffer[entryOffset] & 0xFF;
    87         int imageHeight = buffer[entryOffset+1] & 0xFF;
    89         // Because Microsoft, a size value of zero represents an image size of 256.
    90         if (imageWidth == 0) {
    91             imageWidth = 256;
    92         }
    94         if (imageHeight == 0) {
    95             imageHeight = 256;
    96         }
    98         // If the image uses a colour palette, this is the number of colours, otherwise this is zero.
    99         int paletteSize = buffer[entryOffset + 2] & 0xFF;
   101         // The plane count - usually 0 or 1. When > 1, taken as multiplier on bitsPerPixel.
   102         int colorPlanes = buffer[entryOffset + 4] & 0xFF;
   104         int bitsPerPixel = (buffer[entryOffset + 6] & 0xFF) |
   105                            (buffer[entryOffset + 7] & 0xFF) << 8;
   107         if (colorPlanes > 1) {
   108             bitsPerPixel *= colorPlanes;
   109         }
   111         // Look for PNG magic numbers at the start of the payload.
   112         boolean payloadIsPNG = FaviconDecoder.bufferStartsWith(buffer, FaviconDecoder.ImageMagicNumbers.PNG.value, regionOffset + payloadOffset);
   114         return new IconDirectoryEntry(imageWidth, imageHeight, paletteSize, bitsPerPixel, entryLength, payloadOffset, payloadIsPNG);
   115     }
   117     /**
   118      * Get the number of bytes from the start of the ICO file to the beginning of this entry.
   119      */
   120     public int getOffset() {
   121         return ICODecoder.ICO_HEADER_LENGTH_BYTES + (index * ICODecoder.ICO_ICONDIRENTRY_LENGTH_BYTES);
   122     }
   124     @Override
   125     public int compareTo(IconDirectoryEntry another) {
   126         if (width > another.width) {
   127             return 1;
   128         }
   130         if (width < another.width) {
   131             return -1;
   132         }
   134         // Where both images exceed the max BPP, take the smaller of the two BPP values.
   135         if (bitsPerPixel >= maxBPP && another.bitsPerPixel >= maxBPP) {
   136             if (bitsPerPixel < another.bitsPerPixel) {
   137                 return 1;
   138             }
   140             if (bitsPerPixel > another.bitsPerPixel) {
   141                 return -1;
   142             }
   143         }
   145         // Otherwise, take the larger of the BPP values.
   146         if (bitsPerPixel > another.bitsPerPixel) {
   147             return 1;
   148         }
   150         if (bitsPerPixel < another.bitsPerPixel) {
   151             return -1;
   152         }
   154         // Prefer large palettes.
   155         if (paletteSize > another.paletteSize) {
   156             return 1;
   157         }
   159         if (paletteSize < another.paletteSize) {
   160             return -1;
   161         }
   163         // Prefer smaller payloads.
   164         if (payloadSize < another.payloadSize) {
   165             return 1;
   166         }
   168         if (payloadSize > another.payloadSize) {
   169             return -1;
   170         }
   172         // If all else fails, prefer PNGs over BMPs. They tend to be smaller.
   173         if (payloadIsPNG && !another.payloadIsPNG) {
   174             return 1;
   175         }
   177         if (!payloadIsPNG && another.payloadIsPNG) {
   178             return -1;
   179         }
   181         return 0;
   182     }
   184     public static void setMaxBPP(int maxBPP) {
   185         IconDirectoryEntry.maxBPP = maxBPP;
   186     }
   188     @Override
   189     public String toString() {
   190         return "IconDirectoryEntry{" +
   191                 "\nwidth=" + width +
   192                 ", \nheight=" + height +
   193                 ", \npaletteSize=" + paletteSize +
   194                 ", \nbitsPerPixel=" + bitsPerPixel +
   195                 ", \npayloadSize=" + payloadSize +
   196                 ", \npayloadOffset=" + payloadOffset +
   197                 ", \npayloadIsPNG=" + payloadIsPNG +
   198                 ", \nindex=" + index +
   199                 '}';
   200     }
   201 }

mercurial