Bug 1270832 - Activate standard c++ library hardening r=glandium
[gecko.git] / third_party / jpeg-xl / examples / decode_exif_metadata.cc
blobc1609edde326a2a28842675d2377f8b4effba226
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
6 // This C++ example decodes a JPEG XL image in one shot (all input bytes
7 // available at once). The example outputs the pixels and color information to a
8 // floating point image and an ICC profile on disk.
10 #include <jxl/decode.h>
11 #include <jxl/decode_cxx.h>
12 #include <limits.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <string.h>
17 #include <vector>
19 bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
20 std::vector<uint8_t>* exif) {
21 auto dec = JxlDecoderMake(nullptr);
23 // We're only interested in the Exif boxes in this example, so don't
24 // subscribe to events related to pixel data.
25 if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(
26 dec.get(), JXL_DEC_BOX | JXL_DEC_BOX_COMPLETE)) {
27 fprintf(stderr, "JxlDecoderSubscribeEvents failed\n");
28 return false;
30 bool support_decompression = true;
31 if (JXL_DEC_SUCCESS != JxlDecoderSetDecompressBoxes(dec.get(), JXL_TRUE)) {
32 fprintf(stderr,
33 "NOTE: decompressing brob boxes not supported with the currently "
34 "used jxl library.\n");
35 support_decompression = false;
38 JxlDecoderSetInput(dec.get(), jxl, size);
39 JxlDecoderCloseInput(dec.get());
41 const constexpr size_t kChunkSize = 65536;
42 size_t output_pos = 0;
44 for (;;) {
45 JxlDecoderStatus status = JxlDecoderProcessInput(dec.get());
46 if (status == JXL_DEC_ERROR) {
47 fprintf(stderr, "Decoder error\n");
48 return false;
49 } else if (status == JXL_DEC_NEED_MORE_INPUT) {
50 fprintf(stderr, "Error, already provided all input\n");
51 return false;
52 } else if (status == JXL_DEC_BOX) {
53 if (!exif->empty()) {
54 size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
55 exif->resize(exif->size() - remaining);
56 // No need to wait for JXL_DEC_SUCCESS or decode other boxes.
57 return true;
59 JxlBoxType type;
60 status = JxlDecoderGetBoxType(dec.get(), type,
61 TO_JXL_BOOL(support_decompression));
62 if (JXL_DEC_SUCCESS != status) {
63 fprintf(stderr, "Error, failed to get box type\n");
64 return false;
66 if (!memcmp(type, "Exif", 4)) {
67 exif->resize(kChunkSize);
68 JxlDecoderSetBoxBuffer(dec.get(), exif->data(), exif->size());
70 } else if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
71 size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
72 output_pos += kChunkSize - remaining;
73 exif->resize(exif->size() + kChunkSize);
74 JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos,
75 exif->size() - output_pos);
76 } else if (status == JXL_DEC_BOX_COMPLETE) {
77 if (!exif->empty()) {
78 size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
79 exif->resize(exif->size() - remaining);
80 return true;
82 return true;
83 } else {
84 fprintf(stderr, "Unknown decoder status\n");
85 return false;
90 bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
91 FILE* file = fopen(filename, "rb");
92 if (!file) {
93 return false;
96 if (fseek(file, 0, SEEK_END) != 0) {
97 fclose(file);
98 return false;
101 long size = ftell(file); // NOLINT
102 // Avoid invalid file or directory.
103 if (size >= LONG_MAX || size < 0) {
104 fclose(file);
105 return false;
108 if (fseek(file, 0, SEEK_SET) != 0) {
109 fclose(file);
110 return false;
113 out->resize(size);
114 size_t readsize = fread(out->data(), 1, size, file);
115 if (fclose(file) != 0) {
116 return false;
119 return readsize == static_cast<size_t>(size);
122 bool WriteFile(const char* filename, const uint8_t* data, size_t size) {
123 FILE* file = fopen(filename, "wb");
124 if (!file) {
125 fprintf(stderr, "Could not open %s for writing", filename);
126 return false;
128 fwrite(data, 1, size, file);
129 if (fclose(file) != 0) {
130 return false;
132 return true;
135 int main(int argc, char* argv[]) {
136 if (argc != 3) {
137 fprintf(stderr,
138 "Usage: %s <jxl> <exif>\n"
139 "Where:\n"
140 " jxl = input JPEG XL image filename\n"
141 " exif = output exif filename\n"
142 "Output files will be overwritten.\n",
143 argv[0]);
144 return 1;
147 const char* jxl_filename = argv[1];
148 const char* exif_filename = argv[2];
150 std::vector<uint8_t> jxl;
151 if (!LoadFile(jxl_filename, &jxl)) {
152 fprintf(stderr, "couldn't load %s\n", jxl_filename);
153 return 1;
156 std::vector<uint8_t> exif;
157 if (!DecodeJpegXlExif(jxl.data(), jxl.size(), &exif)) {
158 fprintf(stderr, "Error while decoding the jxl file\n");
159 return 1;
161 if (exif.empty()) {
162 printf("No exif data present in this image\n");
163 } else {
164 // TODO(lode): the exif box data contains the 4-byte TIFF header at the
165 // beginning, check whether this is desired to be part of the output, or
166 // should be removed.
167 if (!WriteFile(exif_filename, exif.data(), exif.size())) {
168 fprintf(stderr, "Error while writing the exif file\n");
169 return 1;
171 printf("Successfully wrote %s\n", exif_filename);
173 return 0;