image/decoders/iccjpeg.c

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * iccprofile.c
michael@0 7 *
michael@0 8 * This file provides code to read and write International Color Consortium
michael@0 9 * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has
michael@0 10 * defined a standard format for including such data in JPEG "APP2" markers.
michael@0 11 * The code given here does not know anything about the internal structure
michael@0 12 * of the ICC profile data; it just knows how to put the profile data into
michael@0 13 * a JPEG file being written, or get it back out when reading.
michael@0 14 *
michael@0 15 * This code depends on new features added to the IJG JPEG library as of
michael@0 16 * IJG release 6b; it will not compile or work with older IJG versions.
michael@0 17 *
michael@0 18 * NOTE: this code would need surgery to work on 16-bit-int machines
michael@0 19 * with ICC profiles exceeding 64K bytes in size. If you need to do that,
michael@0 20 * change all the "unsigned int" variables to "INT32". You'll also need
michael@0 21 * to find a malloc() replacement that can allocate more than 64K.
michael@0 22 */
michael@0 23
michael@0 24 #include "iccjpeg.h"
michael@0 25 #include <stdlib.h> /* define malloc() */
michael@0 26
michael@0 27
michael@0 28 /*
michael@0 29 * Since an ICC profile can be larger than the maximum size of a JPEG marker
michael@0 30 * (64K), we need provisions to split it into multiple markers. The format
michael@0 31 * defined by the ICC specifies one or more APP2 markers containing the
michael@0 32 * following data:
michael@0 33 * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
michael@0 34 * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
michael@0 35 * Number of markers Total number of APP2's used (1 byte)
michael@0 36 * Profile data (remainder of APP2 data)
michael@0 37 * Decoders should use the marker sequence numbers to reassemble the profile,
michael@0 38 * rather than assuming that the APP2 markers appear in the correct sequence.
michael@0 39 */
michael@0 40
michael@0 41 #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
michael@0 42 #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
michael@0 43 #define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
michael@0 44 #define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
michael@0 45
michael@0 46 /*
michael@0 47 * Prepare for reading an ICC profile
michael@0 48 */
michael@0 49
michael@0 50 void
michael@0 51 setup_read_icc_profile (j_decompress_ptr cinfo)
michael@0 52 {
michael@0 53 /* Tell the library to keep any APP2 data it may find */
michael@0 54 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
michael@0 55 }
michael@0 56
michael@0 57
michael@0 58 /*
michael@0 59 * Handy subroutine to test whether a saved marker is an ICC profile marker.
michael@0 60 */
michael@0 61
michael@0 62 static boolean
michael@0 63 marker_is_icc (jpeg_saved_marker_ptr marker)
michael@0 64 {
michael@0 65 return
michael@0 66 marker->marker == ICC_MARKER &&
michael@0 67 marker->data_length >= ICC_OVERHEAD_LEN &&
michael@0 68 /* verify the identifying string */
michael@0 69 GETJOCTET(marker->data[0]) == 0x49 &&
michael@0 70 GETJOCTET(marker->data[1]) == 0x43 &&
michael@0 71 GETJOCTET(marker->data[2]) == 0x43 &&
michael@0 72 GETJOCTET(marker->data[3]) == 0x5F &&
michael@0 73 GETJOCTET(marker->data[4]) == 0x50 &&
michael@0 74 GETJOCTET(marker->data[5]) == 0x52 &&
michael@0 75 GETJOCTET(marker->data[6]) == 0x4F &&
michael@0 76 GETJOCTET(marker->data[7]) == 0x46 &&
michael@0 77 GETJOCTET(marker->data[8]) == 0x49 &&
michael@0 78 GETJOCTET(marker->data[9]) == 0x4C &&
michael@0 79 GETJOCTET(marker->data[10]) == 0x45 &&
michael@0 80 GETJOCTET(marker->data[11]) == 0x0;
michael@0 81 }
michael@0 82
michael@0 83
michael@0 84 /*
michael@0 85 * See if there was an ICC profile in the JPEG file being read;
michael@0 86 * if so, reassemble and return the profile data.
michael@0 87 *
michael@0 88 * TRUE is returned if an ICC profile was found, FALSE if not.
michael@0 89 * If TRUE is returned, *icc_data_ptr is set to point to the
michael@0 90 * returned data, and *icc_data_len is set to its length.
michael@0 91 *
michael@0 92 * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
michael@0 93 * and must be freed by the caller with free() when the caller no longer
michael@0 94 * needs it. (Alternatively, we could write this routine to use the
michael@0 95 * IJG library's memory allocator, so that the data would be freed implicitly
michael@0 96 * at jpeg_finish_decompress() time. But it seems likely that many apps
michael@0 97 * will prefer to have the data stick around after decompression finishes.)
michael@0 98 *
michael@0 99 * NOTE: if the file contains invalid ICC APP2 markers, we just silently
michael@0 100 * return FALSE. You might want to issue an error message instead.
michael@0 101 */
michael@0 102
michael@0 103 boolean
michael@0 104 read_icc_profile (j_decompress_ptr cinfo,
michael@0 105 JOCTET **icc_data_ptr,
michael@0 106 unsigned int *icc_data_len)
michael@0 107 {
michael@0 108 jpeg_saved_marker_ptr marker;
michael@0 109 int num_markers = 0;
michael@0 110 int seq_no;
michael@0 111 JOCTET *icc_data;
michael@0 112 unsigned int total_length;
michael@0 113 #define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */
michael@0 114 char marker_present[MAX_SEQ_NO+1]; /* 1 if marker found */
michael@0 115 unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
michael@0 116 unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
michael@0 117
michael@0 118 *icc_data_ptr = NULL; /* avoid confusion if FALSE return */
michael@0 119 *icc_data_len = 0;
michael@0 120
michael@0 121 /* This first pass over the saved markers discovers whether there are
michael@0 122 * any ICC markers and verifies the consistency of the marker numbering.
michael@0 123 */
michael@0 124
michael@0 125 for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
michael@0 126 marker_present[seq_no] = 0;
michael@0 127
michael@0 128 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
michael@0 129 if (marker_is_icc(marker)) {
michael@0 130 if (num_markers == 0)
michael@0 131 num_markers = GETJOCTET(marker->data[13]);
michael@0 132 else if (num_markers != GETJOCTET(marker->data[13]))
michael@0 133 return FALSE; /* inconsistent num_markers fields */
michael@0 134 seq_no = GETJOCTET(marker->data[12]);
michael@0 135 if (seq_no <= 0 || seq_no > num_markers)
michael@0 136 return FALSE; /* bogus sequence number */
michael@0 137 if (marker_present[seq_no])
michael@0 138 return FALSE; /* duplicate sequence numbers */
michael@0 139 marker_present[seq_no] = 1;
michael@0 140 data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
michael@0 141 }
michael@0 142 }
michael@0 143
michael@0 144 if (num_markers == 0)
michael@0 145 return FALSE;
michael@0 146
michael@0 147 /* Check for missing markers, count total space needed,
michael@0 148 * compute offset of each marker's part of the data.
michael@0 149 */
michael@0 150
michael@0 151 total_length = 0;
michael@0 152 for (seq_no = 1; seq_no <= num_markers; seq_no++) {
michael@0 153 if (marker_present[seq_no] == 0)
michael@0 154 return FALSE; /* missing sequence number */
michael@0 155 data_offset[seq_no] = total_length;
michael@0 156 total_length += data_length[seq_no];
michael@0 157 }
michael@0 158
michael@0 159 if (total_length <= 0)
michael@0 160 return FALSE; /* found only empty markers? */
michael@0 161
michael@0 162 /* Allocate space for assembled data */
michael@0 163 icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
michael@0 164 if (icc_data == NULL)
michael@0 165 return FALSE; /* oops, out of memory */
michael@0 166
michael@0 167 /* and fill it in */
michael@0 168 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
michael@0 169 if (marker_is_icc(marker)) {
michael@0 170 JOCTET FAR *src_ptr;
michael@0 171 JOCTET *dst_ptr;
michael@0 172 unsigned int length;
michael@0 173 seq_no = GETJOCTET(marker->data[12]);
michael@0 174 dst_ptr = icc_data + data_offset[seq_no];
michael@0 175 src_ptr = marker->data + ICC_OVERHEAD_LEN;
michael@0 176 length = data_length[seq_no];
michael@0 177 while (length--) {
michael@0 178 *dst_ptr++ = *src_ptr++;
michael@0 179 }
michael@0 180 }
michael@0 181 }
michael@0 182
michael@0 183 *icc_data_ptr = icc_data;
michael@0 184 *icc_data_len = total_length;
michael@0 185
michael@0 186 return TRUE;
michael@0 187 }

mercurial