1 // Copyright 2019 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fxcodec/jpx/cjpx_decoder.h"
8 
9 #include <algorithm>
10 #include <limits>
11 #include <utility>
12 
13 #include "core/fxcodec/jpx/jpx_decode_utils.h"
14 #include "core/fxcrt/fx_safe_types.h"
15 #include "third_party/base/optional.h"
16 #include "third_party/base/ptr_util.h"
17 #include "third_party/base/stl_util.h"
18 
19 #if !defined(USE_SYSTEM_LIBOPENJPEG2)
20 #include "third_party/libopenjpeg20/opj_malloc.h"
21 #endif
22 
23 namespace fxcodec {
24 
25 namespace {
26 
27 // Used with std::unique_ptr to call opj_image_data_free on raw memory.
28 struct OpjImageDataDeleter {
operator ()fxcodec::__anon6e0280cc0111::OpjImageDataDeleter29   inline void operator()(void* ptr) const { opj_image_data_free(ptr); }
30 };
31 
32 using ScopedOpjImageData = std::unique_ptr<int, OpjImageDataDeleter>;
33 
34 struct OpjImageRgbData {
35   ScopedOpjImageData r;
36   ScopedOpjImageData g;
37   ScopedOpjImageData b;
38 };
39 
fx_ignore_callback(const char * msg,void * client_data)40 void fx_ignore_callback(const char* msg, void* client_data) {}
41 
fx_opj_stream_create_memory_stream(DecodeData * data)42 opj_stream_t* fx_opj_stream_create_memory_stream(DecodeData* data) {
43   if (!data || !data->src_data || data->src_size <= 0)
44     return nullptr;
45 
46   opj_stream_t* stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE,
47                                            /*p_is_input=*/OPJ_TRUE);
48   if (!stream)
49     return nullptr;
50 
51   opj_stream_set_user_data(stream, data, nullptr);
52   opj_stream_set_user_data_length(stream, data->src_size);
53   opj_stream_set_read_function(stream, opj_read_from_memory);
54   opj_stream_set_skip_function(stream, opj_skip_from_memory);
55   opj_stream_set_seek_function(stream, opj_seek_from_memory);
56   return stream;
57 }
58 
alloc_rgb(size_t size)59 Optional<OpjImageRgbData> alloc_rgb(size_t size) {
60   OpjImageRgbData data;
61   data.r.reset(static_cast<int*>(opj_image_data_alloc(size)));
62   if (!data.r)
63     return {};
64 
65   data.g.reset(static_cast<int*>(opj_image_data_alloc(size)));
66   if (!data.g)
67     return {};
68 
69   data.b.reset(static_cast<int*>(opj_image_data_alloc(size)));
70   if (!data.b)
71     return {};
72 
73   return data;
74 }
75 
sycc_to_rgb(int offset,int upb,int y,int cb,int cr,int * out_r,int * out_g,int * out_b)76 void sycc_to_rgb(int offset,
77                  int upb,
78                  int y,
79                  int cb,
80                  int cr,
81                  int* out_r,
82                  int* out_g,
83                  int* out_b) {
84   cb -= offset;
85   cr -= offset;
86   *out_r = pdfium::clamp(y + static_cast<int>(1.402 * cr), 0, upb);
87   *out_g = pdfium::clamp(y - static_cast<int>(0.344 * cb + 0.714 * cr), 0, upb);
88   *out_b = pdfium::clamp(y + static_cast<int>(1.772 * cb), 0, upb);
89 }
90 
sycc444_to_rgb(opj_image_t * img)91 void sycc444_to_rgb(opj_image_t* img) {
92   int prec = img->comps[0].prec;
93   // If we shift 31 we're going to go negative, then things go bad.
94   if (prec > 30)
95     return;
96   int offset = 1 << (prec - 1);
97   int upb = (1 << prec) - 1;
98   OPJ_UINT32 maxw =
99       std::min({img->comps[0].w, img->comps[1].w, img->comps[2].w});
100   OPJ_UINT32 maxh =
101       std::min({img->comps[0].h, img->comps[1].h, img->comps[2].h});
102   FX_SAFE_SIZE_T max_size = maxw;
103   max_size *= maxh;
104   max_size *= sizeof(int);
105   if (!max_size.IsValid())
106     return;
107 
108   const int* y = img->comps[0].data;
109   const int* cb = img->comps[1].data;
110   const int* cr = img->comps[2].data;
111   if (!y || !cb || !cr)
112     return;
113 
114   Optional<OpjImageRgbData> data = alloc_rgb(max_size.ValueOrDie());
115   if (!data.has_value())
116     return;
117 
118   int* r = data.value().r.get();
119   int* g = data.value().g.get();
120   int* b = data.value().b.get();
121   max_size /= sizeof(int);
122   for (size_t i = 0; i < max_size.ValueOrDie(); ++i)
123     sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++);
124 
125   opj_image_data_free(img->comps[0].data);
126   opj_image_data_free(img->comps[1].data);
127   opj_image_data_free(img->comps[2].data);
128   img->comps[0].data = data.value().r.release();
129   img->comps[1].data = data.value().g.release();
130   img->comps[2].data = data.value().b.release();
131 }
132 
sycc420_422_size_is_valid(opj_image_t * img)133 bool sycc420_422_size_is_valid(opj_image_t* img) {
134   return img && img->comps[0].w != std::numeric_limits<OPJ_UINT32>::max() &&
135          (img->comps[0].w + 1) / 2 == img->comps[1].w &&
136          img->comps[1].w == img->comps[2].w &&
137          img->comps[1].h == img->comps[2].h;
138 }
139 
sycc420_size_is_valid(opj_image_t * img)140 bool sycc420_size_is_valid(opj_image_t* img) {
141   return sycc420_422_size_is_valid(img) &&
142          img->comps[0].h != std::numeric_limits<OPJ_UINT32>::max() &&
143          (img->comps[0].h + 1) / 2 == img->comps[1].h;
144 }
145 
sycc420_must_extend_cbcr(OPJ_UINT32 y,OPJ_UINT32 cbcr)146 bool sycc420_must_extend_cbcr(OPJ_UINT32 y, OPJ_UINT32 cbcr) {
147   return (y & 1) && (cbcr == y / 2);
148 }
149 
sycc420_to_rgb(opj_image_t * img)150 void sycc420_to_rgb(opj_image_t* img) {
151   if (!sycc420_size_is_valid(img))
152     return;
153 
154   OPJ_UINT32 prec = img->comps[0].prec;
155   if (!prec)
156     return;
157 
158   OPJ_UINT32 offset = 1 << (prec - 1);
159   OPJ_UINT32 upb = (1 << prec) - 1;
160   OPJ_UINT32 yw = img->comps[0].w;
161   OPJ_UINT32 yh = img->comps[0].h;
162   OPJ_UINT32 cbw = img->comps[1].w;
163   OPJ_UINT32 cbh = img->comps[1].h;
164   OPJ_UINT32 crw = img->comps[2].w;
165   bool extw = sycc420_must_extend_cbcr(yw, cbw);
166   bool exth = sycc420_must_extend_cbcr(yh, cbh);
167   FX_SAFE_UINT32 safe_size = yw;
168   safe_size *= yh;
169   safe_size *= sizeof(int);
170   if (!safe_size.IsValid())
171     return;
172 
173   const int* y = img->comps[0].data;
174   const int* cb = img->comps[1].data;
175   const int* cr = img->comps[2].data;
176   if (!y || !cb || !cr)
177     return;
178 
179   Optional<OpjImageRgbData> data = alloc_rgb(safe_size.ValueOrDie());
180   if (!data.has_value())
181     return;
182 
183   int* r = data.value().r.get();
184   int* g = data.value().g.get();
185   int* b = data.value().b.get();
186   const int* ny = nullptr;
187   int* nr = nullptr;
188   int* ng = nullptr;
189   int* nb = nullptr;
190   OPJ_UINT32 i = 0;
191   OPJ_UINT32 j = 0;
192   for (i = 0; i < (yh & ~(OPJ_UINT32)1); i += 2) {
193     ny = y + yw;
194     nr = r + yw;
195     ng = g + yw;
196     nb = b + yw;
197     for (j = 0; j < (yw & ~(OPJ_UINT32)1); j += 2) {
198       sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
199       ++y;
200       ++r;
201       ++g;
202       ++b;
203       sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
204       ++y;
205       ++r;
206       ++g;
207       ++b;
208       sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
209       ++ny;
210       ++nr;
211       ++ng;
212       ++nb;
213       sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
214       ++ny;
215       ++nr;
216       ++ng;
217       ++nb;
218       ++cb;
219       ++cr;
220     }
221     if (j < yw) {
222       if (extw) {
223         --cb;
224         --cr;
225       }
226       sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
227       ++y;
228       ++r;
229       ++g;
230       ++b;
231       sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
232       ++ny;
233       ++nr;
234       ++ng;
235       ++nb;
236       ++cb;
237       ++cr;
238     }
239     y += yw;
240     r += yw;
241     g += yw;
242     b += yw;
243   }
244   if (i < yh) {
245     if (exth) {
246       cb -= cbw;
247       cr -= crw;
248     }
249     for (j = 0; j < (yw & ~(OPJ_UINT32)1); j += 2) {
250       sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
251       ++y;
252       ++r;
253       ++g;
254       ++b;
255       sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
256       ++y;
257       ++r;
258       ++g;
259       ++b;
260       ++cb;
261       ++cr;
262     }
263     if (j < yw) {
264       if (extw) {
265         --cb;
266         --cr;
267       }
268       sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
269     }
270   }
271 
272   opj_image_data_free(img->comps[0].data);
273   opj_image_data_free(img->comps[1].data);
274   opj_image_data_free(img->comps[2].data);
275   img->comps[0].data = data.value().r.release();
276   img->comps[1].data = data.value().g.release();
277   img->comps[2].data = data.value().b.release();
278   img->comps[1].w = yw;
279   img->comps[1].h = yh;
280   img->comps[2].w = yw;
281   img->comps[2].h = yh;
282   img->comps[1].dx = img->comps[0].dx;
283   img->comps[2].dx = img->comps[0].dx;
284   img->comps[1].dy = img->comps[0].dy;
285   img->comps[2].dy = img->comps[0].dy;
286 }
287 
sycc422_size_is_valid(opj_image_t * img)288 bool sycc422_size_is_valid(opj_image_t* img) {
289   return sycc420_422_size_is_valid(img) && img->comps[0].h == img->comps[1].h;
290 }
291 
sycc422_to_rgb(opj_image_t * img)292 void sycc422_to_rgb(opj_image_t* img) {
293   if (!sycc422_size_is_valid(img))
294     return;
295 
296   int prec = img->comps[0].prec;
297   if (prec <= 0 || prec >= 32)
298     return;
299 
300   int offset = 1 << (prec - 1);
301   int upb = (1 << prec) - 1;
302   OPJ_UINT32 maxw = img->comps[0].w;
303   OPJ_UINT32 maxh = img->comps[0].h;
304   FX_SAFE_SIZE_T max_size = maxw;
305   max_size *= maxh;
306   max_size *= sizeof(int);
307   if (!max_size.IsValid())
308     return;
309 
310   const int* y = img->comps[0].data;
311   const int* cb = img->comps[1].data;
312   const int* cr = img->comps[2].data;
313   if (!y || !cb || !cr)
314     return;
315 
316   Optional<OpjImageRgbData> data = alloc_rgb(max_size.ValueOrDie());
317   if (!data.has_value())
318     return;
319 
320   int* r = data.value().r.get();
321   int* g = data.value().g.get();
322   int* b = data.value().b.get();
323   for (uint32_t i = 0; i < maxh; ++i) {
324     OPJ_UINT32 j;
325     for (j = 0; j < (maxw & ~static_cast<OPJ_UINT32>(1)); j += 2) {
326       sycc_to_rgb(offset, upb, *y++, *cb, *cr, r++, g++, b++);
327       sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++);
328     }
329     if (j < maxw) {
330       sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++);
331     }
332   }
333 
334   opj_image_data_free(img->comps[0].data);
335   opj_image_data_free(img->comps[1].data);
336   opj_image_data_free(img->comps[2].data);
337   img->comps[0].data = data.value().r.release();
338   img->comps[1].data = data.value().g.release();
339   img->comps[2].data = data.value().b.release();
340   img->comps[1].w = maxw;
341   img->comps[1].h = maxh;
342   img->comps[2].w = maxw;
343   img->comps[2].h = maxh;
344   img->comps[1].dx = img->comps[0].dx;
345   img->comps[2].dx = img->comps[0].dx;
346   img->comps[1].dy = img->comps[0].dy;
347   img->comps[2].dy = img->comps[0].dy;
348 }
349 
is_sycc420(const opj_image_t * img)350 bool is_sycc420(const opj_image_t* img) {
351   return img->comps[0].dx == 1 && img->comps[0].dy == 1 &&
352          img->comps[1].dx == 2 && img->comps[1].dy == 2 &&
353          img->comps[2].dx == 2 && img->comps[2].dy == 2;
354 }
355 
is_sycc422(const opj_image_t * img)356 bool is_sycc422(const opj_image_t* img) {
357   return img->comps[0].dx == 1 && img->comps[0].dy == 1 &&
358          img->comps[1].dx == 2 && img->comps[1].dy == 1 &&
359          img->comps[2].dx == 2 && img->comps[2].dy == 1;
360 }
361 
is_sycc444(const opj_image_t * img)362 bool is_sycc444(const opj_image_t* img) {
363   return img->comps[0].dx == 1 && img->comps[0].dy == 1 &&
364          img->comps[1].dx == 1 && img->comps[1].dy == 1 &&
365          img->comps[2].dx == 1 && img->comps[2].dy == 1;
366 }
367 
color_sycc_to_rgb(opj_image_t * img)368 void color_sycc_to_rgb(opj_image_t* img) {
369   if (img->numcomps < 3) {
370     img->color_space = OPJ_CLRSPC_GRAY;
371     return;
372   }
373   if (is_sycc420(img))
374     sycc420_to_rgb(img);
375   else if (is_sycc422(img))
376     sycc422_to_rgb(img);
377   else if (is_sycc444(img))
378     sycc444_to_rgb(img);
379   else
380     return;
381 
382   img->color_space = OPJ_CLRSPC_SRGB;
383 }
384 
385 }  // namespace
386 
387 // static
Sycc420ToRgbForTesting(opj_image_t * img)388 void CJPX_Decoder::Sycc420ToRgbForTesting(opj_image_t* img) {
389   sycc420_to_rgb(img);
390 }
391 
CJPX_Decoder(ColorSpaceOption option)392 CJPX_Decoder::CJPX_Decoder(ColorSpaceOption option)
393     : m_ColorSpaceOption(option) {}
394 
~CJPX_Decoder()395 CJPX_Decoder::~CJPX_Decoder() {
396   if (m_Codec)
397     opj_destroy_codec(m_Codec.Release());
398   if (m_Stream)
399     opj_stream_destroy(m_Stream.Release());
400   if (m_Image)
401     opj_image_destroy(m_Image.Release());
402 }
403 
Init(pdfium::span<const uint8_t> src_data)404 bool CJPX_Decoder::Init(pdfium::span<const uint8_t> src_data) {
405   static const unsigned char szJP2Header[] = {
406       0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a};
407   if (src_data.empty() || src_data.size() < sizeof(szJP2Header))
408     return false;
409 
410   m_Image = nullptr;
411   m_SrcData = src_data;
412   m_DecodeData =
413       pdfium::MakeUnique<DecodeData>(src_data.data(), src_data.size());
414   m_Stream = fx_opj_stream_create_memory_stream(m_DecodeData.get());
415   if (!m_Stream)
416     return false;
417 
418   opj_set_default_decoder_parameters(&m_Parameters);
419   m_Parameters.decod_format = 0;
420   m_Parameters.cod_format = 3;
421   if (memcmp(m_SrcData.data(), szJP2Header, sizeof(szJP2Header)) == 0) {
422     m_Codec = opj_create_decompress(OPJ_CODEC_JP2);
423     m_Parameters.decod_format = 1;
424   } else {
425     m_Codec = opj_create_decompress(OPJ_CODEC_J2K);
426   }
427   if (!m_Codec)
428     return false;
429 
430   if (m_ColorSpaceOption == kIndexedColorSpace)
431     m_Parameters.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
432   opj_set_info_handler(m_Codec.Get(), fx_ignore_callback, nullptr);
433   opj_set_warning_handler(m_Codec.Get(), fx_ignore_callback, nullptr);
434   opj_set_error_handler(m_Codec.Get(), fx_ignore_callback, nullptr);
435   if (!opj_setup_decoder(m_Codec.Get(), &m_Parameters))
436     return false;
437 
438   m_Image = nullptr;
439   opj_image_t* pTempImage = nullptr;
440   if (!opj_read_header(m_Stream.Get(), m_Codec.Get(), &pTempImage))
441     return false;
442 
443   m_Image = pTempImage;
444   return true;
445 }
446 
StartDecode()447 bool CJPX_Decoder::StartDecode() {
448   if (!m_Parameters.nb_tile_to_decode) {
449     if (!opj_set_decode_area(m_Codec.Get(), m_Image.Get(), m_Parameters.DA_x0,
450                              m_Parameters.DA_y0, m_Parameters.DA_x1,
451                              m_Parameters.DA_y1)) {
452       opj_image_destroy(m_Image.Release());
453       return false;
454     }
455     if (!(opj_decode(m_Codec.Get(), m_Stream.Get(), m_Image.Get()) &&
456           opj_end_decompress(m_Codec.Get(), m_Stream.Get()))) {
457       opj_image_destroy(m_Image.Release());
458       return false;
459     }
460   } else if (!opj_get_decoded_tile(m_Codec.Get(), m_Stream.Get(), m_Image.Get(),
461                                    m_Parameters.tile_index)) {
462     return false;
463   }
464 
465   opj_stream_destroy(m_Stream.Release());
466   if (m_Image->color_space != OPJ_CLRSPC_SYCC && m_Image->numcomps == 3 &&
467       m_Image->comps[0].dx == m_Image->comps[0].dy &&
468       m_Image->comps[1].dx != 1) {
469     m_Image->color_space = OPJ_CLRSPC_SYCC;
470   } else if (m_Image->numcomps <= 2) {
471     m_Image->color_space = OPJ_CLRSPC_GRAY;
472   }
473   if (m_Image->color_space == OPJ_CLRSPC_SYCC)
474     color_sycc_to_rgb(m_Image.Get());
475 
476   if (m_Image->icc_profile_buf) {
477     // TODO(palmer): Using |opj_free| here resolves the crash described in
478     // https://crbug.com/737033, but ultimately we need to harmonize the
479     // memory allocation strategy across OpenJPEG and its PDFium callers.
480 #if !defined(USE_SYSTEM_LIBOPENJPEG2)
481     opj_free(m_Image->icc_profile_buf);
482 #else
483     free(m_Image->icc_profile_buf);
484 #endif
485     m_Image->icc_profile_buf = nullptr;
486     m_Image->icc_profile_len = 0;
487   }
488   return true;
489 }
490 
GetInfo() const491 CJPX_Decoder::JpxImageInfo CJPX_Decoder::GetInfo() const {
492   return {m_Image->x1, m_Image->y1, m_Image->numcomps, m_Image->color_space};
493 }
494 
Decode(uint8_t * dest_buf,uint32_t pitch,bool swap_rgb)495 bool CJPX_Decoder::Decode(uint8_t* dest_buf, uint32_t pitch, bool swap_rgb) {
496   if (m_Image->comps[0].w != m_Image->x1 || m_Image->comps[0].h != m_Image->y1)
497     return false;
498 
499   if (pitch<(m_Image->comps[0].w * 8 * m_Image->numcomps + 31)>> 5 << 2)
500     return false;
501 
502   if (swap_rgb && m_Image->numcomps < 3)
503     return false;
504 
505   memset(dest_buf, 0xff, m_Image->y1 * pitch);
506   std::vector<uint8_t*> channel_bufs(m_Image->numcomps);
507   std::vector<int> adjust_comps(m_Image->numcomps);
508   for (uint32_t i = 0; i < m_Image->numcomps; i++) {
509     channel_bufs[i] = dest_buf + i;
510     adjust_comps[i] = m_Image->comps[i].prec - 8;
511     if (i > 0) {
512       if (m_Image->comps[i].dx != m_Image->comps[i - 1].dx ||
513           m_Image->comps[i].dy != m_Image->comps[i - 1].dy ||
514           m_Image->comps[i].prec != m_Image->comps[i - 1].prec) {
515         return false;
516       }
517     }
518   }
519   if (swap_rgb)
520     std::swap(channel_bufs[0], channel_bufs[2]);
521 
522   uint32_t width = m_Image->comps[0].w;
523   uint32_t height = m_Image->comps[0].h;
524   for (uint32_t channel = 0; channel < m_Image->numcomps; ++channel) {
525     uint8_t* pChannel = channel_bufs[channel];
526     if (adjust_comps[channel] < 0) {
527       for (uint32_t row = 0; row < height; ++row) {
528         uint8_t* pScanline = pChannel + row * pitch;
529         for (uint32_t col = 0; col < width; ++col) {
530           uint8_t* pPixel = pScanline + col * m_Image->numcomps;
531           if (!m_Image->comps[channel].data)
532             continue;
533 
534           int src = m_Image->comps[channel].data[row * width + col];
535           src += m_Image->comps[channel].sgnd
536                      ? 1 << (m_Image->comps[channel].prec - 1)
537                      : 0;
538           if (adjust_comps[channel] > 0) {
539             *pPixel = 0;
540           } else {
541             *pPixel = static_cast<uint8_t>(src << -adjust_comps[channel]);
542           }
543         }
544       }
545     } else {
546       for (uint32_t row = 0; row < height; ++row) {
547         uint8_t* pScanline = pChannel + row * pitch;
548         for (uint32_t col = 0; col < width; ++col) {
549           uint8_t* pPixel = pScanline + col * m_Image->numcomps;
550           if (!m_Image->comps[channel].data)
551             continue;
552 
553           int src = m_Image->comps[channel].data[row * width + col];
554           src += m_Image->comps[channel].sgnd
555                      ? 1 << (m_Image->comps[channel].prec - 1)
556                      : 0;
557           if (adjust_comps[channel] - 1 < 0) {
558             *pPixel = static_cast<uint8_t>((src >> adjust_comps[channel]));
559           } else {
560             int tmpPixel = (src >> adjust_comps[channel]) +
561                            ((src >> (adjust_comps[channel] - 1)) % 2);
562             tmpPixel = pdfium::clamp(tmpPixel, 0, 255);
563             *pPixel = static_cast<uint8_t>(tmpPixel);
564           }
565         }
566       }
567     }
568   }
569   return true;
570 }
571 
572 }  // namespace fxcodec
573