ReactOS 0.4.16-dev-2646-g1219156
pngwtran.c
Go to the documentation of this file.
1/* pngwtran.c - transforms the data in a row for PNG writers
2 *
3 * Copyright (c) 2018 Cosmin Truta
4 * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
5 * Copyright (c) 1996-1997 Andreas Dilger
6 * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
7 *
8 * This code is released under the libpng license.
9 * For conditions of distribution and use, see the disclaimer
10 * and license in png.h
11 */
12
13#include "pngpriv.h"
14
15#ifdef PNG_WRITE_SUPPORTED
16#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
17
18#ifdef PNG_WRITE_PACK_SUPPORTED
19/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
20 * row_info bit depth should be 8 (one pixel per byte). The channels
21 * should be 1 (this only happens on grayscale and paletted images).
22 */
23static void
24png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
25{
26 png_debug(1, "in png_do_pack");
27
28 if (row_info->bit_depth == 8 &&
29 row_info->channels == 1)
30 {
31 switch ((int)bit_depth)
32 {
33 case 1:
34 {
35 png_bytep sp, dp;
36 int mask, v;
38 png_uint_32 row_width = row_info->width;
39
40 sp = row;
41 dp = row;
42 mask = 0x80;
43 v = 0;
44
45 for (i = 0; i < row_width; i++)
46 {
47 if (*sp != 0)
48 v |= mask;
49
50 sp++;
51
52 if (mask > 1)
53 mask >>= 1;
54
55 else
56 {
57 mask = 0x80;
58 *dp = (png_byte)v;
59 dp++;
60 v = 0;
61 }
62 }
63
64 if (mask != 0x80)
65 *dp = (png_byte)v;
66
67 break;
68 }
69
70 case 2:
71 {
72 png_bytep sp, dp;
73 unsigned int shift;
74 int v;
76 png_uint_32 row_width = row_info->width;
77
78 sp = row;
79 dp = row;
80 shift = 6;
81 v = 0;
82
83 for (i = 0; i < row_width; i++)
84 {
85 png_byte value;
86
87 value = (png_byte)(*sp & 0x03);
88 v |= (value << shift);
89
90 if (shift == 0)
91 {
92 shift = 6;
93 *dp = (png_byte)v;
94 dp++;
95 v = 0;
96 }
97
98 else
99 shift -= 2;
100
101 sp++;
102 }
103
104 if (shift != 6)
105 *dp = (png_byte)v;
106
107 break;
108 }
109
110 case 4:
111 {
112 png_bytep sp, dp;
113 unsigned int shift;
114 int v;
116 png_uint_32 row_width = row_info->width;
117
118 sp = row;
119 dp = row;
120 shift = 4;
121 v = 0;
122
123 for (i = 0; i < row_width; i++)
124 {
125 png_byte value;
126
127 value = (png_byte)(*sp & 0x0f);
128 v |= (value << shift);
129
130 if (shift == 0)
131 {
132 shift = 4;
133 *dp = (png_byte)v;
134 dp++;
135 v = 0;
136 }
137
138 else
139 shift -= 4;
140
141 sp++;
142 }
143
144 if (shift != 4)
145 *dp = (png_byte)v;
146
147 break;
148 }
149
150 default:
151 break;
152 }
153
154 row_info->bit_depth = (png_byte)bit_depth;
155 row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
156 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
157 row_info->width);
158 }
159}
160#endif
161
162#ifdef PNG_WRITE_SHIFT_SUPPORTED
163/* Shift pixel values to take advantage of whole range. Pass the
164 * true number of bits in bit_depth. The row should be packed
165 * according to row_info->bit_depth. Thus, if you had a row of
166 * bit depth 4, but the pixels only had values from 0 to 7, you
167 * would pass 3 as bit_depth, and this routine would translate the
168 * data to 0 to 15.
169 */
170static void
171png_do_shift(png_row_infop row_info, png_bytep row,
172 png_const_color_8p bit_depth)
173{
174 png_debug(1, "in png_do_shift");
175
176 if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)
177 {
178 int shift_start[4], shift_dec[4];
179 unsigned int channels = 0;
180
181 if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
182 {
183 shift_start[channels] = row_info->bit_depth - bit_depth->red;
184 shift_dec[channels] = bit_depth->red;
185 channels++;
186
187 shift_start[channels] = row_info->bit_depth - bit_depth->green;
188 shift_dec[channels] = bit_depth->green;
189 channels++;
190
191 shift_start[channels] = row_info->bit_depth - bit_depth->blue;
192 shift_dec[channels] = bit_depth->blue;
193 channels++;
194 }
195
196 else
197 {
198 shift_start[channels] = row_info->bit_depth - bit_depth->gray;
199 shift_dec[channels] = bit_depth->gray;
200 channels++;
201 }
202
203 if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
204 {
205 shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
206 shift_dec[channels] = bit_depth->alpha;
207 channels++;
208 }
209
210 /* With low row depths, could only be grayscale, so one channel */
211 if (row_info->bit_depth < 8)
212 {
213 png_bytep bp = row;
214 size_t i;
215 unsigned int mask;
216 size_t row_bytes = row_info->rowbytes;
217
218 if (bit_depth->gray == 1 && row_info->bit_depth == 2)
219 mask = 0x55;
220
221 else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
222 mask = 0x11;
223
224 else
225 mask = 0xff;
226
227 for (i = 0; i < row_bytes; i++, bp++)
228 {
229 int j;
230 unsigned int v, out;
231
232 v = *bp;
233 out = 0;
234
235 for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
236 {
237 if (j > 0)
238 out |= v << j;
239
240 else
241 out |= (v >> (-j)) & mask;
242 }
243
244 *bp = (png_byte)(out & 0xff);
245 }
246 }
247
248 else if (row_info->bit_depth == 8)
249 {
250 png_bytep bp = row;
252 png_uint_32 istop = channels * row_info->width;
253
254 for (i = 0; i < istop; i++, bp++)
255 {
256 unsigned int c = i%channels;
257 int j;
258 unsigned int v, out;
259
260 v = *bp;
261 out = 0;
262
263 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
264 {
265 if (j > 0)
266 out |= v << j;
267
268 else
269 out |= v >> (-j);
270 }
271
272 *bp = (png_byte)(out & 0xff);
273 }
274 }
275
276 else
277 {
278 png_bytep bp;
280 png_uint_32 istop = channels * row_info->width;
281
282 for (bp = row, i = 0; i < istop; i++)
283 {
284 unsigned int c = i%channels;
285 int j;
286 unsigned int value, v;
287
288 v = png_get_uint_16(bp);
289 value = 0;
290
291 for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
292 {
293 if (j > 0)
294 value |= v << j;
295
296 else
297 value |= v >> (-j);
298 }
299 *bp++ = (png_byte)((value >> 8) & 0xff);
300 *bp++ = (png_byte)(value & 0xff);
301 }
302 }
303 }
304}
305#endif
306
307#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
308static void
309png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
310{
311 png_debug(1, "in png_do_write_swap_alpha");
312
313 {
314 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
315 {
316 if (row_info->bit_depth == 8)
317 {
318 /* This converts from ARGB to RGBA */
319 png_bytep sp, dp;
321 png_uint_32 row_width = row_info->width;
322
323 for (i = 0, sp = dp = row; i < row_width; i++)
324 {
325 png_byte save = *(sp++);
326 *(dp++) = *(sp++);
327 *(dp++) = *(sp++);
328 *(dp++) = *(sp++);
329 *(dp++) = save;
330 }
331 }
332
333#ifdef PNG_WRITE_16BIT_SUPPORTED
334 else
335 {
336 /* This converts from AARRGGBB to RRGGBBAA */
337 png_bytep sp, dp;
339 png_uint_32 row_width = row_info->width;
340
341 for (i = 0, sp = dp = row; i < row_width; i++)
342 {
343 png_byte save[2];
344 save[0] = *(sp++);
345 save[1] = *(sp++);
346 *(dp++) = *(sp++);
347 *(dp++) = *(sp++);
348 *(dp++) = *(sp++);
349 *(dp++) = *(sp++);
350 *(dp++) = *(sp++);
351 *(dp++) = *(sp++);
352 *(dp++) = save[0];
353 *(dp++) = save[1];
354 }
355 }
356#endif /* WRITE_16BIT */
357 }
358
359 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
360 {
361 if (row_info->bit_depth == 8)
362 {
363 /* This converts from AG to GA */
364 png_bytep sp, dp;
366 png_uint_32 row_width = row_info->width;
367
368 for (i = 0, sp = dp = row; i < row_width; i++)
369 {
370 png_byte save = *(sp++);
371 *(dp++) = *(sp++);
372 *(dp++) = save;
373 }
374 }
375
376#ifdef PNG_WRITE_16BIT_SUPPORTED
377 else
378 {
379 /* This converts from AAGG to GGAA */
380 png_bytep sp, dp;
382 png_uint_32 row_width = row_info->width;
383
384 for (i = 0, sp = dp = row; i < row_width; i++)
385 {
386 png_byte save[2];
387 save[0] = *(sp++);
388 save[1] = *(sp++);
389 *(dp++) = *(sp++);
390 *(dp++) = *(sp++);
391 *(dp++) = save[0];
392 *(dp++) = save[1];
393 }
394 }
395#endif /* WRITE_16BIT */
396 }
397 }
398}
399#endif
400
401#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
402static void
403png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
404{
405 png_debug(1, "in png_do_write_invert_alpha");
406
407 {
408 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
409 {
410 if (row_info->bit_depth == 8)
411 {
412 /* This inverts the alpha channel in RGBA */
413 png_bytep sp, dp;
415 png_uint_32 row_width = row_info->width;
416
417 for (i = 0, sp = dp = row; i < row_width; i++)
418 {
419 /* Does nothing
420 *(dp++) = *(sp++);
421 *(dp++) = *(sp++);
422 *(dp++) = *(sp++);
423 */
424 sp+=3; dp = sp;
425 *dp = (png_byte)(255 - *(sp++));
426 }
427 }
428
429#ifdef PNG_WRITE_16BIT_SUPPORTED
430 else
431 {
432 /* This inverts the alpha channel in RRGGBBAA */
433 png_bytep sp, dp;
435 png_uint_32 row_width = row_info->width;
436
437 for (i = 0, sp = dp = row; i < row_width; i++)
438 {
439 /* Does nothing
440 *(dp++) = *(sp++);
441 *(dp++) = *(sp++);
442 *(dp++) = *(sp++);
443 *(dp++) = *(sp++);
444 *(dp++) = *(sp++);
445 *(dp++) = *(sp++);
446 */
447 sp+=6; dp = sp;
448 *(dp++) = (png_byte)(255 - *(sp++));
449 *dp = (png_byte)(255 - *(sp++));
450 }
451 }
452#endif /* WRITE_16BIT */
453 }
454
455 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
456 {
457 if (row_info->bit_depth == 8)
458 {
459 /* This inverts the alpha channel in GA */
460 png_bytep sp, dp;
462 png_uint_32 row_width = row_info->width;
463
464 for (i = 0, sp = dp = row; i < row_width; i++)
465 {
466 *(dp++) = *(sp++);
467 *(dp++) = (png_byte)(255 - *(sp++));
468 }
469 }
470
471#ifdef PNG_WRITE_16BIT_SUPPORTED
472 else
473 {
474 /* This inverts the alpha channel in GGAA */
475 png_bytep sp, dp;
477 png_uint_32 row_width = row_info->width;
478
479 for (i = 0, sp = dp = row; i < row_width; i++)
480 {
481 /* Does nothing
482 *(dp++) = *(sp++);
483 *(dp++) = *(sp++);
484 */
485 sp+=2; dp = sp;
486 *(dp++) = (png_byte)(255 - *(sp++));
487 *dp = (png_byte)(255 - *(sp++));
488 }
489 }
490#endif /* WRITE_16BIT */
491 }
492 }
493}
494#endif
495
496/* Transform the data according to the user's wishes. The order of
497 * transformations is significant.
498 */
499void /* PRIVATE */
500png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
501{
502 png_debug(1, "in png_do_write_transformations");
503
504 if (png_ptr == NULL)
505 return;
506
507#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
508 if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
509 if (png_ptr->write_user_transform_fn != NULL)
510 (*(png_ptr->write_user_transform_fn)) /* User write transform
511 function */
512 (png_ptr, /* png_ptr */
513 row_info, /* row_info: */
514 /* png_uint_32 width; width of row */
515 /* size_t rowbytes; number of bytes in row */
516 /* png_byte color_type; color type of pixels */
517 /* png_byte bit_depth; bit depth of samples */
518 /* png_byte channels; number of channels (1-4) */
519 /* png_byte pixel_depth; bits per pixel (depth*channels) */
520 png_ptr->row_buf + 1); /* start of pixel data for row */
521#endif
522
523#ifdef PNG_WRITE_FILLER_SUPPORTED
524 if ((png_ptr->transformations & PNG_FILLER) != 0)
525 png_do_strip_channel(row_info, png_ptr->row_buf + 1,
526 !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
527#endif
528
529#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
530 if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
531 png_do_packswap(row_info, png_ptr->row_buf + 1);
532#endif
533
534#ifdef PNG_WRITE_PACK_SUPPORTED
535 if ((png_ptr->transformations & PNG_PACK) != 0)
536 png_do_pack(row_info, png_ptr->row_buf + 1,
537 (png_uint_32)png_ptr->bit_depth);
538#endif
539
540#ifdef PNG_WRITE_SWAP_SUPPORTED
541# ifdef PNG_16BIT_SUPPORTED
542 if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
543 png_do_swap(row_info, png_ptr->row_buf + 1);
544# endif
545#endif
546
547#ifdef PNG_WRITE_SHIFT_SUPPORTED
548 if ((png_ptr->transformations & PNG_SHIFT) != 0)
549 png_do_shift(row_info, png_ptr->row_buf + 1,
550 &(png_ptr->shift));
551#endif
552
553#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
554 if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
555 png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);
556#endif
557
558#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
559 if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
560 png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);
561#endif
562
563#ifdef PNG_WRITE_BGR_SUPPORTED
564 if ((png_ptr->transformations & PNG_BGR) != 0)
565 png_do_bgr(row_info, png_ptr->row_buf + 1);
566#endif
567
568#ifdef PNG_WRITE_INVERT_SUPPORTED
569 if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
570 png_do_invert(row_info, png_ptr->row_buf + 1);
571#endif
572}
573#endif /* WRITE_TRANSFORMS */
574#endif /* WRITE */
#define NULL
Definition: types.h:112
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
const GLdouble * v
Definition: gl.h:2040
const GLubyte * c
Definition: glext.h:8905
GLenum GLint GLuint mask
Definition: glext.h:6028
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define c
Definition: ke_i.h:80
#define PNG_COLOR_TYPE_RGB_ALPHA
Definition: image.c:5168
#define PNG_COLOR_TYPE_GRAY_ALPHA
Definition: image.c:5167
#define PNG_COLOR_TYPE_PALETTE
Definition: image.c:5166
static const WCHAR sp[]
Definition: suminfo.c:287
#define shift
Definition: input.c:3280
#define png_get_uint_16(buf)
Definition: png.h:2843
png_structrp png_ptr
Definition: png.h:1122
png_uint_32
Definition: png.h:2036
#define PNG_COLOR_MASK_COLOR
Definition: png.h:659
#define PNG_COLOR_MASK_ALPHA
Definition: png.h:660
png_struct *PNG_RESTRICT png_structrp
Definition: png.h:464
png_byte * png_bytep
Definition: pngconf.h:566
#define png_debug(l, m)
Definition: pngdebug.h:145
#define PNG_ROWBYTES(pixel_bits, width)
Definition: pngpriv.h:754
#define PNG_INVERT_ALPHA
Definition: pngpriv.h:677
#define PNG_SWAP_ALPHA
Definition: pngpriv.h:675
#define PNG_USER_TRANSFORM
Definition: pngpriv.h:678
#define PNG_SHIFT
Definition: pngpriv.h:661
#define PNG_FILLER
Definition: pngpriv.h:673
#define PNG_FLAG_FILLER_AFTER
Definition: pngpriv.h:702
#define PNG_INVERT_MONO
Definition: pngpriv.h:663
#define PNG_PACK
Definition: pngpriv.h:660
#define PNG_PACKSWAP
Definition: pngpriv.h:674
#define PNG_SWAP_BYTES
Definition: pngpriv.h:662
#define PNG_BGR
Definition: pngpriv.h:658
int This channels
Definition: rdpsnd_libao.c:37
png_byte green
Definition: png.h:498
png_byte gray
Definition: png.h:500
png_byte blue
Definition: png.h:499
png_byte red
Definition: png.h:497
png_byte alpha
Definition: png.h:501
png_uint_32 width
Definition: png.h:766
png_byte color_type
Definition: png.h:768
png_byte bit_depth
Definition: png.h:769
png_byte pixel_depth
Definition: png.h:771
png_byte channels
Definition: png.h:770
size_t rowbytes
Definition: png.h:767
Definition: pdh_main.c:96
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383