1 | /* |
2 | * Copyright (C) 2009 Apple, Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
14 | * its contributors may be used to endorse or promote products derived |
15 | * from this software without specific prior written permission. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include "config.h" |
30 | #include "PixelDumpSupport.h" |
31 | |
32 | #include "CyclicRedundancyCheck.h" |
33 | #include <cstdio> |
34 | |
35 | static void appendIntToVector(unsigned number, Vector<unsigned char>& vector) |
36 | { |
37 | size_t offset = vector.size(); |
38 | vector.grow(offset + 4); |
39 | vector[offset] = ((number >> 24) & 0xff); |
40 | vector[offset + 1] = ((number >> 16) & 0xff); |
41 | vector[offset + 2] = ((number >> 8) & 0xff); |
42 | vector[offset + 3] = (number & 0xff); |
43 | } |
44 | |
45 | static void (const char* checksum, Vector<unsigned char>& bytesToAdd) |
46 | { |
47 | // Chunks of PNG files are <length>, <type>, <data>, <crc>. |
48 | static const char [] = "\x00\x00\x00\x29tEXtchecksum\x00" ; |
49 | static const size_t prefixLength = sizeof(textCommentPrefix) - 1; // The -1 is for the null at the end of the char[]. |
50 | static const size_t checksumLength = 32; |
51 | |
52 | bytesToAdd.append(textCommentPrefix, prefixLength); |
53 | bytesToAdd.append(checksum, checksumLength); |
54 | |
55 | Vector<unsigned char> dataToCrc; |
56 | dataToCrc.append(textCommentPrefix + 4, prefixLength - 4); // Don't include the chunk length in the crc. |
57 | dataToCrc.append(checksum, checksumLength); |
58 | unsigned crc32 = computeCrc(dataToCrc); |
59 | |
60 | appendIntToVector(crc32, bytesToAdd); |
61 | } |
62 | |
63 | static size_t offsetAfterIHDRChunk(const unsigned char* data, const size_t dataLength) |
64 | { |
65 | const int = 8; |
66 | const int pngIHDRChunkLength = 25; // chunk length + "IHDR" + 13 bytes of data + checksum |
67 | return pngHeaderLength + pngIHDRChunkLength; |
68 | } |
69 | |
70 | void printPNG(const unsigned char* data, const size_t dataLength, const char* checksum) |
71 | { |
72 | Vector<unsigned char> bytesToAdd; |
73 | convertChecksumToPNGComment(checksum, bytesToAdd); |
74 | |
75 | printf("Content-Type: %s\n" , "image/png" ); |
76 | printf("Content-Length: %lu\n" , static_cast<unsigned long>(dataLength + bytesToAdd.size())); |
77 | |
78 | size_t insertOffset = offsetAfterIHDRChunk(data, dataLength); |
79 | |
80 | fwrite(data, 1, insertOffset, stdout); |
81 | fwrite(bytesToAdd.data(), 1, bytesToAdd.size(), stdout); |
82 | |
83 | const size_t bytesToWriteInOneChunk = 1 << 15; |
84 | data += insertOffset; |
85 | size_t dataRemainingToWrite = dataLength - insertOffset; |
86 | while (dataRemainingToWrite) { |
87 | size_t bytesToWriteInThisChunk = std::min(dataRemainingToWrite, bytesToWriteInOneChunk); |
88 | size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, stdout); |
89 | if (bytesWritten != bytesToWriteInThisChunk) |
90 | break; |
91 | dataRemainingToWrite -= bytesWritten; |
92 | data += bytesWritten; |
93 | } |
94 | } |
95 | |