OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/include/fxcodec/fx_codec.h" | |
8 | |
9 #include <cmath> | |
10 #include <utility> | |
11 | |
12 #include "core/include/fxcrt/fx_ext.h" | |
13 #include "core/include/fxcrt/fx_safe_types.h" | |
14 #include "core/src/fxcodec/codec/codec_int.h" | |
15 #include "third_party/base/logging.h" | |
16 | |
17 CCodec_ModuleMgr::CCodec_ModuleMgr() | |
18 : m_pBasicModule(new CCodec_BasicModule), | |
19 m_pFaxModule(new CCodec_FaxModule), | |
20 m_pJpegModule(new CCodec_JpegModule), | |
21 m_pJpxModule(new CCodec_JpxModule), | |
22 m_pJbig2Module(new CCodec_Jbig2Module), | |
23 m_pIccModule(new CCodec_IccModule), | |
24 #ifdef PDF_ENABLE_XFA | |
25 m_pPngModule(new CCodec_PngModule), | |
26 m_pGifModule(new CCodec_GifModule), | |
27 m_pBmpModule(new CCodec_BmpModule), | |
28 m_pTiffModule(new CCodec_TiffModule), | |
29 #endif // PDF_ENABLE_XFA | |
30 m_pFlateModule(new CCodec_FlateModule) { | |
31 } | |
32 | |
33 CCodec_ScanlineDecoder::ImageDataCache::ImageDataCache(int width, | |
34 int height, | |
35 FX_DWORD pitch) | |
36 : m_Width(width), m_Height(height), m_Pitch(pitch), m_nCachedLines(0) {} | |
37 | |
38 CCodec_ScanlineDecoder::ImageDataCache::~ImageDataCache() { | |
39 } | |
40 | |
41 bool CCodec_ScanlineDecoder::ImageDataCache::AllocateCache() { | |
42 if (m_Pitch == 0 || m_Height < 0) | |
43 return false; | |
44 | |
45 FX_SAFE_SIZE_T size = m_Pitch; | |
46 size *= m_Height; | |
47 if (!size.IsValid()) | |
48 return false; | |
49 | |
50 m_Data.reset(FX_TryAlloc(uint8_t, size.ValueOrDie())); | |
51 return IsValid(); | |
52 } | |
53 | |
54 void CCodec_ScanlineDecoder::ImageDataCache::AppendLine(const uint8_t* line) { | |
55 // If the callers adds more lines than there is room, fail. | |
56 if (m_Pitch == 0 || m_nCachedLines >= m_Height) { | |
57 NOTREACHED(); | |
58 return; | |
59 } | |
60 | |
61 size_t offset = m_Pitch; | |
62 FXSYS_memcpy(m_Data.get() + offset * m_nCachedLines, line, m_Pitch); | |
63 ++m_nCachedLines; | |
64 } | |
65 | |
66 const uint8_t* CCodec_ScanlineDecoder::ImageDataCache::GetLine(int line) const { | |
67 if (m_Pitch == 0 || line < 0 || line >= m_nCachedLines) | |
68 return nullptr; | |
69 | |
70 size_t offset = m_Pitch; | |
71 return m_Data.get() + offset * line; | |
72 } | |
73 | |
74 CCodec_ScanlineDecoder::CCodec_ScanlineDecoder() | |
75 : m_NextLine(-1), m_pLastScanline(nullptr) { | |
76 } | |
77 | |
78 CCodec_ScanlineDecoder::~CCodec_ScanlineDecoder() { | |
79 } | |
80 | |
81 const uint8_t* CCodec_ScanlineDecoder::GetScanline(int line) { | |
82 if (m_pDataCache && line < m_pDataCache->NumLines()) | |
83 return m_pDataCache->GetLine(line); | |
84 | |
85 if (m_NextLine == line + 1) | |
86 return m_pLastScanline; | |
87 | |
88 if (m_NextLine < 0 || m_NextLine > line) { | |
89 if (!v_Rewind()) | |
90 return nullptr; | |
91 m_NextLine = 0; | |
92 } | |
93 while (m_NextLine < line) { | |
94 ReadNextLine(); | |
95 m_NextLine++; | |
96 } | |
97 m_pLastScanline = ReadNextLine(); | |
98 m_NextLine++; | |
99 return m_pLastScanline; | |
100 } | |
101 | |
102 FX_BOOL CCodec_ScanlineDecoder::SkipToScanline(int line, IFX_Pause* pPause) { | |
103 if (m_pDataCache && line < m_pDataCache->NumLines()) | |
104 return FALSE; | |
105 | |
106 if (m_NextLine == line || m_NextLine == line + 1) | |
107 return FALSE; | |
108 | |
109 if (m_NextLine < 0 || m_NextLine > line) { | |
110 v_Rewind(); | |
111 m_NextLine = 0; | |
112 } | |
113 m_pLastScanline = nullptr; | |
114 while (m_NextLine < line) { | |
115 m_pLastScanline = ReadNextLine(); | |
116 m_NextLine++; | |
117 if (pPause && pPause->NeedToPauseNow()) { | |
118 return TRUE; | |
119 } | |
120 } | |
121 return FALSE; | |
122 } | |
123 | |
124 uint8_t* CCodec_ScanlineDecoder::ReadNextLine() { | |
125 uint8_t* pLine = v_GetNextLine(); | |
126 if (!pLine) | |
127 return nullptr; | |
128 | |
129 if (m_pDataCache && m_NextLine == m_pDataCache->NumLines()) | |
130 m_pDataCache->AppendLine(pLine); | |
131 return pLine; | |
132 } | |
133 | |
134 void CCodec_ScanlineDecoder::DownScale(int dest_width, int dest_height) { | |
135 dest_width = std::abs(dest_width); | |
136 dest_height = std::abs(dest_height); | |
137 v_DownScale(dest_width, dest_height); | |
138 | |
139 if (m_pDataCache && | |
140 m_pDataCache->IsSameDimensions(m_OutputWidth, m_OutputHeight)) { | |
141 return; | |
142 } | |
143 | |
144 std::unique_ptr<ImageDataCache> cache( | |
145 new ImageDataCache(m_OutputWidth, m_OutputHeight, m_Pitch)); | |
146 if (!cache->AllocateCache()) | |
147 return; | |
148 | |
149 m_pDataCache = std::move(cache); | |
150 } | |
151 | |
152 FX_BOOL CCodec_BasicModule::RunLengthEncode(const uint8_t* src_buf, | |
153 FX_DWORD src_size, | |
154 uint8_t*& dest_buf, | |
155 FX_DWORD& dest_size) { | |
156 return FALSE; | |
157 } | |
158 | |
159 #define EXPONENT_DETECT(ptr) \ | |
160 for (;; ptr++) { \ | |
161 if (!std::isdigit(*ptr)) { \ | |
162 if (endptr) \ | |
163 *endptr = (char*)ptr; \ | |
164 break; \ | |
165 } else { \ | |
166 exp_ret *= 10; \ | |
167 exp_ret += FXSYS_toDecimalDigit(*ptr); \ | |
168 continue; \ | |
169 } \ | |
170 } | |
171 | |
172 extern "C" double FXstrtod(const char* nptr, char** endptr) { | |
173 double ret = 0.0; | |
174 const char* ptr = nptr; | |
175 const char* exp_ptr = NULL; | |
176 int e_number = 0, e_signal = 0, e_point = 0, is_negative = 0; | |
177 int exp_ret = 0, exp_sig = 1, fra_ret = 0, fra_count = 0, fra_base = 1; | |
178 if (!nptr) { | |
179 return 0.0; | |
180 } | |
181 for (;; ptr++) { | |
182 if (!e_number && !e_point && (*ptr == '\t' || *ptr == ' ')) | |
183 continue; | |
184 | |
185 if (std::isdigit(*ptr)) { | |
186 if (!e_number) | |
187 e_number = 1; | |
188 | |
189 if (!e_point) { | |
190 ret *= 10; | |
191 ret += FXSYS_toDecimalDigit(*ptr); | |
192 } else { | |
193 fra_count++; | |
194 fra_ret *= 10; | |
195 fra_ret += FXSYS_toDecimalDigit(*ptr); | |
196 } | |
197 continue; | |
198 } | |
199 if (!e_point && *ptr == '.') { | |
200 e_point = 1; | |
201 continue; | |
202 } | |
203 if (!e_number && !e_point && !e_signal) { | |
204 switch (*ptr) { | |
205 case '-': | |
206 is_negative = 1; | |
207 case '+': | |
208 e_signal = 1; | |
209 continue; | |
210 } | |
211 } | |
212 if (e_number && (*ptr == 'e' || *ptr == 'E')) { | |
213 exp_ptr = ptr++; | |
214 if (*ptr == '+' || *ptr == '-') { | |
215 exp_sig = (*ptr++ == '+') ? 1 : -1; | |
216 if (!std::isdigit(*ptr)) { | |
217 if (endptr) { | |
218 *endptr = (char*)exp_ptr; | |
219 } | |
220 break; | |
221 } | |
222 EXPONENT_DETECT(ptr); | |
223 } else if (std::isdigit(*ptr)) { | |
224 EXPONENT_DETECT(ptr); | |
225 } else { | |
226 if (endptr) { | |
227 *endptr = (char*)exp_ptr; | |
228 } | |
229 break; | |
230 } | |
231 break; | |
232 } | |
233 if (ptr != nptr && !e_number) { | |
234 if (endptr) { | |
235 *endptr = (char*)nptr; | |
236 } | |
237 break; | |
238 } | |
239 if (endptr) { | |
240 *endptr = (char*)ptr; | |
241 } | |
242 break; | |
243 } | |
244 while (fra_count--) { | |
245 fra_base *= 10; | |
246 } | |
247 ret += (double)fra_ret / (double)fra_base; | |
248 if (exp_sig == 1) { | |
249 while (exp_ret--) { | |
250 ret *= 10.0; | |
251 } | |
252 } else { | |
253 while (exp_ret--) { | |
254 ret /= 10.0; | |
255 } | |
256 } | |
257 return is_negative ? -ret : ret; | |
258 } | |
259 #undef EXPONENT_DETECT | |
260 | |
261 FX_BOOL CCodec_BasicModule::A85Encode(const uint8_t* src_buf, | |
262 FX_DWORD src_size, | |
263 uint8_t*& dest_buf, | |
264 FX_DWORD& dest_size) { | |
265 return FALSE; | |
266 } | |
267 | |
268 #ifdef PDF_ENABLE_XFA | |
269 CFX_DIBAttribute::CFX_DIBAttribute() | |
270 : m_nXDPI(-1), | |
271 m_nYDPI(-1), | |
272 m_fAspectRatio(-1.0f), | |
273 m_wDPIUnit(0), | |
274 m_nGifLeft(0), | |
275 m_nGifTop(0), | |
276 m_pGifLocalPalette(nullptr), | |
277 m_nGifLocalPalNum(0), | |
278 m_nBmpCompressType(0) { | |
279 FXSYS_memset(m_strTime, 0, sizeof(m_strTime)); | |
280 } | |
281 CFX_DIBAttribute::~CFX_DIBAttribute() { | |
282 for (const auto& pair : m_Exif) | |
283 FX_Free(pair.second); | |
284 } | |
285 #endif // PDF_ENABLE_XFA | |
286 | |
287 class CCodec_RLScanlineDecoder : public CCodec_ScanlineDecoder { | |
288 public: | |
289 CCodec_RLScanlineDecoder(); | |
290 ~CCodec_RLScanlineDecoder() override; | |
291 | |
292 FX_BOOL Create(const uint8_t* src_buf, | |
293 FX_DWORD src_size, | |
294 int width, | |
295 int height, | |
296 int nComps, | |
297 int bpc); | |
298 | |
299 // CCodec_ScanlineDecoder | |
300 void v_DownScale(int dest_width, int dest_height) override {} | |
301 FX_BOOL v_Rewind() override; | |
302 uint8_t* v_GetNextLine() override; | |
303 FX_DWORD GetSrcOffset() override { return m_SrcOffset; } | |
304 | |
305 protected: | |
306 FX_BOOL CheckDestSize(); | |
307 void GetNextOperator(); | |
308 void UpdateOperator(uint8_t used_bytes); | |
309 | |
310 uint8_t* m_pScanline; | |
311 const uint8_t* m_pSrcBuf; | |
312 FX_DWORD m_SrcSize; | |
313 FX_DWORD m_dwLineBytes; | |
314 FX_DWORD m_SrcOffset; | |
315 FX_BOOL m_bEOD; | |
316 uint8_t m_Operator; | |
317 }; | |
318 CCodec_RLScanlineDecoder::CCodec_RLScanlineDecoder() | |
319 : m_pScanline(NULL), | |
320 m_pSrcBuf(NULL), | |
321 m_SrcSize(0), | |
322 m_dwLineBytes(0), | |
323 m_SrcOffset(0), | |
324 m_bEOD(FALSE), | |
325 m_Operator(0) {} | |
326 CCodec_RLScanlineDecoder::~CCodec_RLScanlineDecoder() { | |
327 FX_Free(m_pScanline); | |
328 } | |
329 FX_BOOL CCodec_RLScanlineDecoder::CheckDestSize() { | |
330 FX_DWORD i = 0; | |
331 FX_DWORD old_size = 0; | |
332 FX_DWORD dest_size = 0; | |
333 while (i < m_SrcSize) { | |
334 if (m_pSrcBuf[i] < 128) { | |
335 old_size = dest_size; | |
336 dest_size += m_pSrcBuf[i] + 1; | |
337 if (dest_size < old_size) { | |
338 return FALSE; | |
339 } | |
340 i += m_pSrcBuf[i] + 2; | |
341 } else if (m_pSrcBuf[i] > 128) { | |
342 old_size = dest_size; | |
343 dest_size += 257 - m_pSrcBuf[i]; | |
344 if (dest_size < old_size) { | |
345 return FALSE; | |
346 } | |
347 i += 2; | |
348 } else { | |
349 break; | |
350 } | |
351 } | |
352 if (((FX_DWORD)m_OrigWidth * m_nComps * m_bpc * m_OrigHeight + 7) / 8 > | |
353 dest_size) { | |
354 return FALSE; | |
355 } | |
356 return TRUE; | |
357 } | |
358 FX_BOOL CCodec_RLScanlineDecoder::Create(const uint8_t* src_buf, | |
359 FX_DWORD src_size, | |
360 int width, | |
361 int height, | |
362 int nComps, | |
363 int bpc) { | |
364 m_pSrcBuf = src_buf; | |
365 m_SrcSize = src_size; | |
366 m_OutputWidth = m_OrigWidth = width; | |
367 m_OutputHeight = m_OrigHeight = height; | |
368 m_nComps = nComps; | |
369 m_bpc = bpc; | |
370 m_bColorTransformed = FALSE; | |
371 m_DownScale = 1; | |
372 // Aligning the pitch to 4 bytes requires an integer overflow check. | |
373 FX_SAFE_DWORD pitch = width; | |
374 pitch *= nComps; | |
375 pitch *= bpc; | |
376 pitch += 31; | |
377 pitch /= 32; | |
378 pitch *= 4; | |
379 if (!pitch.IsValid()) { | |
380 return FALSE; | |
381 } | |
382 m_Pitch = pitch.ValueOrDie(); | |
383 // Overflow should already have been checked before this is called. | |
384 m_dwLineBytes = (static_cast<FX_DWORD>(width) * nComps * bpc + 7) / 8; | |
385 m_pScanline = FX_Alloc(uint8_t, m_Pitch); | |
386 return CheckDestSize(); | |
387 } | |
388 FX_BOOL CCodec_RLScanlineDecoder::v_Rewind() { | |
389 FXSYS_memset(m_pScanline, 0, m_Pitch); | |
390 m_SrcOffset = 0; | |
391 m_bEOD = FALSE; | |
392 m_Operator = 0; | |
393 return TRUE; | |
394 } | |
395 uint8_t* CCodec_RLScanlineDecoder::v_GetNextLine() { | |
396 if (m_SrcOffset == 0) { | |
397 GetNextOperator(); | |
398 } else { | |
399 if (m_bEOD) { | |
400 return NULL; | |
401 } | |
402 } | |
403 FXSYS_memset(m_pScanline, 0, m_Pitch); | |
404 FX_DWORD col_pos = 0; | |
405 FX_BOOL eol = FALSE; | |
406 while (m_SrcOffset < m_SrcSize && !eol) { | |
407 if (m_Operator < 128) { | |
408 FX_DWORD copy_len = m_Operator + 1; | |
409 if (col_pos + copy_len >= m_dwLineBytes) { | |
410 copy_len = m_dwLineBytes - col_pos; | |
411 eol = TRUE; | |
412 } | |
413 if (copy_len >= m_SrcSize - m_SrcOffset) { | |
414 copy_len = m_SrcSize - m_SrcOffset; | |
415 m_bEOD = TRUE; | |
416 } | |
417 FXSYS_memcpy(m_pScanline + col_pos, m_pSrcBuf + m_SrcOffset, copy_len); | |
418 col_pos += copy_len; | |
419 UpdateOperator((uint8_t)copy_len); | |
420 } else if (m_Operator > 128) { | |
421 int fill = 0; | |
422 if (m_SrcOffset - 1 < m_SrcSize - 1) { | |
423 fill = m_pSrcBuf[m_SrcOffset]; | |
424 } | |
425 FX_DWORD duplicate_len = 257 - m_Operator; | |
426 if (col_pos + duplicate_len >= m_dwLineBytes) { | |
427 duplicate_len = m_dwLineBytes - col_pos; | |
428 eol = TRUE; | |
429 } | |
430 FXSYS_memset(m_pScanline + col_pos, fill, duplicate_len); | |
431 col_pos += duplicate_len; | |
432 UpdateOperator((uint8_t)duplicate_len); | |
433 } else { | |
434 m_bEOD = TRUE; | |
435 break; | |
436 } | |
437 } | |
438 return m_pScanline; | |
439 } | |
440 void CCodec_RLScanlineDecoder::GetNextOperator() { | |
441 if (m_SrcOffset >= m_SrcSize) { | |
442 m_Operator = 128; | |
443 return; | |
444 } | |
445 m_Operator = m_pSrcBuf[m_SrcOffset]; | |
446 m_SrcOffset++; | |
447 } | |
448 void CCodec_RLScanlineDecoder::UpdateOperator(uint8_t used_bytes) { | |
449 if (used_bytes == 0) { | |
450 return; | |
451 } | |
452 if (m_Operator < 128) { | |
453 FXSYS_assert((FX_DWORD)m_Operator + 1 >= used_bytes); | |
454 if (used_bytes == m_Operator + 1) { | |
455 m_SrcOffset += used_bytes; | |
456 GetNextOperator(); | |
457 return; | |
458 } | |
459 m_Operator -= used_bytes; | |
460 m_SrcOffset += used_bytes; | |
461 if (m_SrcOffset >= m_SrcSize) { | |
462 m_Operator = 128; | |
463 } | |
464 return; | |
465 } | |
466 uint8_t count = 257 - m_Operator; | |
467 FXSYS_assert((FX_DWORD)count >= used_bytes); | |
468 if (used_bytes == count) { | |
469 m_SrcOffset++; | |
470 GetNextOperator(); | |
471 return; | |
472 } | |
473 count -= used_bytes; | |
474 m_Operator = 257 - count; | |
475 } | |
476 ICodec_ScanlineDecoder* CCodec_BasicModule::CreateRunLengthDecoder( | |
477 const uint8_t* src_buf, | |
478 FX_DWORD src_size, | |
479 int width, | |
480 int height, | |
481 int nComps, | |
482 int bpc) { | |
483 CCodec_RLScanlineDecoder* pRLScanlineDecoder = new CCodec_RLScanlineDecoder; | |
484 if (!pRLScanlineDecoder->Create(src_buf, src_size, width, height, nComps, | |
485 bpc)) { | |
486 delete pRLScanlineDecoder; | |
487 return NULL; | |
488 } | |
489 return pRLScanlineDecoder; | |
490 } | |
OLD | NEW |