Subversion Repositories Kolibri OS

Rev

Rev 6779 | Rev 8341 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6733 IgorA 1
 
2
3
 
4
; Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
5
; (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
6
; (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
7
8
 
9
; For conditions of distribution and use, see the disclaimer
10
; and license in png.inc
11
12
 
6881 IgorA 13
6733 IgorA 14
 
15
include '../../../../../../fs/kfar/trunk/zlib/deflate.inc'
16
include 'pngtokos.inc' ;integrate png to kos
17
18
 
19
include 'pnglibconf.inc'
20
include 'pngpriv.inc'
21
include 'png.inc'
22
include 'pngstruct.inc'
23
include 'pnginfo.inc'
24
include 'pngerror.asm'
25
include 'pngtrans.asm'
26
include 'pngget.asm'
27
include 'pngwrite.asm'
28
include 'pngmem.asm'
29
include 'pngset.asm'
30
include 'pngwutil.asm'
31
include 'pngwio.asm'
32
include 'pngwtran.asm'
33
34
 
35
;typedef png_libpng_version_1_6_25 Your_png_h_is_not_version_1_6_25;
36
37
 
38
; of the PNG file signature.  If the PNG data is embedded into another
39
; stream we can set num_bytes = 8 so that libpng will not attempt to read
40
; or write any of the magic bytes before it starts on the IHDR.
41
42
 
43
 
44
;void (png_structrp png_ptr, int num_bytes)
45
align 4
46
proc png_set_sig_bytes uses eax edi, png_ptr:dword, num_bytes:dword
47
	png_debug 1, 'in png_set_sig_bytes'
48
49
 
50
	cmp edi,0
51
	je .end_f ;if (..==0) return
52
53
 
54
	cmp eax,0
55
	jge @f
56
		xor eax,eax
57
	@@:
58
	cmp eax,8
59
	jle @f ;if (..>8)
60
		png_error edi, 'Too many bytes for PNG signature'
61
	@@:
62
	mov byte[edi+png_struct.sig_bytes],al
63
.end_f:
64
	ret
65
endp
66
67
 
68
; checking less than the full 8-byte signature so that those apps that
69
; already read the first few bytes of a file to determine the file type
70
; can simply check the remaining bytes for extra assurance.  Returns
71
; an integer less than, equal to, or greater than zero if sig is found,
72
; respectively, to be less than, to match, or be greater than the correct
73
; PNG signature (this is the same behavior as strcmp, memcmp, etc).
74
75
 
76
align 4
77
proc png_sig_cmp, sig:dword, start:dword, num_to_check:dword
78
;   byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
79
80
 
81
;      num_to_check = 8;
82
83
 
84
;      return (-1);
85
86
 
87
;      return (-1);
88
89
 
90
;      num_to_check = 8 - start;
91
92
 
93
	ret
94
endp
95
96
 
97
98
 
99
;voidpf (voidpf png_ptr, uInt items, uInt size)
100
align 4
101
proc png_zalloc uses edx ecx, png_ptr:dword, items:dword, size:dword
102
103
 
104
	jne @f
105
		xor eax,eax
106
		jmp .end_f ;if (..==0) return 0
107
	@@:
108
109
 
110
	not eax
111
	xor edx,edx
112
	mov ecx,[size]
113
	div ecx
114
	cmp [items],eax
115
	jl @f ;if (..>=..)
116
		png_warning [png_ptr], 'Potential overflow in png_zalloc()'
117
		xor eax,eax
118
		jmp .end_f
119
	@@:
120
121
 
122
	imul ecx,[items]
123
	stdcall png_malloc_warn, [png_ptr], ecx
124
.end_f:
125
	ret
126
endp
127
128
 
129
;void (voidpf png_ptr, voidpf ptr)
130
align 4
131
proc png_zfree, png_ptr:dword, p2ptr:dword
132
	stdcall png_free, [png_ptr], [p2ptr]
133
	ret
134
endp
135
136
 
137
; in case CRC is > 32 bits to leave the top bits 0.
138
139
 
140
align 4
141
proc png_reset_crc uses eax edi, png_ptr:dword
142
	; The cast is safe because the crc is a 32-bit value.
143
	mov edi,[png_ptr]
144
	stdcall [calc_crc32], 0, Z_NULL, 0
145
	mov dword[edi+png_struct.crc],eax
146
	ret
147
endp
148
149
 
150
; much data to this routine as the largest single buffer size.  We
151
; also check that this data will actually be used before going to the
152
; trouble of calculating it.
153
154
 
155
align 4
156
proc png_calculate_crc uses eax ebx edi, png_ptr:dword, ptr:dword, length:dword
157
locals
158
	need_crc dd 1
159
	safe_length dd ?
160
endl
161
	mov edi,[png_ptr]
162
	PNG_CHUNK_ANCILLARY [edi+png_struct.chunk_name]
163
	cmp eax,0 ;if (..!=0)
164
	je @f
165
		mov eax,[edi+png_struct.flags]
166
		and eax,PNG_FLAG_CRC_ANCILLARY_MASK
167
		cmp eax,PNG_FLAG_CRC_ANCILLARY_USE or PNG_FLAG_CRC_ANCILLARY_NOWARN
168
		jne .end0 ;if (..==..)
169
			mov dword[need_crc],0
170
		jmp .end0
171
	@@: ;else ;critical
172
		mov eax,[edi+png_struct.flags]
173
		and eax,PNG_FLAG_CRC_CRITICAL_IGNORE
174
		jz .end0 ;if (..!=0)
6779 IgorA 175
			mov dword[need_crc],0
6733 IgorA 176
	.end0:
177
178
 
179
	; systems it is a 64-bit value.  crc32, however, returns 32 bits so the
180
	; following cast is safe.  'uInt' may be no more than 16 bits, so it is
181
	; necessary to perform a loop here.
182
183
 
184
	je .end_f
185
	cmp dword[length],0
186
	jle .end_f ;if (..!=0 && ..>0)
187
		mov eax,[edi+png_struct.crc] ;Should never issue a warning
188
189
 
190
			mov ebx,[length]
191
			mov [safe_length],ebx
192
;#ifndef __COVERITY__
193
;         if (safe_length == 0)
194
;            safe_length = (uInt)-1 ;evil, but safe
195
;end if
196
			stdcall [calc_crc32], eax, [ptr], [safe_length]
197
198
 
199
			; target system has characteristics that will probably violate other
200
			; assumptions within the libpng code.
201
202
 
203
			add [ptr],ebx
204
			sub [length],ebx
205
			cmp dword[length],0
206
		jg .cycle0 ;while (..>0)
207
208
 
209
		mov [edi+png_struct.crc],eax
210
	.end_f:
211
	ret
212
endp
213
214
 
215
; functions that create a png_struct.
216
217
 
218
align 4
219
proc png_user_version_check, png_ptr:dword, user_png_ver:dword
220
	; Libpng versions 1.0.0 and later are binary compatible if the version
221
	; string matches through the second '.'; we must recompile any
222
	; applications that use any older library version.
223
224
 
225
;   {
226
;      int i = -1;
227
;      int found_dots = 0;
228
229
 
230
;      {
231
;         i++;
232
;         if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])
233
;            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
234
;         if (user_png_ver[i] == '.')
235
;            found_dots++;
236
;      } while (found_dots < 2 && user_png_ver[i] != 0 &&
237
;            PNG_LIBPNG_VER_STRING[i] != 0);
238
;   }
239
240
 
241
;      png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
242
243
 
244
;   {
245
if PNG_WARNINGS_SUPPORTED eq 1
246
;      size_t pos = 0;
247
;      char m[128];
248
249
 
250
;          "Application built with libpng-");
251
;      pos = png_safecat(m, (sizeof m), pos, user_png_ver);
252
;      pos = png_safecat(m, (sizeof m), pos, " but running with ");
253
;      pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING);
254
255
 
256
end if
257
258
 
259
;      png_ptr->flags = 0;
260
end if
261
262
 
263
;   }
264
265
 
266
	xor eax,eax
267
	inc eax
268
.end_f:
269
	ret
270
endp
271
272
 
273
; contains the common initialization.
274
275
 
276
;    png_error_ptr error_fn, png_error_ptr warn_fn, voidp mem_ptr,
277
;    png_malloc_ptr malloc_fn, png_free_ptr free_fn)
278
align 4
279
proc png_create_png_struct uses ebx ecx edi esi, user_png_ver:dword, error_ptr:dword, error_fn:dword, warn_fn:dword, mem_ptr:dword, malloc_fn:dword, free_fn:dword
280
locals
281
if PNG_SETJMP_SUPPORTED eq 1
282
	create_jmp_buf dd ? ;jmp_buf
283
end if
284
	create_struct png_struct
285
endl
286
	; This temporary stack-allocated structure is used to provide a place to
287
	; build enough context to allow the user provided memory allocator (if any)
288
	; to be called.
289
290
 
291
	mov ecx,sizeof.png_struct
292
	mov edi,ebp
293
	sub edi,ecx
294
	mov ebx,edi
295
	rep stosb
296
297
 
298
if PNG_USER_LIMITS_SUPPORTED eq 1
299
	mov dword[ebx+png_struct.user_width_max], PNG_USER_WIDTH_MAX
300
	mov dword[ebx+png_struct.user_height_max], PNG_USER_HEIGHT_MAX
301
302
 
303
	mov dword[ebx+png_struct.user_chunk_cache_max], PNG_USER_CHUNK_CACHE_MAX
304
305
 
306
	; in png_struct regardless.
307
308
 
309
end if
310
311
 
312
	; to do them now even though error handling is not yet set up.
313
314
 
315
	stdcall png_set_mem_fn, ebx, [mem_ptr], [malloc_fn], [free_fn]
316
end if
317
318
 
319
	; this will result in a memory leak unless the error_fn does something
320
	; extremely sophisticated.  The design lacks merit but is implicit in the
321
	; API.
322
323
 
324
325
 
326
	stdcall setjmp,... ;create_jmp_buf
327
	cmp eax,0
328
	j... .end0 ;if (!setjmp(create_jmp_buf))
329
330
 
331
		; successfully completed this function.  This only works if we have
332
		; setjmp() support compiled in, but it is safe - this stuff should
333
		; never happen.
334
335
 
336
		mov dword[ebx+png_struct.jmp_buf_size],0 ;stack allocation
337
;         create_struct.longjmp_fn = longjmp;
338
end if
339
	; Call the general version checker (shared with read and write code):
340
341
 
342
		cmp eax,0
343
		je .end0 ;if (..!=0)
344
			stdcall png_malloc_warn, ebx, sizeof.png_struct
345
			;eax = png_ptr
346
			cmp eax,0
347
			je .end0 ;if (..!=0)
348
				; png_ptr->zstream holds a back-pointer to the png_struct, so
349
				; this can only be done now:
350
351
 
352
				mov [ebx+png_struct.zstream.zfree], png_zfree
353
				mov [ebx+png_struct.zstream.opaque], eax
354
355
 
356
				; Eliminate the local error handling:
357
				mov [ebx+png_struct.jmp_buf_ptr], 0
358
				mov [ebx+png_struct.jmp_buf_size], 0
359
				mov [ebx+png_struct.longjmp_fn], 0
360
end if
361
				mov ecx,sizeof.png_struct
362
				mov edi,eax
363
				mov esi,ebx
364
				rep movsb ;*png_ptr = create_struct
365
366
 
367
				jmp .end_f
368
	.end0:
369
370
 
371
	; simple failure to allocate the png_struct.
372
373
 
374
.end_f:
375
	ret
376
endp
377
378
 
379
;png_infop (png_structrp png_ptr)
380
align 4
381
proc png_create_info_struct uses ebx ecx edi, png_ptr:dword
382
	png_debug 1, 'in png_create_info_struct'
383
	;ebx - info_ptr dd ? ;png_inforp
384
385
 
386
	cmp edi,0
387
	jne @f ;if (..==0) return 0
388
		xor eax,eax
389
		jmp .end_f
390
	@@:
391
392
 
393
	; that this call always returns ok.  The application typically sets up the
394
	; error handling *after* creating the info_struct because this is the way it
395
	; has always been done in 'example.asm'.
396
397
 
398
	mov ebx,eax
399
400
 
401
	je @f
402
		mov edi,eax
403
		xor eax,eax
404
		mov ecx,sizeof.png_info_def
405
		rep stosb ;memset(...
406
	@@:
407
408
 
409
.end_f:
410
	ret
411
endp
412
413
 
414
; Normally, one would use either png_destroy_read_struct() or
415
; png_destroy_write_struct() to free an info struct, but this may be
416
; useful for some applications.  From libpng 1.6.0 this function is also used
417
; internally to implement the png_info release part of the 'struct' destroy
418
; APIs.  This ensures that all possible approaches free the same data (all of
419
; it).
420
421
 
422
align 4
423
proc png_destroy_info_struct uses eax ebx ecx edi, png_ptr:dword, info_ptr_ptr:dword
424
	png_debug 1, 'in png_destroy_info_struct'
425
426
 
427
	je .end_f ;if (..==0) return
428
429
 
430
	cmp edi,0 ;if (..!=0)
431
	je .end_f
432
		; Do this first in case of an error below; if the app implements its own
433
		; memory management this can lead to png_free calling png_error, which
434
		; will abort this routine and return control to the app error handler.
435
		; An infinite loop may result if it then tries to free the same info
436
		; ptr.
437
438
 
439
440
 
441
		mov ebx,edi
442
		xor eax,eax
443
		mov ecx,sizeof.png_info_def
444
		rep stosb
445
		stdcall png_free, [png_ptr], ebx
446
	.end_f:
447
	ret
448
endp
449
450
 
451
; and applications using it are urged to use png_create_info_struct()
452
; instead.  Use deprecated in 1.6.0, internal use removed (used internally it
453
; is just a memset).
454
455
 
456
; the user-memory mechanism and the user error handling/warning mechanisms in
457
; those cases where it does anything other than a memset.
458
459
 
460
align 4
461
proc png_info_init_3, ptr_ptr:dword, png_info_struct_size:dword
462
;   png_inforp info_ptr = *ptr_ptr;
463
464
 
465
466
 
467
;      return;
468
469
 
470
;   {
471
;      *ptr_ptr = NULL;
472
	; The following line is why this API should not be used:
473
;      free(info_ptr);
474
;      info_ptr = png_malloc_base(NULL, (sizeof *info_ptr));
475
;      if (info_ptr == NULL)
476
;         return;
477
;      *ptr_ptr = info_ptr;
478
;   }
479
480
 
481
;   memset(info_ptr, 0, (sizeof *info_ptr));
482
	ret
483
endp
484
485
 
486
;void (png_structrp png_ptr, png_inforp info_ptr, int freer, uint_32 mask)
487
align 4
488
proc png_data_freer uses edi esi, png_ptr:dword, info_ptr:dword, freer:dword, mask:dword
489
	png_debug 1, 'in png_data_freer'
490
491
 
492
	cmp edi,0
493
	je .end_f
494
	mov esi,[info_ptr]
495
	cmp esi,0
496
	je .end_f ;if (..==0 || ..==0) return
497
498
 
499
;      info_ptr->free_me |= mask;
500
501
 
502
;      info_ptr->free_me &= ~mask;
503
504
 
505
;      png_error(png_ptr, "Unknown freer parameter in png_data_freer");
506
.end_f
507
	ret
508
endp
509
510
 
511
align 4
512
proc png_free_data uses eax edi esi, png_ptr:dword, info_ptr:dword, mask:dword, num:dword
513
	png_debug 1, 'in png_free_data'
514
515
 
516
	cmp edi,0
517
	je .end_f
518
	mov esi,[info_ptr]
519
	cmp esi,0
520
	je .end_f ;if (..==0 || ..==0) return
521
522
 
523
	; Free text item num or (if num == -1) all text items
524
;   if (info_ptr->text != 0 &&
525
;       ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0)
526
;   {
527
;      if (num != -1)
528
;      {
529
;         png_free(png_ptr, info_ptr->text[num].key);
530
;         info_ptr->text[num].key = NULL;
531
;      }
532
533
 
534
;      {
535
;         int i;
536
537
 
538
;            png_free(png_ptr, info_ptr->text[i].key);
539
540
 
541
;         info_ptr->text = NULL;
542
;         info_ptr->num_text = 0;
543
;      }
544
;   }
545
end if
546
547
 
548
	; Free any tRNS entry
549
	mov eax,[mask]
550
	and eax,PNG_FREE_TRNS
551
	and eax,[esi+png_info_def.free_me]
552
	jz @f ;if (..!=0)
6779 IgorA 553
		and dword[esi+png_info_def.valid], not PNG_INFO_tRNS
6733 IgorA 554
		stdcall png_free, edi, [esi+png_info_def.trans_alpha]
555
		mov dword[esi+png_info_def.trans_alpha],0
556
		mov word[esi+png_info_def.num_trans],0
557
	@@:
558
end if
559
560
 
561
	; Free any sCAL entry
562
	mov eax,[mask]
563
	and eax,PNG_FREE_SCAL
564
	and eax,[esi+png_info_def.free_me]
565
	jz @f ;if (..!=0)
6779 IgorA 566
		stdcall png_free, edi, [esi+png_info_def.scal_s_width]
6733 IgorA 567
		stdcall png_free, edi, [esi+png_info_def.scal_s_height]
568
		mov dword[esi+png_info_def.scal_s_width],0
569
		mov dword[esi+png_info_def.scal_s_height],0
570
		and dword[esi+png_info_def.valid], not PNG_INFO_sCAL
571
	@@:
572
end if
573
574
 
575
	; Free any pCAL entry
576
;   if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0)
577
;   {
578
;      png_free(png_ptr, info_ptr->pcal_purpose);
579
;      png_free(png_ptr, info_ptr->pcal_units);
580
;      info_ptr->pcal_purpose = NULL;
581
;      info_ptr->pcal_units = NULL;
582
583
 
584
;         {
585
;            int i;
586
587
 
588
;               png_free(png_ptr, info_ptr->pcal_params[i]);
589
;
590
;            png_free(png_ptr, info_ptr->pcal_params);
591
;            info_ptr->pcal_params = NULL;
592
;         }
593
;      info_ptr->valid &= ~PNG_INFO_pCAL;
594
;   }
595
end if
596
597
 
598
	; Free any profile entry
599
	mov eax,[mask]
600
	and eax,PNG_FREE_ICCP
601
	and eax,[esi+png_info_def.free_me]
602
	jz @f ;if (..!=0)
6779 IgorA 603
		stdcall png_free, edi, [esi+png_info_def.iccp_name]
6733 IgorA 604
		stdcall png_free, edi, [esi+png_info_def.iccp_profile]
605
		mov dword[esi+png_info_def.iccp_name],0
606
		mov dword[esi+png_info_def.iccp_profile],0
607
		and dword[esi+png_info_def.valid], not PNG_INFO_iCCP
608
	@@:
609
end if
610
611
 
612
	; Free a given sPLT entry, or (if num == -1) all sPLT entries
613
;   if (info_ptr->splt_palettes != 0 &&
614
;       ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0)
615
;   {
616
;      if (num != -1)
617
;      {
618
;         png_free(png_ptr, info_ptr->splt_palettes[num].name);
619
;         png_free(png_ptr, info_ptr->splt_palettes[num].entries);
620
;         info_ptr->splt_palettes[num].name = NULL;
621
;         info_ptr->splt_palettes[num].entries = NULL;
622
;      }
623
624
 
625
;      {
626
;         int i;
627
628
 
629
;         {
630
;            png_free(png_ptr, info_ptr->splt_palettes[i].name);
631
;            png_free(png_ptr, info_ptr->splt_palettes[i].entries);
632
;         }
633
634
 
635
;         info_ptr->splt_palettes = NULL;
636
;         info_ptr->splt_palettes_num = 0;
637
;         info_ptr->valid &= ~PNG_INFO_sPLT;
638
;      }
639
;   }
640
end if
641
642
 
643
;   if (info_ptr->unknown_chunks != 0 &&
644
;       ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0)
645
;   {
646
;      if (num != -1)
647
;      {
648
;          png_free(png_ptr, info_ptr->unknown_chunks[num].data);
649
;          info_ptr->unknown_chunks[num].data = NULL;
650
;      }
651
652
 
653
;      {
654
;         int i;
655
656
 
657
;            png_free(png_ptr, info_ptr->unknown_chunks[i].data);
658
659
 
660
;         info_ptr->unknown_chunks = NULL;
661
;         info_ptr->unknown_chunks_num = 0;
662
;      }
663
;   }
664
end if
665
666
 
667
	; Free any hIST entry
668
	mov eax,[mask]
669
	and eax,PNG_FREE_HIST
670
	and eax,[esi+png_info_def.free_me]
671
	jz @f ;if (..!=0)
6779 IgorA 672
		stdcall png_free, edi, [esi+png_info_def.hist]
6733 IgorA 673
		mov dword[esi+png_info_def.hist],0
674
		and dword[esi+png_info_def.valid], not PNG_INFO_hIST
675
	@@:
676
end if
677
678
 
679
	mov eax,[mask]
680
	and eax,PNG_FREE_PLTE
681
	and eax,[esi+png_info_def.free_me]
682
	jz @f ;if (..!=0)
6779 IgorA 683
		stdcall png_free, edi, [esi+png_info_def.palette]
6733 IgorA 684
		mov dword[esi+png_info_def.palette],0
685
		and dword[esi+png_info_def.valid],not PNG_INFO_PLTE
686
		mov dword[esi+png_info_def.num_palette],0
687
	@@:
688
689
 
690
	; Free any image bits attached to the info structure
691
;   if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0)
692
;   {
693
;      if (info_ptr->row_pointers != 0)
694
;      {
695
;         uint_32 row;
696
;         for (row = 0; row < info_ptr->height; row++)
697
;            png_free(png_ptr, info_ptr->row_pointers[row]);
698
699
 
700
;         info_ptr->row_pointers = NULL;
701
;      }
702
;      info_ptr->valid &= ~PNG_INFO_IDAT;
703
;   }
704
end if
705
706
 
707
;      mask &= ~PNG_FREE_MUL;
708
709
 
710
	not eax
711
	and [esi+png_info_def.free_me],eax
712
.end_f:
713
	ret
714
endp
715
716
 
717
; functions.  The application should free any memory associated with this
718
; pointer before png_write_destroy() or png_read_destroy() are called.
719
720
 
721
align 4
722
proc png_get_io_ptr, png_ptr:dword
723
	mov eax,[png_ptr]
724
	cmp eax,0
725
	je @f ;if (..==0) return 0
726
		mov eax,[eax+png_struct.io_ptr]
727
	@@:
728
	ret
729
endp
730
731
 
732
; Initialize the default input/output functions for the PNG file.  If you
733
; use your own read or write routines, you can call either png_set_read_fn()
734
; or png_set_write_fn() instead of png_init_io().  If you have defined
735
; PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a
736
; function of your own because "FILE *" isn't necessarily available.
737
738
 
739
align 4
740
proc png_init_io uses eax edi, png_ptr:dword, fp:dword
741
	png_debug 1, 'in png_init_io'
742
743
 
744
	cmp edi,0
745
	je @f ;if (..==0) return
746
		mov eax,[fp]
747
		mov [edi+png_struct.io_ptr],eax
748
	@@:
749
	ret
750
endp
751
752
 
753
; defines a cast of a signed integer to an unsigned integer either to preserve
754
; the value, if it is positive, or to calculate:
755
756
 
757
758
 
759
; negative integral value is added the result will be an unsigned value
760
; correspnding to the 2's complement representation.
761
762
 
763
align 4
764
proc png_save_int_32, buf:dword, i:dword
765
	stdcall png_save_uint_32, [buf], [i]
766
	ret
767
endp
768
769
 
770
; Convert the supplied time into an RFC 1123 string suitable for use in
771
; a "Creation Time" or other text-based time string.
772
773
 
774
align 4
775
short_months db 'Jan',0, 'Feb',0, 'Mar',0, 'Apr',0, 'May',0, 'Jun',0,\
776
	'Jul',0, 'Aug',0, 'Sep',0, 'Oct',0, 'Nov',0, 'Dec',0
777
778
 
779
proc png_convert_to_rfc1123_buffer, out_29:dword, ptime:dword
780
	cmp dword[out_29],0
781
	jne @f
782
		xor eax,eax
783
		jmp .end_f ;if (..==0) return 0
784
	@@:
785
786
 
787
;       ptime->month == 0    ||  ptime->month > 12  ||
788
;       ptime->day   == 0    ||  ptime->day   > 31  ||
789
;       ptime->hour  > 23    ||  ptime->minute > 59 ||
790
;       ptime->second > 60)
791
;      return 0;
792
793
 
794
;      size_t pos = 0;
795
;      char number_buf[5]; /* enough for a four-digit year */
796
797
 
798
;#     define APPEND_NUMBER(format, value)\
799
;         APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value)))
800
;#     define APPEND(ch) if (pos < 28) out_29[pos++] = (ch)
801
802
 
803
;      APPEND(' ');
804
;      APPEND_STRING(short_months[(ptime->month - 1)]);
805
;      APPEND(' ');
806
;      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year);
807
;      APPEND(' ');
808
;      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour);
809
;      APPEND(':');
810
;      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute);
811
;      APPEND(':');
812
;      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second);
813
;      APPEND_STRING(" +0000"); /* This reliably terminates the buffer */
814
815
 
816
;#     undef APPEND_NUMBER
817
;#     undef APPEND_STRING
818
;   }
819
820
 
821
	inc eax
822
.end_f:
823
	ret
824
endp
825
826
 
827
; To do: remove the following from libpng-1.7
828
; Original API that uses a private buffer in png_struct.
829
; Deprecated because it causes png_struct to carry a spurious temporary
830
; buffer (png_struct::time_buffer), better to have the caller pass this in.
831
832
 
833
align 4
834
proc png_convert_to_rfc1123, png_ptr:dword, ptime:dword
835
;   if (png_ptr != NULL)
836
;   {
837
	; The only failure above if png_ptr != NULL is from an invalid ptime
838
;      if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0)
839
;         png_warning(png_ptr, "Ignoring invalid time value");
840
841
 
842
;         return png_ptr->time_buffer;
843
;   }
844
845
 
846
	ret
847
endp
848
;#    endif /* LIBPNG_VER < 10700 */
849
;#  endif /* TIME_RFC1123 */
850
851
 
852
853
 
854
align 4
855
proc png_get_copyright, png_ptr:dword
856
jmp .end_0
857
@@: db 'libpng version 1.6.25 - September 1, 2016',13,10,\
858
	'      Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson',13,10,\
859
	'      Copyright (c) 1996-1997 Andreas Dilger',13,10,\
860
	'      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.',0
861
.end_0:
862
	mov eax,@b
863
	ret
864
endp
865
866
 
867
; format 1.0.0 through 99.99.99zz.  To get the version of *.inc files
868
; used with your application, print out PNG_LIBPNG_VER_STRING, which
869
; is defined in png.inc.
870
; Note: now there is no difference between png_get_libpng_ver() and
871
; png_get_header_ver().  Due to the version_nn_nn_nn typedef guard,
872
; it is guaranteed that png.asm uses the correct version of png.inc.
873
874
 
875
align 4
876
proc png_get_libpng_ver, png_ptr:dword
877
	; Version of *.asm files used when building libpng
878
;   return png_get_header_ver(png_ptr);
879
	ret
880
endp
881
882
 
883
align 4
884
proc png_get_header_ver, png_ptr:dword
885
	; Version of *.inc files used when building libpng
886
;   return PNG_LIBPNG_VER_STRING;
887
	ret
888
endp
889
890
 
891
align 4
892
proc png_get_header_version, png_ptr:dword
893
	; Returns longer string containing both version and date
894
;if __STDC__
895
;   return PNG_HEADER_VERSION_STRING
896
;#  ifndef PNG_READ_SUPPORTED
897
;      " (NO READ SUPPORT)"
898
;#  endif
899
;      PNG_STRING_NEWLINE;
900
;#else
901
;   return PNG_HEADER_VERSION_STRING;
902
;end if
903
	ret
904
endp
905
906
 
907
; Build a grayscale palette.  Palette is assumed to be 1 << bit_depth
908
; large of png_color.  This lets grayscale images be treated as
909
; paletted.  Most useful for gamma correction and simplification
910
; of code.  This API is not used internally.
911
912
 
913
align 4
914
proc png_build_grayscale_palette, bit_depth:dword, palette:dword
915
;   int num_palette;
916
;   int color_inc;
917
;   int i;
918
;   int v;
919
920
 
921
922
 
923
;      return;
924
925
 
926
;   {
927
;      case 1:
928
;         num_palette = 2;
929
;         color_inc = 0xff;
930
;         break;
931
;
932
;      case 2:
933
;         num_palette = 4;
934
;         color_inc = 0x55;
935
;         break;
936
;
937
;      case 4:
938
;         num_palette = 16;
939
;         color_inc = 0x11;
940
;         break;
941
;
942
;      case 8:
943
;         num_palette = 256;
944
;         color_inc = 1;
945
;         break;
946
;
947
;      default:
948
;         num_palette = 0;
949
;         color_inc = 0;
950
;         break;
951
;   }
952
;
953
;   for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
954
;   {
955
;      palette[i].red = (byte)(v & 0xff);
956
;      palette[i].green = (byte)(v & 0xff);
957
;      palette[i].blue = (byte)(v & 0xff);
958
;   }
959
	ret
960
endp
961
962
 
963
align 4
964
proc png_handle_as_unknown uses ecx edi esi, png_ptr:dword, chunk_name:dword
965
	; Check chunk_name and return "keep" value if it's on the list, else 0
966
;   bytep p, p_end;
967
968
 
969
	cmp edi,0
970
	je .end0
971
	cmp dword[chunk_name],0
972
	je .end0
973
	cmp dword[edi+png_struct.num_chunk_list],0
974
	je .end0
975
		jmp @f
976
	.end0: ;if (..==0 || ..==0 || ..==0)
977
		mov eax,PNG_HANDLE_CHUNK_AS_DEFAULT
978
		jmp .end_f
979
	@@:
980
981
 
982
;   p = p_end + png_ptr->num_chunk_list*5; /* beyond end */
983
984
 
985
	; code was always searched from the end of the list, this is no longer
986
	; necessary because the 'set' routine handles duplicate entries correcty.
987
988
 
989
;   {
990
;      p -= 5;
991
992
 
993
;         return p[4];
994
;   }
995
;   while (p > p_end);
996
997
 
998
	; be handled according to the value of png_ptr->unknown_default; this can be
999
	; confusing because, as a result, there are two levels of defaulting for
1000
	; unknown chunks.
1001
1002
 
1003
.end_f:
1004
	ret
1005
endp
1006
1007
 
1008
align 4
1009
proc png_chunk_unknown_handling, png_ptr:dword, chunk_name:dword
1010
;   byte chunk_string[5];
1011
1012
 
1013
;   return png_handle_as_unknown(png_ptr, chunk_string);
1014
	ret
1015
endp
1016
1017
 
1018
;int (png_structrp png_ptr)
1019
align 4
1020
proc png_reset_zstream, png_ptr:dword
1021
	mov eax,[png_ptr]
1022
	cmp eax,0
1023
	jne @f ;if (..==0)
1024
		mov eax,Z_STREAM_ERROR
1025
		jmp .end_f
1026
	@@:
1027
	; WARNING: this resets the window bits to the maximum!
1028
	add eax,png_struct.zstream
1029
	stdcall inflateReset,eax
1030
.end_f:
1031
	ret
1032
endp
1033
1034
 
1035
;uint_32 png_access_version_number(void)
1036
align 4
1037
png_access_version_number:
1038
	; Version of *.asm files used when building libpng
1039
	mov eax,PNG_LIBPNG_VER
1040
	ret
1041
1042
 
1043
; Ensure that png_ptr->zstream.msg holds some appropriate error message string.
1044
; If it doesn't 'ret' is used to set it to something appropriate, even in cases
1045
; like Z_OK or Z_STREAM_END where the error code is apparently a success code.
1046
1047
 
1048
align 4
1049
proc png_zstream_error uses eax edi, png_ptr:dword, p2ret:dword
1050
	; Translate 'p2ret' into an appropriate error string, priority is given to the
1051
	; one in zstream if set.  This always returns a string, even in cases like
1052
	; Z_OK or Z_STREAM_END where the error code is a success code.
1053
1054
 
1055
	cmp dword[edi+png_struct.zstream.msg],0
1056
	jne .end_f ;if (..==0) switch (p2ret)
1057
		mov eax,[p2ret]
1058
;      default:
1059
		cmp eax,Z_OK
1060
		jne @f
1061
			cStr dword[edi+png_struct.zstream.msg],'unexpected zlib return code'
1062
			jmp .end_f
1063
		@@:
1064
		cmp eax,Z_STREAM_END
1065
		jne @f
1066
			; Normal exit
1067
			cStr dword[edi+png_struct.zstream.msg],'unexpected end of LZ stream'
1068
			jmp .end_f
1069
		@@:
1070
		cmp eax,Z_NEED_DICT
1071
		jne @f
1072
			; This means the deflate stream did not have a dictionary; this
1073
			; indicates a bogus PNG.
1074
1075
 
1076
			jmp .end_f
1077
		@@:
1078
		cmp eax,Z_ERRNO
1079
		jne @f
1080
			; gz APIs only: should not happen
1081
			cStr dword[edi+png_struct.zstream.msg],'zlib IO error'
1082
			jmp .end_f
1083
		@@:
1084
		cmp eax,Z_STREAM_ERROR
1085
		jne @f
1086
			; internal libpng error
1087
			cStr dword[edi+png_struct.zstream.msg],'bad parameters to zlib'
1088
			jmp .end_f
1089
		@@:
1090
		cmp eax,Z_DATA_ERROR
1091
		jne @f
1092
			cStr dword[edi+png_struct.zstream.msg],'damaged LZ stream'
1093
			jmp .end_f
1094
		@@:
1095
		cmp eax,Z_MEM_ERROR
1096
		jne @f
1097
			cStr dword[edi+png_struct.zstream.msg],'insufficient memory'
1098
			jmp .end_f
1099
		@@:
1100
		cmp eax,Z_BUF_ERROR
1101
		jne @f
1102
			; End of input or output; not a problem if the caller is doing
1103
			; incremental read or write.
1104
1105
 
1106
			jmp .end_f
1107
		@@:
1108
		cmp eax,Z_VERSION_ERROR
1109
		jne @f
1110
			cStr dword[edi+png_struct.zstream.msg],'unsupported zlib version'
1111
			jmp .end_f
1112
		@@:
1113
		cmp eax,PNG_UNEXPECTED_ZLIB_RETURN
1114
		jne .end_f
1115
			; Compile errors here mean that zlib now uses the value co-opted in
1116
			; pngpriv.inc for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above
1117
			; and change pngpriv.inc.  Note that this message is "... return",
1118
			; whereas the default/Z_OK one is "... return code".
1119
1120
 
1121
;         break;
1122
.end_f:
1123
	ret
1124
endp
1125
1126
 
1127
; at libpng 1.5.5!
1128
1129
 
1130
 
1131
;if PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */
1132
;int (png_structrp png_ptr,
1133
;    png_colorspacerp colorspace, png_fixed_point gAMA, int from)
1134
	; This is called to check a new gamma value against an existing one.  The
1135
	; routine returns false if the new gamma value should not be written.
1136
	;
1137
	; 'from' says where the new gamma value comes from:
1138
	;
1139
	;    0: the new gamma value is the libpng estimate for an ICC profile
1140
	;    1: the new gamma value comes from a gAMA chunk
1141
	;    2: the new gamma value comes from an sRGB chunk
1142
1143
 
1144
proc png_colorspace_check_gamma, png_ptr:dword, colorspace:dword, gAMA:dword, from:dword
1145
;   png_fixed_point gtest;
1146
;
1147
;   if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
1148
;       (png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0  ||
1149
;      png_gamma_significant(gtest) != 0))
1150
;   {
1151
	; Either this is an sRGB image, in which case the calculated gamma
1152
	; approximation should match, or this is an image with a profile and the
1153
	; value libpng calculates for the gamma of the profile does not match the
1154
	; value recorded in the file.  The former, sRGB, case is an error, the
1155
	; latter is just a warning.
1156
1157
 
1158
;      {
1159
;         png_chunk_report(png_ptr, "gamma value does not match sRGB",
1160
;             PNG_CHUNK_ERROR);
1161
;         /* Do not overwrite an sRGB value */
1162
;         return from == 2;
1163
;      }
1164
1165
 
1166
;      {
1167
;         png_chunk_report(png_ptr, "gamma value does not match libpng estimate",
1168
;             PNG_CHUNK_WARNING);
1169
;         return from == 1;
1170
;      }
1171
;   }
1172
1173
 
1174
	ret
1175
endp
1176
1177
 
1178
align 4
1179
proc png_colorspace_set_gamma, png_ptr:dword, colorspace:dword, gAMA:dword
1180
	; Changed in libpng-1.5.4 to limit the values to ensure overflow can't
1181
	; occur.  Since the fixed point representation is asymetrical it is
1182
	; possible for 1/gamma to overflow the limit of 21474 and this means the
1183
	; gamma value must be at least 5/100000 and hence at most 20000.0.  For
1184
	; safety the limits here are a little narrower.  The values are 0.00016 to
1185
	; 6250.0, which are truly ridiculous gamma values (and will produce
1186
	; displays that are all black or all white.)
1187
1188
 
1189
	; handling code, which only required the value to be >0.
1190
1191
 
1192
1193
 
1194
;      errmsg = "gamma value out of range";
1195
1196
 
1197
	; Allow the application to set the gamma value more than once
1198
;   else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
1199
;      (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)
1200
;      errmsg = "duplicate";
1201
;#  endif
1202
1203
 
1204
;   else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
1205
;      return;
1206
1207
 
1208
;   {
1209
;      if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA,
1210
;          1/*from gAMA*/) != 0)
1211
;      {
1212
;         /* Store this gamma value. */
1213
;         colorspace->gamma = gAMA;
1214
;         colorspace->flags |=
1215
;            (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);
1216
;      }
1217
1218
 
1219
	; not updated however the colorspace is not invalidated.  This
1220
	; corresponds to the case where the existing gamma comes from an sRGB
1221
	; chunk or profile.  An error message has already been output.
1222
1223
 
1224
;   }
1225
1226
 
1227
;   colorspace->flags |= PNG_COLORSPACE_INVALID;
1228
;   png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);
1229
.end_f:
1230
	ret
1231
endp
1232
1233
 
1234
align 4
1235
proc png_colorspace_sync_info uses eax esi, png_ptr:dword, info_ptr:dword
1236
	mov esi,[info_ptr]
1237
	mov ax,[esi+png_info_def.colorspace.flags]
1238
	and ax,PNG_COLORSPACE_INVALID
1239
	cmp ax,0
1240
	je @f ;if (..!=0)
1241
		; Everything is invalid
1242
		and dword[esi+png_info_def.valid], not (PNG_INFO_gAMA or PNG_INFO_cHRM or PNG_INFO_sRGB or PNG_INFO_iCCP)
1243
1244
 
1245
		; Clean up the iCCP profile now if it won't be used.
1246
		stdcall png_free_data, [png_ptr], esi, PNG_FREE_ICCP, -1 ;not used
1247
end if
1248
		jmp .end0
1249
	@@: ;else
1250
if PNG_COLORSPACE_SUPPORTED eq 1
1251
		; Leave the INFO_iCCP flag set if the pngset.c code has already set
1252
		; it; this allows a PNG to contain a profile which matches sRGB and
1253
		; yet still have that profile retrievable by the application.
1254
1255
 
1256
		and ax,PNG_COLORSPACE_MATCHES_sRGB
1257
		cmp ax,0
1258
		je @f ;if (..!=0)
1259
			or dword[esi+png_info_def.valid], PNG_INFO_sRGB
1260
			jmp .end1
1261
		@@: ;else
1262
			and dword[esi+png_info_def.valid], not PNG_INFO_sRGB
1263
		.end1:
1264
		mov ax,[esi+png_info_def.colorspace.flags]
1265
		and ax,PNG_COLORSPACE_HAVE_ENDPOINTS
1266
		cmp ax,0
1267
		je @f ;if (..!=0)
1268
			or dword[esi+png_info_def.valid], PNG_INFO_cHRM
1269
			jmp .end2
1270
		@@: ;else
1271
			and dword[esi+png_info_def.valid], not PNG_INFO_cHRM
1272
		.end2:
1273
end if
1274
1275
 
1276
		and ax,PNG_COLORSPACE_HAVE_GAMMA
1277
		cmp ax,0
1278
		je @f ;if (..!=0)
1279
			or dword[esi+png_info_def.valid], PNG_INFO_gAMA
1280
			jmp .end0
1281
		@@: ;else
1282
			and dword[esi+png_info_def.valid], not PNG_INFO_gAMA
1283
	.end0:
1284
	ret
1285
endp
1286
1287
 
1288
align 4
1289
proc png_colorspace_sync uses ecx edi esi, png_ptr:dword, info_ptr:dword
1290
	mov edi,[info_ptr]
1291
	cmp edi,0
1292
	je @f ;if (..==0) ;reduce code size; check here not in the caller
1293
		mov ecx,sizeof.png_colorspace
1294
		mov esi,[png_ptr]
1295
		add esi,png_struct.colorspace
6881 IgorA 1296
		add edi,png_info_def.colorspace
1297
		rep movsb
6733 IgorA 1298
		stdcall png_colorspace_sync_info, [png_ptr], [info_ptr]
1299
	@@:
1300
	ret
1301
endp
1302
1303
 
1304
1305
 
1306
; Added at libpng-1.5.5 to support read and write of true CIEXYZ values for
1307
; cHRM, as opposed to using chromaticities.  These internal APIs return
1308
; non-zero on a parameter error.  The X, Y and Z values are required to be
1309
; positive and less than 1.0.
1310
1311
 
1312
align 4
1313
proc png_xy_from_XYZ, xy:dword, XYZ:dword
1314
;   int_32 d, dwhite, whiteX, whiteY;
1315
1316
 
1317
;   if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0)
1318
;      return 1;
1319
;   if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0)
1320
;      return 1;
1321
;   dwhite = d;
1322
;   whiteX = XYZ->red_X;
1323
;   whiteY = XYZ->red_Y;
1324
1325
 
1326
;   if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0)
1327
;      return 1;
1328
;   if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0)
1329
;      return 1;
1330
;   dwhite += d;
1331
;   whiteX += XYZ->green_X;
1332
;   whiteY += XYZ->green_Y;
1333
1334
 
1335
;   if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0)
1336
;      return 1;
1337
;   if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0)
1338
;      return 1;
1339
;   dwhite += d;
1340
;   whiteX += XYZ->blue_X;
1341
;   whiteY += XYZ->blue_Y;
1342
1343
 
1344
	; thus:
1345
1346
 
1347
;      return 1;
1348
;   if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0)
1349
;      return 1;
1350
1351
 
1352
	ret
1353
endp
1354
1355
 
1356
align 4
1357
proc png_XYZ_from_xy, XYZ:dword, xy:dword
1358
;   png_fixed_point red_inverse, green_inverse, blue_scale;
1359
;   png_fixed_point left, right, denominator;
1360
1361
 
1362
	; have end points with 0 tristimulus values (these are impossible end
1363
	; points, but they are used to cover the possible colors).  We check
1364
	; xy->whitey against 5, not 0, to avoid a possible integer overflow.
1365
1366
 
1367
;   if (xy->redy   < 0 || xy->redy > PNG_FP_1-xy->redx) return 1;
1368
;   if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1;
1369
;   if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1;
1370
;   if (xy->bluex  < 0 || xy->bluex > PNG_FP_1) return 1;
1371
;   if (xy->bluey  < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1;
1372
;   if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1;
1373
;   if (xy->whitey < 5 || xy->whitey > PNG_FP_1-xy->whitex) return 1;
1374
1375
 
1376
	; value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8
1377
	; derived values were recorded in the cHRM chunk;
1378
	; (red,green,blue,white)x(x,y).  This loses one degree of freedom and
1379
	; therefore an arbitrary ninth value has to be introduced to undo the
1380
	; original transformations.
1381
1382
 
1383
	; chromaticity values (c) have the property:
1384
1385
 
1386
	;   c = ---------
1387
	;       X + Y + Z
1388
1389
 
1390
	; three chromaticity values (x,y,z) for each end-point obey the
1391
	; relationship:
1392
1393
 
1394
1395
 
1396
	; value 1.0; call this the chromaticity plane.  Thus the chromaticity
1397
	; calculation has scaled each end-point so that it is on the x+y+z=1 plane
1398
	; and chromaticity is the intersection of the vector from the origin to the
1399
	; (X,Y,Z) value with the chromaticity plane.
1400
1401
 
1402
	; end-point scale factors, (red-scale, green-scale, blue-scale), but these
1403
	; were not recorded.  Instead we calculated the reference white (X,Y,Z) and
1404
	; recorded the chromaticity of this.  The reference white (X,Y,Z) would have
1405
	; given all three of the scale factors since:
1406
1407
 
1408
	;    white-C = red-C + green-C + blue-C
1409
	;            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
1410
1411
 
1412
	; factor:
1413
1414
 
1415
1416
 
1417
	; about white-scale:
1418
1419
 
1420
	;    Hence:  white-scale = 1/white-y
1421
	;    Or:     red-Y + green-Y + blue-Y = 1.0
1422
1423
 
1424
	; the nine values we want to calculate.  8 more equations come from the
1425
	; above routine as summarised at the top above (the chromaticity
1426
	; calculation):
1427
1428
 
1429
	;    Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0
1430
1431
 
1432
	; solved by Cramer's rule.  Cramer's rule requires calculating 10 9x9 matrix
1433
	; determinants, however this is not as bad as it seems because only 28 of
1434
	; the total of 90 terms in the various matrices are non-zero.  Nevertheless
1435
	; Cramer's rule is notoriously numerically unstable because the determinant
1436
	; calculation involves the difference of large, but similar, numbers.  It is
1437
	; difficult to be sure that the calculation is stable for real world values
1438
	; and it is certain that it becomes unstable where the end points are close
1439
	; together.
1440
1441
 
1442
	; understandable and totally obvious approach of calculating color-scale.
1443
1444
 
1445
	; (1/white-y), so we can immediately see that as white-y approaches 0 the
1446
	; accuracy inherent in the cHRM chunk drops off substantially.
1447
1448
 
1449
	; ------------------------------------------------------------
1450
1451
 
1452
	;    white-X = white-x * white-scale
1453
	;    white-Y = 1.0
1454
	;    white-Z = (1 - white-x - white-y) * white_scale
1455
1456
 
1457
	;            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
1458
1459
 
1460
	; all the coefficients are now known:
1461
1462
 
1463
	;       = white-x/white-y
1464
	;    red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1
1465
	;    red-z*red-scale + green-z*green-scale + blue-z*blue-scale
1466
	;       = (1 - white-x - white-y)/white-y
1467
1468
 
1469
	; three equations together to get an alternative third:
1470
1471
 
1472
1473
 
1474
	; 3x3 - far more tractible.  Unfortunately 3x3 determinants still involve
1475
	; multiplication of three coefficients so we can't guarantee to avoid
1476
	; overflow in the libpng fixed point representation.  Using Cramer's rule in
1477
	; floating point is probably a good choice here, but it's not an option for
1478
	; fixed point.  Instead proceed to simplify the first two equations by
1479
	; eliminating what is likely to be the largest value, blue-scale:
1480
1481
 
1482
1483
 
1484
1485
 
1486
	;                (white-x - blue-x)*white-scale
1487
1488
 
1489
	;                1 - blue-y*white-scale
1490
1491
 
1492
1493
 
1494
	;                (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale
1495
	;                -----------------------------------------------------------
1496
	;                                  green-x - blue-x
1497
1498
 
1499
	;                1 - blue-y*white-scale - (green-y - blue-y) * green-scale
1500
	;                ---------------------------------------------------------
1501
	;                                  red-y - blue-y
1502
1503
 
1504
1505
 
1506
	;          ( (green-x - blue-x) * (white-y - blue-y) -
1507
	;            (green-y - blue-y) * (white-x - blue-x) ) / white-y
1508
	; -------------------------------------------------------------------------
1509
	;  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
1510
1511
 
1512
	;          ( (red-y - blue-y) * (white-x - blue-x) -
1513
	;            (red-x - blue-x) * (white-y - blue-y) ) / white-y
1514
	; -------------------------------------------------------------------------
1515
	;  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
1516
1517
 
1518
	; The input values have 5 decimal digits of accuracy.  The values are all in
1519
	; the range 0 < value < 1, so simple products are in the same range but may
1520
	; need up to 10 decimal digits to preserve the original precision and avoid
1521
	; underflow.  Because we are using a 32-bit signed representation we cannot
1522
	; match this; the best is a little over 9 decimal digits, less than 10.
1523
1524
 
1525
	; signed representation.  Because the red-scale calculation above uses the
1526
	; difference between two products of values that must be in the range -1..+1
1527
	; it is sufficient to divide the product by 7; ceil(100,000/32767*2).  The
1528
	; factor is irrelevant in the calculation because it is applied to both
1529
	; numerator and denominator.
1530
1531
 
1532
	; chromaticities in the above equations tend to be small, for example for
1533
	; the sRGB chromaticities they are:
1534
1535
 
1536
	; green numerator:  -0.08788
1537
	; denominator:      -0.2241 (without white-y multiplication)
1538
1539
 
1540
	;  color space definitions are (to 15 decimal places):
1541
1542
 
1543
	;    0.212639005871510 0.715168678767756 0.072192315360734
1544
	;  Kodak ProPhoto
1545
	;    0.288071128229293 0.711843217810102 0.000085653960605
1546
	;  Adobe RGB
1547
	;    0.297344975250536 0.627363566255466 0.075291458493998
1548
	;  Adobe Wide Gamut RGB
1549
	;    0.258728243040113 0.724682314948566 0.016589442011321
1550
1551
 
1552
	; value of 2 indicates an internal error to the caller.
1553
1554
 
1555
;      return 2;
1556
;   if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0)
1557
;      return 2;
1558
;   denominator = left - right;
1559
1560
 
1561
;   if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
1562
;      return 2;
1563
;   if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
1564
;      return 2;
1565
1566
 
1567
	; chunk values.  This calculation actually returns the reciprocal of the
1568
	; scale value because this allows us to delay the multiplication of white-y
1569
	; into the denominator, which tends to produce a small number.
1570
1571
 
1572
;       red_inverse <= xy->whitey /* r+g+b scales = white scale */)
1573
;      return 1;
1574
1575
 
1576
;   if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
1577
;      return 2;
1578
;   if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
1579
;      return 2;
1580
;   if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 ||
1581
;       green_inverse <= xy->whitey)
1582
;      return 1;
1583
1584
 
1585
	; can still produce 0 for extreme cHRM values.
1586
1587
 
1588
;       png_reciprocal(green_inverse);
1589
;   if (blue_scale <= 0)
1590
;      return 1;
1591
1592
 
1593
 
1594
;   if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0)
1595
;      return 1;
1596
;   if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0)
1597
;      return 1;
1598
;   if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1,
1599
;       red_inverse) == 0)
1600
;      return 1;
1601
1602
 
1603
;      return 1;
1604
;   if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0)
1605
;      return 1;
1606
;   if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1,
1607
;       green_inverse) == 0)
1608
;      return 1;
1609
1610
 
1611
;      return 1;
1612
;   if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0)
1613
;      return 1;
1614
;   if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale,
1615
;       PNG_FP_1) == 0)
1616
;      return 1;
1617
1618
 
1619
	ret
1620
endp
1621
1622
 
1623
align 4
1624
proc png_XYZ_normalize, XYZ:dword
1625
;   int_32 Y;
1626
1627
 
1628
;      XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 ||
1629
;      XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0)
1630
;      return 1;
1631
1632
 
1633
	; IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore
1634
	; relying on addition of two positive values producing a negative one is not
1635
	; safe.
1636
1637
 
1638
;   if (0x7fffffff - Y < XYZ->green_X)
1639
;      return 1;
1640
;   Y += XYZ->green_Y;
1641
;   if (0x7fffffff - Y < XYZ->blue_X)
1642
;      return 1;
1643
;   Y += XYZ->blue_Y;
1644
1645
 
1646
;   {
1647
;      if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0)
1648
;         return 1;
1649
;      if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0)
1650
;         return 1;
1651
;      if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0)
1652
;         return 1;
1653
1654
 
1655
;         return 1;
1656
;      if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0)
1657
;         return 1;
1658
;      if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0)
1659
;         return 1;
1660
1661
 
1662
;         return 1;
1663
;      if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0)
1664
;         return 1;
1665
;      if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0)
1666
;         return 1;
1667
;   }
1668
1669
 
1670
	ret
1671
endp
1672
1673
 
1674
align 4
1675
proc png_colorspace_endpoints_match, xy1:dword, xy2:dword, delta:dword
1676
	; Allow an error of +/-0.01 (absolute value) on each chromaticity
1677
;   if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) ||
1678
;       PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) ||
1679
;       PNG_OUT_OF_RANGE(xy1->redx,   xy2->redx,  delta) ||
1680
;       PNG_OUT_OF_RANGE(xy1->redy,   xy2->redy,  delta) ||
1681
;       PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) ||
1682
;       PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) ||
1683
;       PNG_OUT_OF_RANGE(xy1->bluex,  xy2->bluex, delta) ||
1684
;       PNG_OUT_OF_RANGE(xy1->bluey,  xy2->bluey, delta))
1685
;      return 0;
1686
;   return 1;
1687
	ret
1688
endp
1689
1690
 
1691
; chunk chromaticities.  Earlier checks used to simply look for the overflow
1692
; condition (where the determinant of the matrix to solve for XYZ ends up zero
1693
; because the chromaticity values are not all distinct.)  Despite this it is
1694
; theoretically possible to produce chromaticities that are apparently valid
1695
; but that rapidly degrade to invalid, potentially crashing, sets because of
1696
; arithmetic inaccuracies when calculations are performed on them.  The new
1697
; check is to round-trip xy -> XYZ -> xy and then check that the result is
1698
; within a small percentage of the original.
1699
1700
 
1701
align 4
1702
proc png_colorspace_check_xy, XYZ:dword, xy:dword
1703
;   int result;
1704
;   png_xy xy_test;
1705
1706
 
1707
;   result = png_XYZ_from_xy(XYZ, xy);
1708
;   if (result != 0)
1709
;      return result;
1710
1711
 
1712
;   if (result != 0)
1713
;      return result;
1714
1715
 
1716
;       5/*actually, the math is pretty accurate*/) != 0)
1717
;      return 0;
1718
1719
 
1720
;   return 1;
1721
	ret
1722
endp
1723
1724
 
1725
; (another side-effect) and the xy chromaticities are returned.
1726
1727
 
1728
align 4
1729
proc png_colorspace_check_XYZ, xy:dword, XYZ:dword
1730
;   int result;
1731
;   png_XYZ XYZtemp;
1732
1733
 
1734
;   if (result != 0)
1735
;      return result;
1736
1737
 
1738
;   if (result != 0)
1739
;      return result;
1740
1741
 
1742
;   return png_colorspace_check_xy(&XYZtemp, xy);
1743
	ret
1744
endp
1745
1746
 
1747
;const png_xy sRGB_xy = /* From ITU-R BT.709-3 */
1748
;   /* color      x       y */
1749
;   /* red   */ 64000, 33000,
1750
;   /* green */ 30000, 60000,
1751
;   /* blue  */ 15000,  6000,
1752
;   /* white */ 31270, 32900
1753
1754
 
1755
;    png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ,
1756
;    int preferred)
1757
align 4
1758
proc png_colorspace_set_xy_and_XYZ, png_ptr:dword, colorspace:dword, xy:dword, XYZ:dword, preferred:dword
1759
;   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
1760
;      return 0;
1761
1762
 
1763
	; variations because of the normalization (or not) of the end point Y
1764
	; values.
1765
1766
 
1767
;       (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
1768
;   {
1769
	; The end points must be reasonably close to any we already have.  The
1770
	; following allows an error of up to +/-.001
1771
1772
 
1773
;          100) == 0)
1774
;      {
1775
;         colorspace->flags |= PNG_COLORSPACE_INVALID;
1776
;         png_benign_error(png_ptr, "inconsistent chromaticities");
1777
;         return 0; /* failed */
1778
;      }
1779
1780
 
1781
;      if (preferred == 0)
1782
;         return 1; /* ok, but no change */
1783
;   }
1784
1785
 
1786
;   colorspace->end_points_XYZ = *XYZ;
1787
;   colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS;
1788
1789
 
1790
	; on this test.
1791
1792
 
1793
;      colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB;
1794
;
1795
;   else
1796
;      colorspace->flags &= PNG_COLORSPACE_CANCEL(
1797
;         PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
1798
1799
 
1800
	ret
1801
endp
1802
1803
 
1804
;    png_colorspacerp colorspace, const png_xy *xy, int preferred)
1805
align 4
1806
proc png_colorspace_set_chromaticities, png_ptr:dword, colorspace:dword, xy:dword, preferred:dword
1807
	; We must check the end points to ensure they are reasonable - in the past
1808
	; color management systems have crashed as a result of getting bogus
1809
	; colorant values, while this isn't the fault of libpng it is the
1810
	; responsibility of libpng because PNG carries the bomb and libpng is in a
1811
	; position to protect against it.
1812
1813
 
1814
1815
 
1816
;   {
1817
;      case 0: /* success */
1818
;         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ,
1819
;             preferred);
1820
1821
 
1822
	; We can't invert the chromaticities so we can't produce value XYZ
1823
	; values.  Likely as not a color management system will fail too.
1824
1825
 
1826
;         png_benign_error(png_ptr, "invalid chromaticities");
1827
;         break;
1828
;
1829
;      default:
1830
	; libpng is broken; this should be a warning but if it happens we
1831
	; want error reports so for the moment it is an error.
1832
1833
 
1834
;         png_error(png_ptr, "internal error checking chromaticities");
1835
;   }
1836
1837
 
1838
.end_f:
1839
	ret
1840
endp
1841
1842
 
1843
;    png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred)
1844
align 4
1845
proc png_colorspace_set_endpoints, png_ptr:dword, colorspace:dword, XYZ_in:dword, preferred:dword
1846
;   png_XYZ XYZ = *XYZ_in;
1847
;   png_xy xy;
1848
1849
 
1850
;   {
1851
;      case 0:
1852
;         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ,
1853
;             preferred);
1854
1855
 
1856
	; End points are invalid.
1857
;         colorspace->flags |= PNG_COLORSPACE_INVALID;
1858
;         png_benign_error(png_ptr, "invalid end points");
1859
;         break;
1860
1861
 
1862
;         colorspace->flags |= PNG_COLORSPACE_INVALID;
1863
;         png_error(png_ptr, "internal error checking chromaticities");
1864
;   }
1865
1866
 
1867
.end_f:
1868
	ret
1869
endp
1870
1871
 
1872
;char (uint_32 byte)
1873
align 4
1874
proc png_icc_tag_char, p1byte:dword
1875
	mov eax,[p1byte]
1876
	cmp al,32
1877
	jl @f
1878
	cmp al,126
1879
	jg @f ;if (..>=.. && ..<=..) return
1880
		mov al,'?'
1881
	@@:
1882
	and eax,0xff
1883
	ret
1884
endp
1885
1886
 
1887
align 4
1888
proc png_icc_tag_name uses eax edi, name:dword, tag:dword
1889
	mov edi,[name]
1890
	mov byte[edi],39
1891
	mov byte[edi+5],39
1892
	inc edi
1893
	mov eax,[tag]
1894
	shr eax,24
1895
	stdcall png_icc_tag_char,eax
1896
	stosb
1897
	mov eax,[tag]
1898
	shr eax,16
1899
	stdcall png_icc_tag_char,eax
1900
	stosb
1901
	mov eax,[tag]
1902
	shr eax,8
1903
	stdcall png_icc_tag_char,eax
1904
	stosb
1905
	stdcall png_icc_tag_char,[tag]
1906
	stosb
1907
	ret
1908
endp
1909
1910
 
1911
align 4
1912
proc is_ICC_signature_char, it:dword
1913
;   return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) ||
1914
;      (it >= 97 && it <= 122);
1915
	ret
1916
endp
1917
1918
 
1919
align 4
1920
proc is_ICC_signature, it:dword
1921
;   return is_ICC_signature_char(it >> 24) /* checks all the top bits */ &&
1922
;      is_ICC_signature_char((it >> 16) & 0xff) &&
1923
;      is_ICC_signature_char((it >> 8) & 0xff) &&
1924
;      is_ICC_signature_char(it & 0xff);
1925
	ret
1926
endp
1927
1928
 
1929
;    charp name, png_alloc_size_t value, charp reason)
1930
align 4
1931
proc png_icc_profile_error, png_ptr:dword, colorspace:dword, name:dword, value:dword, reason:dword
1932
locals
1933
	pos dd ? ;size_t
1934
	message rb 196 ;char[] ;see below for calculation
1935
endl
1936
	mov eax,[colorspace]
1937
	cmp eax,0
1938
	je @f ;if (..!=0)
1939
		or word[eax+png_colorspace.flags], PNG_COLORSPACE_INVALID
1940
	@@:
1941
1942
 
1943
;   pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */
1944
;   pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */
1945
;   if (is_ICC_signature(value) != 0)
1946
;   {
1947
	; So 'value' is at most 4 bytes and the following cast is safe
1948
;      png_icc_tag_name(message+pos, (uint_32)value);
1949
;      pos += 6; /* total +8; less than the else clause */
1950
;      message[pos++] = ':';
1951
;      message[pos++] = ' ';
1952
;   }
1953
if PNG_WARNINGS_SUPPORTED eq 1
1954
;   else
1955
;      {
1956
;         char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/
1957
1958
 
1959
;             png_format_number(number, number+(sizeof number),
1960
;             PNG_NUMBER_FORMAT_x, value));
1961
;         pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/
1962
;      }
1963
end if
1964
	; The 'reason' is an arbitrary message, allow +79 maximum 195
1965
;   pos = png_safecat(message, (sizeof message), pos, reason);
1966
1967
 
1968
	; avoid writing invalid ICC profiles into PNG files (i.e., we handle them
1969
	; on read, with a warning, but on write unless the app turns off
1970
	; application errors the PNG won't be written.)
1971
1972
 
1973
;       (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);
1974
1975
 
1976
	ret
1977
endp
1978
1979
 
1980
;color      X      Y      Z
1981
sRGB_XYZ dd 41239, 21264,  1933,\ ;red
1982
	35758, 71517, 11919,\ ;green
1983
	18048,  7219, 95053  ;blue
1984
end if
1985
1986
 
1987
align 4
1988
proc png_colorspace_set_sRGB uses ebx ecx edi esi, png_ptr:dword, colorspace:dword, intent:dword
1989
	; sRGB sets known gamma, end points and (from the chunk) intent.
1990
	; IMPORTANT: these are not necessarily the values found in an ICC profile
1991
	; because ICC profiles store values adapted to a D50 environment; it is
1992
	; expected that the ICC profile mediaWhitePointTag will be D50; see the
1993
	; checks and code elsewhere to understand this better.
1994
1995
 
1996
	; coefficients of (6968,23435,2366), which are reduced (because they add up
1997
	; to 32769 not 32768) to (6968,23434,2366).  These are the values that
1998
	; libpng has traditionally used (and are the best values given the 15bit
1999
	; algorithm used by the rgb to gray code.)
2000
2001
 
2002
	mov ebx,[colorspace]
2003
	mov ax,[ebx+png_colorspace.flags]
2004
	and ax,PNG_COLORSPACE_INVALID
2005
	cmp ax,0
2006
	je @f ;if (..!=0)
2007
		xor eax,eax
2008
		jmp .end_f
2009
	@@:
2010
2011
 
2012
	; PNG file to have cHRM or gAMA chunks along with sRGB, but the values must
2013
	; be consistent with the correct values.  If, however, this function is
2014
	; called below because an iCCP chunk matches sRGB then it is quite
2015
	; conceivable that an older app recorded incorrect gAMA and cHRM because of
2016
	; an incorrect calculation based on the values in the profile - this does
2017
	; *not* invalidate the profile (though it still produces an error, which can
2018
	; be ignored.)
2019
2020
 
2021
	cmp dword[intent],0
2022
	jl @f
2023
	cmp dword[intent],PNG_sRGB_INTENT_LAST
2024
	jge @f
2025
		jmp .end0
2026
	@@: ;if (..<0 || ..>=..)
2027
		cStr ,'sRGB'
2028
		cStr ecx,'invalid sRGB rendering intent'
2029
		stdcall png_icc_profile_error, edi, ebx, eax, [intent], ecx
2030
		jmp .end_f
2031
	.end0:
2032
2033
 
2034
	and ax,PNG_COLORSPACE_HAVE_INTENT
2035
	cmp ax,0
2036
	je @f
2037
	movzx eax,word[ebx+png_colorspace.rendering_intent]
2038
	cmp eax,[intent]
2039
	je @f ;if (..!=0 && ..!=..)
2040
		cStr ,'sRGB'
2041
		cStr ecx,'inconsistent rendering intents'
2042
		stdcall png_icc_profile_error, edi, ebx, eax, [intent], ecx
2043
		jmp .end_f
2044
	@@:
2045
2046
 
2047
	and ax,PNG_COLORSPACE_FROM_sRGB
2048
	cmp ax,0
2049
	je @f ;if (..!=0)
2050
		png_benign_error edi, 'duplicate sRGB information ignored'
2051
		xor eax,eax
2052
		jmp .end_f
2053
	@@:
2054
2055
 
2056
	; warn but overwrite the value with the correct one.
2057
2058
 
2059
	and ax,PNG_COLORSPACE_HAVE_ENDPOINTS
2060
	cmp ax,0
2061
	je @f ;if (..!=0 &&
2062
;       !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy,
2063
;       100))
2064
		cStr ,'cHRM chunk does not match sRGB'
2065
		stdcall png_chunk_report, edi, eax, PNG_CHUNK_ERROR
2066
	@@:
2067
2068
 
2069
	; returns true when the 'from' argument corresponds to sRGB (2).
2070
2071
 
2072
2073
 
2074
	mov eax,[intent]
2075
	mov [ebx+png_colorspace.rendering_intent],ax
2076
	or word[ebx+png_colorspace.flags], PNG_COLORSPACE_HAVE_INTENT
2077
2078
 
2079
;   colorspace->end_points_xy = sRGB_xy;
2080
;   colorspace->end_points_XYZ = sRGB_XYZ;
2081
	or word[ebx+png_colorspace.flags], (PNG_COLORSPACE_HAVE_ENDPOINTS or PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB)
2082
2083
 
2084
	mov dword[ebx+png_colorspace.gamma], PNG_GAMMA_sRGB_INVERSE
2085
	or word[ebx+png_colorspace.flags], PNG_COLORSPACE_HAVE_GAMMA
2086
2087
 
2088
	or word[ebx+png_colorspace.flags], (PNG_COLORSPACE_MATCHES_sRGB or PNG_COLORSPACE_FROM_sRGB)
2089
2090
 
2091
	inc eax ;set
2092
.end_f:
2093
	ret
2094
endp
2095
2096
 
2097
; Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value
2098
; is XYZ(0.9642,1.0,0.8249), which scales to:
2099
2100
 
2101
2102
 
2103
	0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d
2104
2105
 
2106
;(png_structrp png_ptr, png_colorspacerp colorspace, charp name, uint_32 profile_length)
2107
align 4
2108
proc icc_check_length, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword
2109
	cmp dword[profile_length],132
2110
	jge @f ;if (..<..)
2111
;      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2112
;          "too short");
2113
		jmp .end_f
2114
	@@:
2115
	xor eax,eax
2116
	inc eax
2117
.end_f:
2118
	ret
2119
endp
2120
2121
 
2122
;    charp name, uint_32 profile_length)
2123
align 4
2124
proc png_icc_check_length, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword
2125
;   if (!icc_check_length(png_ptr, colorspace, name, profile_length))
2126
;      return 0;
2127
2128
 
2129
	; png_decompress_chunk, yet this happens after the attempt to
2130
	; png_malloc_base the required data.  We only need this on read; on write
2131
	; the caller supplies the profile buffer so libpng doesn't allocate it.  See
2132
	; the call to icc_check_length below (the write case).
2133
2134
 
2135
;      else if (png_ptr->user_chunk_malloc_max > 0 &&
2136
;               png_ptr->user_chunk_malloc_max < profile_length)
2137
;         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2138
;             "exceeds application limits");
2139
elseif PNG_USER_CHUNK_MALLOC_MAX > 0
2140
;      else if (PNG_USER_CHUNK_MALLOC_MAX < profile_length)
2141
;         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2142
;             "exceeds libpng limits");
2143
else ;!SET_USER_LIMITS
2144
	; This will get compiled out on all 32-bit and better systems.
2145
;      else if (PNG_SIZE_MAX < profile_length)
2146
;         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2147
;             "exceeds system limits");
2148
end if ;!SET_USER_LIMITS
2149
	xor eax,eax
2150
	inc eax
2151
.end_f:
2152
	ret
2153
endp
2154
2155
 
2156
;    charp name, uint_32 profile_length,
2157
;    bytep profile/* first 132 bytes only */, int color_type)
2158
align 4
2159
proc png_icc_check_header, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword, profile:dword, color_type:dword
2160
;   uint_32 temp;
2161
2162
 
2163
	; is used later to check the tag table, so even if the profile seems over
2164
	; long profile_length from the caller must be correct.  The caller can fix
2165
	; this up on read or write by just passing in the profile header length.
2166
2167
 
2168
;   if (temp != profile_length)
2169
;      return png_icc_profile_error(png_ptr, colorspace, name, temp,
2170
;          "length does not match profile");
2171
2172
 
2173
;   if (temp > 3 && (profile_length & 3))
2174
;      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
2175
;          "invalid length");
2176
2177
 
2178
;   if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */
2179
;      profile_length < 132+12*temp) /* truncated tag table */
2180
;      return png_icc_profile_error(png_ptr, colorspace, name, temp,
2181
;          "tag count too large");
2182
2183
 
2184
	; 16 bits.
2185
2186
 
2187
;   if (temp >= 0xffff) /* The ICC limit */
2188
;      return png_icc_profile_error(png_ptr, colorspace, name, temp,
2189
;          "invalid rendering intent");
2190
2191
 
2192
	; versions.
2193
2194
 
2195
;      (void)png_icc_profile_error(png_ptr, NULL, name, temp,
2196
;          "intent outside defined range");
2197
2198
 
2199
	; been loaded; however, various header fields can be checked.  These checks
2200
	; are for values permitted by the PNG spec in an ICC profile; the PNG spec
2201
	; restricts the profiles that can be passed in an iCCP chunk (they must be
2202
	; appropriate to processing PNG data!)
2203
2204
 
2205
	; version number; however, the version number doesn't accomodate changes in
2206
	; the header fields (just the known tags and the interpretation of the
2207
	; data.)
2208
2209
 
2210
;   if (temp != 0x61637370)
2211
;      return png_icc_profile_error(png_ptr, colorspace, name, temp,
2212
;          "invalid signature");
2213
2214
 
2215
	; white point) are required to be D50,
2216
	; however the profile contains a record of the illuminant so perhaps ICC
2217
	; expects to be able to change this in the future (despite the rationale in
2218
	; the introduction for using a fixed PCS adopted white.)  Consequently the
2219
	; following is just a warning.
2220
2221
 
2222
;      (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/,
2223
;          "PCS illuminant is not D50");
2224
2225
 
2226
	; "If the iCCP chunk is present, the image samples conform to the colour
2227
	; space represented by the embedded ICC profile as defined by the
2228
	; International Color Consortium [ICC]. The colour space of the ICC profile
2229
	; shall be an RGB colour space for colour images (PNG colour types 2, 3, and
2230
	; 6), or a greyscale colour space for greyscale images (PNG colour types 0
2231
	; and 4)."
2232
2233
 
2234
	; conforms to the specification requirements.  Notice that an ICC 'gray'
2235
	; color-space profile contains the information to transform the monochrome
2236
	; data to XYZ or L*a*b (according to which PCS the profile uses) and this
2237
	; should be used in preference to the standard libpng K channel replication
2238
	; into R, G and B channels.
2239
2240
 
2241
	; handled.  However it it is clear that using an RGB profile in this context
2242
	; must be an error - there is no specification of what it means.  Thus it is
2243
	; almost certainly more correct to ignore the profile.
2244
2245
 
2246
;   switch (temp)
2247
;   {
2248
;      case 0x52474220: /* 'RGB ' */
2249
;         if ((color_type & PNG_COLOR_MASK_COLOR) == 0)
2250
;            return png_icc_profile_error(png_ptr, colorspace, name, temp,
2251
;                "RGB color space not permitted on grayscale PNG");
2252
;         break;
2253
2254
 
2255
;         if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
2256
;            return png_icc_profile_error(png_ptr, colorspace, name, temp,
2257
;                "Gray color space not permitted on RGB PNG");
2258
;         break;
2259
2260
 
2261
;         return png_icc_profile_error(png_ptr, colorspace, name, temp,
2262
;             "invalid ICC profile color space");
2263
;   }
2264
2265
 
2266
	; application requirements; the spec provides no guidance, but it's pretty
2267
	; weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer
2268
	; ('prtr') or 'spac' (for generic color spaces).  Issue a warning in these
2269
	; cases.  Issue an error for device link or abstract profiles - these don't
2270
	; contain the records necessary to transform the color-space to anything
2271
	; other than the target device (and not even that for an abstract profile).
2272
	; Profiles of these classes may not be embedded in images.
2273
2274
 
2275
;   switch (temp)
2276
;   {
2277
;      case 0x73636e72: /* 'scnr' */
2278
;      case 0x6d6e7472: /* 'mntr' */
2279
;      case 0x70727472: /* 'prtr' */
2280
;      case 0x73706163: /* 'spac' */
2281
;         /* All supported */
2282
;         break;
2283
2284
 
2285
;         /* May not be embedded in an image */
2286
;         return png_icc_profile_error(png_ptr, colorspace, name, temp,
2287
;             "invalid embedded Abstract ICC profile");
2288
2289
 
2290
;         /* DeviceLink profiles cannot be interpreted in a non-device specific
2291
	; fashion, if an app uses the AToB0Tag in the profile the results are
2292
	; undefined unless the result is sent to the intended device,
2293
	; therefore a DeviceLink profile should not be found embedded in a
2294
	; PNG.
2295
2296
 
2297
;             "unexpected DeviceLink ICC profile class");
2298
2299
 
2300
;         /* A NamedColor profile is also device specific, however it doesn't
2301
	; contain an AToB0 tag that is open to misinterpretation.  Almost
2302
	; certainly it will fail the tests below.
2303
2304
 
2305
;             "unexpected NamedColor ICC profile class");
2306
;         break;
2307
2308
 
2309
;         /* To allow for future enhancements to the profile accept unrecognized
2310
	; profile classes with a warning, these then hit the test below on the
2311
	; tag content to ensure they are backward compatible with one of the
2312
	; understood profiles.
2313
2314
 
2315
;             "unrecognized ICC profile class");
2316
;         break;
2317
;   }
2318
2319
 
2320
	; either in XYZ or Lab.
2321
2322
 
2323
;   switch (temp)
2324
;   {
2325
;      case 0x58595a20: /* 'XYZ ' */
2326
;      case 0x4c616220: /* 'Lab ' */
2327
;         break;
2328
2329
 
2330
;         return png_icc_profile_error(png_ptr, colorspace, name, temp,
2331
;             "unexpected ICC PCS encoding");
2332
;   }
2333
2334
 
2335
	ret
2336
endp
2337
2338
 
2339
;    charp name, uint_32 profile_length,
2340
;    bytep profile /* header plus whole tag table */)
2341
align 4
2342
proc png_icc_check_tag_table, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword, profile:dword
2343
;   uint_32 tag_count = png_get_uint_32(profile+128);
2344
;   uint_32 itag;
2345
;   bytep tag = profile+132; /* The first tag */
2346
2347
 
2348
	; (temporarily in 'tags').
2349
2350
 
2351
;   {
2352
;      uint_32 tag_id = png_get_uint_32(tag+0);
2353
;      uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */
2354
;      uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */
2355
2356
 
2357
	; start might actually be anywhere if there is no data, but this would be
2358
	; a clear abuse of the intent of the standard so the start is checked for
2359
	; being in range.  All defined tag types have an 8 byte header - a 4 byte
2360
	; type signature then 0.
2361
2362
 
2363
;      {
2364
	; CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is
2365
	; only a warning here because libpng does not care about the
2366
	; alignment.
2367
2368
 
2369
;             "ICC profile tag start not a multiple of 4");
2370
;      }
2371
2372
 
2373
	; profile.
2374
2375
 
2376
;         return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
2377
;             "ICC profile tag outside profile");
2378
;   }
2379
	xor eax,eax
2380
	inc eax ;success, maybe with warnings
2381
.end_f:
2382
	ret
2383
endp
2384
2385
 
2386
;#if PNG_sRGB_PROFILE_CHECKS >= 0
2387
; Information about the known ICC sRGB profiles
2388
struct png_sRGB_checks
2389
	adler dd ? ;uint_32
2390
	crc dd ?
2391
	length dd ?
2392
	md5 rd 4 ;uint_32[4]
2393
	have_md5 db ? ;byte
2394
	is_broken db ? ;byte
2395
	intent dw ? ;uint_16
2396
ends
2397
;#  define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0)
2398
;#  define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\
2399
;      { adler, crc, length, md5, broke, intent },
2400
2401
 
2402
	; This data comes from contrib/tools/checksum-icc run on downloads of
2403
	; all four ICC sRGB profiles from www.color.org.
2404
2405
 
2406
;   PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9,
2407
;       PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0,
2408
;       "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc")
2409
2410
 
2411
;   PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21,
2412
;       PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0,
2413
;       "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc")
2414
2415
 
2416
;       PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0,
2417
;       "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc")
2418
2419
 
2420
;   PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812,
2421
;       PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0,
2422
;       "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc")
2423
2424
 
2425
	; on the (empty) MD5 the other fields are used to attempt a match and
2426
	; a warning is produced.  The first two of these profiles have a 'cprt' tag
2427
	; which suggests that they were also made by Hewlett Packard.
2428
2429
 
2430
;       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0,
2431
;       "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc")
2432
2433
 
2434
	; match the D50 PCS illuminant in the header (it is in fact the D65 values,
2435
	; so the white point is recorded as the un-adapted value.)  The profiles
2436
	; below only differ in one byte - the intent - and are basically the same as
2437
	; the previous profile except for the mediaWhitePointTag error and a missing
2438
	; chromaticAdaptationTag.
2439
2440
 
2441
;       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/,
2442
;       "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual")
2443
2444
 
2445
;       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/,
2446
;       "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative")
2447
;
2448
2449
 
2450
align 4
2451
proc png_compare_ICC_profile_with_sRGB, png_ptr:dword, profile:dword, adler:dword
2452
	; The quick check is to verify just the MD5 signature and trust the
2453
	; rest of the data.  Because the profile has already been verified for
2454
	; correctness this is safe.  png_colorspace_set_sRGB will check the 'intent'
2455
	; field too, so if the profile has been edited with an intent not defined
2456
	; by sRGB (but maybe defined by a later ICC specification) the read of
2457
	; the profile will fail at that point.
2458
2459
 
2460
;   uint_32 intent = 0x10000; /* invalid */
2461
if PNG_sRGB_PROFILE_CHECKS > 1
2462
;   uLong crc = 0; /* the value for 0 length data */
2463
end if
2464
;   uint i;
2465
2466
 
2467
	; First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on"
2468
;   if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) ==
2469
;               PNG_OPTION_ON)
2470
;      return 0;
2471
end if
2472
2473
 
2474
;   {
2475
;      if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&
2476
;         png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&
2477
;         png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&
2478
;         png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])
2479
;      {
2480
	; This may be one of the old HP profiles without an MD5, in that
2481
	; case we can only use the length and Adler32 (note that these
2482
	; are not used by default if there is an MD5!)
2483
2484
 
2485
;            if (png_sRGB_checks[i].have_md5 != 0)
2486
;               return 1+png_sRGB_checks[i].is_broken;
2487
;#        endif
2488
2489
 
2490
;         if (length == 0)
2491
;         {
2492
;            length = png_get_uint_32(profile);
2493
;            intent = png_get_uint_32(profile+64);
2494
;         }
2495
2496
 
2497
;         if (length == (uint_32) png_sRGB_checks[i].length &&
2498
;            intent == (uint_32) png_sRGB_checks[i].intent)
2499
;         {
2500
	; Now calculate the adler32 if not done already.
2501
;            if (adler == 0)
2502
;            {
2503
;               adler = adler32(0, NULL, 0);
2504
;               adler = adler32(adler, profile, length);
2505
;            }
2506
2507
 
2508
;            {
2509
	; These basic checks suggest that the data has not been
2510
	; modified, but if the check level is more than 1 perform
2511
	; our own crc32 checksum on the data.
2512
2513
 
2514
;                  if (crc == 0)
2515
;                  {
2516
;                     crc = calc_crc32(0, NULL, 0);
2517
;                     crc = calc_crc32(crc, profile, length);
2518
;                  }
2519
2520
 
2521
2522
 
2523
;#              endif
2524
;               {
2525
;                  if (png_sRGB_checks[i].is_broken != 0)
2526
;                  {
2527
	; These profiles are known to have bad data that may cause
2528
	; problems if they are used, therefore attempt to
2529
	; discourage their use, skip the 'have_md5' warning below,
2530
	; which is made irrelevant by this error.
2531
2532
 
2533
;                         PNG_CHUNK_ERROR);
2534
;                  }
2535
2536
 
2537
	; the profile is perfectly valid, but it would be nice if
2538
	; people used the up-to-date ones.
2539
2540
 
2541
;                  {
2542
;                     png_chunk_report(png_ptr,
2543
;                         "out-of-date sRGB profile with no signature",
2544
;                         PNG_CHUNK_WARNING);
2545
;                  }
2546
2547
 
2548
;               }
2549
;            }
2550
2551
 
2552
	; The signature matched, but the profile had been changed in some
2553
	; way.  This probably indicates a data error or uninformed hacking.
2554
	; Fall through to "no match".
2555
2556
 
2557
;             "Not recognizing known sRGB profile that has been edited",
2558
;             PNG_CHUNK_WARNING);
2559
;         break;
2560
;# endif
2561
;         }
2562
;      }
2563
;   }
2564
2565
 
2566
	ret
2567
endp
2568
2569
 
2570
;    png_colorspacerp colorspace, bytep profile, uLong adler)
2571
align 4
2572
proc png_icc_set_sRGB uses eax, png_ptr:dword, colorspace:dword, profile:dword, adler:dword
2573
	; Is this profile one of the known ICC sRGB profiles?  If it is, just set
2574
	; the sRGB information.
2575
2576
 
2577
;      (void)png_colorspace_set_sRGB(png_ptr, colorspace,
2578
;         (int)/*already checked*/png_get_uint_32(profile+64));
2579
	ret
2580
endp
2581
;end if /* PNG_sRGB_PROFILE_CHECKS >= 0 */
2582
;end if /* sRGB */
2583
2584
 
2585
;    charp name, uint_32 profile_length, bytep profile,
2586
;    int color_type)
2587
align 4
2588
proc png_colorspace_set_ICC, png_ptr:dword, colorspace:dword, name:dword, profile_length:dword, profile:dword, color_type:dword
2589
;   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
2590
;      return 0;
2591
2592
 
2593
;       png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,
2594
;           color_type) != 0 &&
2595
;       png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,
2596
;           profile) != 0)
2597
;   {
2598
;#     if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0
2599
	; If no sRGB support, don't try storing sRGB information
2600
;         png_icc_set_sRGB(png_ptr, colorspace, profile, 0);
2601
;#     endif
2602
;      return 1;
2603
;   }
2604
2605
 
2606
	xor eax,eax
2607
.end_f:
2608
	ret
2609
endp
2610
;end if /* iCCP */
2611
2612
 
2613
align 4
2614
proc png_colorspace_set_rgb_coefficients, png_ptr:dword
2615
	; Set the rgb_to_gray coefficients from the colorspace.
2616
;   if (png_ptr->rgb_to_gray_coefficients_set == 0 &&
2617
;      (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
2618
;   {
2619
	; png_set_background has not been called, get the coefficients from the Y
2620
	; values of the colorspace colorants.
2621
2622
 
2623
;      png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y;
2624
;      png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y;
2625
;      png_fixed_point total = r+g+b;
2626
2627
 
2628
;         r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&
2629
;         g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&
2630
;         b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&
2631
;         r+g+b <= 32769)
2632
;      {
2633
	; We allow 0 coefficients here.  r+g+b may be 32769 if two or
2634
	; all of the coefficients were rounded up.  Handle this by
2635
	; reducing the *largest* coefficient by 1; this matches the
2636
	; approach used for the default coefficients in pngrtran.c
2637
2638
 
2639
;
2640
;         if (r+g+b > 32768)
2641
;            add = -1;
2642
;         else if (r+g+b < 32768)
2643
;            add = 1;
2644
2645
 
2646
;         {
2647
;            if (g >= r && g >= b)
2648
;               g += add;
2649
;            else if (r >= g && r >= b)
2650
;               r += add;
2651
;            else
2652
;               b += add;
2653
;         }
2654
2655
 
2656
;         if (r+g+b != 32768)
2657
;            png_error(png_ptr,
2658
;                "internal error handling cHRM coefficients");
2659
2660
 
2661
;         {
2662
;            png_ptr->rgb_to_gray_red_coeff   = (uint_16)r;
2663
;            png_ptr->rgb_to_gray_green_coeff = (uint_16)g;
2664
;         }
2665
;      }
2666
2667
 
2668
	; it should never happen, but it is important that if it does, the
2669
	; bug is fixed.
2670
2671
 
2672
;         png_error(png_ptr, "internal error handling cHRM->XYZ");
2673
;   }
2674
	ret
2675
endp
2676
2677
 
2678
2679
 
2680
;    uint_32 width, uint_32 height, int bit_depth,
2681
;    int color_type, int interlace_type, int compression_type, int filter_type)
2682
align 4
2683
proc png_check_IHDR uses eax ebx edi, png_ptr:dword, width:dword, height:dword, bit_depth:dword, color_type:dword, interlace_type:dword, compression_type:dword, filter_type:dword
2684
	mov edi,[png_ptr]
2685
	xor ebx,ebx
2686
2687
 
2688
	cmp dword[width],0
2689
	jne @f ;if (..==0)
2690
		png_warning edi, 'Image width is zero in IHDR'
2691
		inc ebx
2692
	@@:
2693
2694
 
2695
	jle @f ;if (..>..)
2696
		png_warning edi, 'Invalid image width in IHDR'
2697
		inc ebx
2698
	@@:
2699
2700
 
2701
	;  1 - filter byte
2702
	;  8 - 8-byte RGBA pixels
2703
	;  1 - extra max_pixel_depth pad
2704
	mov eax,[width]
2705
	add eax,7
2706
	and eax,not 7
2707
	cmp eax,((PNG_SIZE_MAX -48 -1) / 8) -1
2708
	jle @f ;if (..>..)
2709
		; The size of the row must be within the limits of this architecture.
2710
		; Because the read code can perform arbitrary transformations the
2711
		; maximum size is checked here.  Because the code in png_read_start_row
2712
		; adds extra space "for safety's sake" in several places a conservative
2713
		; limit is used here.
2714
2715
 
2716
		; but the effect in the real world is minor and the changes are more
2717
		; extensive, therefore much more dangerous and much more difficult to
2718
		; write in a way that avoids compiler warnings.
2719
2720
 
2721
		inc ebx
2722
	@@:
2723
2724
 
2725
	mov eax,[edi+png_struct.user_width_max]
2726
	cmp dword[width],eax
2727
else
2728
	cmp dword[width],PNG_USER_WIDTH_MAX
2729
end if
2730
	jle @f ;if (..>..)
2731
		png_warning edi, 'Image width exceeds user limit in IHDR'
2732
		inc ebx
2733
	@@:
2734
2735
 
2736
	jne @f ;if (..==0)
2737
		png_warning edi, 'Image height is zero in IHDR'
2738
		inc ebx
2739
	@@:
2740
2741
 
2742
	jle @f ;if (..>..)
2743
		png_warning edi, 'Invalid image height in IHDR'
2744
		inc ebx
2745
	@@:
2746
2747
 
2748
	mov eax,[edi+png_struct.user_height_max]
2749
	cmp dword[height],eax
2750
else
2751
	cmp dword[height],PNG_USER_HEIGHT_MAX
2752
end if
2753
	jle @f ;if (..>..)
2754
		png_warning edi, 'Image height exceeds user limit in IHDR'
2755
		inc ebx
2756
	@@:
2757
2758
 
2759
	cmp dword[bit_depth],1
2760
	je @f
2761
	cmp dword[bit_depth],2
2762
	je @f
2763
	cmp dword[bit_depth],4
2764
	je @f
2765
	cmp dword[bit_depth],8
2766
	je @f
2767
	cmp dword[bit_depth],16
2768
	je @f ;if (..!=.. && ...)
2769
		png_warning edi, 'Invalid bit depth in IHDR'
2770
		inc ebx
2771
	@@:
2772
2773
 
2774
	jl @f
2775
	cmp dword[color_type],1
2776
	je @f
2777
	cmp dword[color_type],5
2778
	je @f
2779
	cmp dword[color_type],6
2780
	jg @f
2781
		jmp .end0
2782
	@@: ;if (..<0 || ..==1 || ..==5 || ..>6)
2783
		png_warning edi, 'Invalid color type in IHDR'
2784
		inc ebx
2785
	.end0:
2786
2787
 
2788
	jne @f
2789
	cmp dword[bit_depth],8
2790
	jg .beg1
2791
	@@:
2792
	cmp dword[color_type],PNG_COLOR_TYPE_RGB
2793
	je @f
2794
	cmp dword[color_type],PNG_COLOR_TYPE_GRAY_ALPHA
2795
	je @f
2796
	cmp dword[color_type],PNG_COLOR_TYPE_RGB_ALPHA
2797
	jne .end1
2798
	@@:
2799
	cmp dword[bit_depth],8
2800
	jge .end1
2801
	.beg1: ;if (((..==..) && ..>..) || ((..==.. || ..==.. || ..==..) && ..<..))
2802
		png_warning edi, 'Invalid color type/bit depth combination in IHDR'
2803
		inc ebx
2804
	.end1:
2805
2806
 
2807
	jl @f ;if (..>=..)
2808
		png_warning edi, 'Unknown interlace method in IHDR'
2809
		inc ebx
2810
	@@:
2811
2812
 
2813
	je @f ;if (..!=..)
2814
		png_warning edi, 'Unknown compression method in IHDR'
2815
		inc ebx
2816
	@@:
2817
2818
 
2819
	; Accept filter_method 64 (intrapixel differencing) only if
2820
	; 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
2821
	; 2. Libpng did not read a PNG signature (this filter_method is only
2822
	;    used in PNG datastreams that are embedded in MNG datastreams) and
2823
	; 3. The application called png_permit_mng_features with a mask that
2824
	;    included PNG_FLAG_MNG_FILTER_64 and
2825
	; 4. The filter_method is 64 and
2826
	; 5. The color_type is RGB or RGBA
2827
2828
 
2829
;       png_ptr->mng_features_permitted != 0)
2830
		png_warning edi, 'MNG features are not allowed in a PNG datastream'
2831
2832
 
2833
;   {
2834
;      if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
2835
;          (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
2836
;          ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
2837
;          (color_type == PNG_COLOR_TYPE_RGB ||
2838
;          color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
2839
;      {
2840
		png_warning edi, 'Unknown filter method in IHDR'
2841
		inc ebx
2842
;      }
2843
2844
 
2845
;      {
2846
		png_warning edi, 'Invalid filter method in IHDR'
2847
		inc ebx
2848
;      }
2849
;   }
2850
2851
 
2852
	cmp dword[filter_type],PNG_FILTER_TYPE_BASE
2853
	je @f ;if (..!=..)
2854
		png_warning edi, 'Unknown filter method in IHDR'
2855
		inc ebx
2856
	@@:
2857
end if
2858
2859
 
2860
	je @f
2861
		png_error edi, 'Invalid IHDR data'
2862
	@@:
2863
	ret
2864
endp
2865
2866
 
2867
; ASCII to fp functions
2868
; Check an ASCII formated floating point value, see the more detailed
2869
; comments in pngpriv.inc
2870
2871
 
2872
;#define png_fp_add(state, flags) ((state) |= (flags))
2873
;#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY))
2874
2875
 
2876
align 4
2877
proc png_check_fp_number, string:dword, size:dword, statep:dword, whereami:dword
2878
;   int state = *statep;
2879
;   png_size_t i = *whereami;
2880
2881
 
2882
;   {
2883
;      int type;
2884
	; First find the type of the next character
2885
;      switch (string[i])
2886
;      {
2887
;      case 43:  type = PNG_FP_SAW_SIGN;                   break;
2888
;      case 45:  type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break;
2889
;      case 46:  type = PNG_FP_SAW_DOT;                    break;
2890
;      case 48:  type = PNG_FP_SAW_DIGIT;                  break;
2891
;      case 49: case 50: case 51: case 52:
2892
;      case 53: case 54: case 55: case 56:
2893
;      case 57:  type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break;
2894
;      case 69:
2895
;      case 101: type = PNG_FP_SAW_E;                      break;
2896
;      default:  goto PNG_FP_End;
2897
;      }
2898
2899
 
2900
	; state, the type is arranged to not overlap the
2901
	; bits of the PNG_FP_STATE.
2902
2903
 
2904
;      {
2905
;      case PNG_FP_INTEGER + PNG_FP_SAW_SIGN:
2906
;         if ((state & PNG_FP_SAW_ANY) != 0)
2907
;            goto PNG_FP_End; /* not a part of the number */
2908
2909
 
2910
;         break;
2911
2912
 
2913
	; Ok as trailer, ok as lead of fraction.
2914
;         if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */
2915
;            goto PNG_FP_End;
2916
2917
 
2918
;            png_fp_add(state, type);
2919
2920
 
2921
;            png_fp_set(state, PNG_FP_FRACTION | type);
2922
2923
 
2924
2925
 
2926
;         if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */
2927
;            png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
2928
2929
 
2930
2931
 
2932
2933
 
2934
;         if ((state & PNG_FP_SAW_DIGIT) == 0)
2935
;            goto PNG_FP_End;
2936
2937
 
2938
2939
 
2940
2941
 
2942
2943
 
2944
2945
 
2946
;         png_fp_add(state, type | PNG_FP_WAS_VALID);
2947
;         break;
2948
2949
 
2950
	; This is correct because the trailing '.' on an
2951
	; integer is handled above - so we can only get here
2952
	; with the sequence ".E" (with no preceding digits).
2953
2954
 
2955
;            goto PNG_FP_End;
2956
2957
 
2958
2959
 
2960
2961
 
2962
;         if ((state & PNG_FP_SAW_ANY) != 0)
2963
;            goto PNG_FP_End; /* not a part of the number */
2964
2965
 
2966
2967
 
2968
2969
 
2970
2971
 
2972
;         png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID);
2973
2974
 
2975
2976
 
2977
2978
 
2979
;      }
2980
2981
 
2982
;      ++i;
2983
;   }
2984
;
2985
;PNG_FP_End:
2986
	; Here at the end, update the state and return the correct
2987
	; return code.
2988
2989
 
2990
;   *whereami = i;
2991
2992
 
2993
	ret
2994
endp
2995
2996
 
2997
 
2998
;int (charp string, png_size_t size)
2999
align 4
3000
proc png_check_fp_string, string:dword, size:dword
3001
;   int        state=0;
3002
;   png_size_t char_index=0;
3003
;
3004
;   if (png_check_fp_number(string, size, &state, &char_index) != 0 &&
3005
;      (char_index == size || string[char_index] == 0))
3006
;      return state /* must be non-zero - see above */;
3007
3008
 
3009
	ret
3010
endp
3011
;end if /* pCAL || sCAL */
3012
3013
 
3014
;#  ifdef PNG_FLOATING_POINT_SUPPORTED
3015
; Utility used below - a simple accurate power of ten from an integral
3016
; exponent.
3017
3018
 
3019
align 4
3020
proc png_pow10, power:dword
3021
;   int recip = 0;
3022
;   double d = 1;
3023
3024
 
3025
	; 10 is exact whereas .1 is inexact in base 2
3026
3027
 
3028
;   {
3029
;      if (power < DBL_MIN_10_EXP) return 0;
3030
;      recip = 1, power = -power;
3031
;   }
3032
3033
 
3034
;   {
3035
	; Decompose power bitwise.
3036
;      double mult = 10;
3037
;      do
3038
;      {
3039
;         if (power & 1) d *= mult;
3040
;         mult *= mult;
3041
;         power >>= 1;
3042
;      }
3043
;      while (power > 0);
3044
3045
 
3046
;   }
3047
	; else power is 0 and d is 1
3048
3049
 
3050
	ret
3051
endp
3052
3053
 
3054
; precision.
3055
3056
 
3057
;    double fp, uint precision)
3058
align 4
3059
proc png_ascii_from_fp, png_ptr:dword, ascii:dword, size:dword, fp:dword, precision:dword
3060
	; We use standard functions from math.h, but not printf because
3061
	; that would require stdio.  The caller must supply a buffer of
3062
	; sufficient size or we will png_error.  The tests on size and
3063
	; the space in ascii[] consumed are indicated below.
3064
3065
 
3066
;      precision = DBL_DIG;
3067
3068
 
3069
;   if (precision > DBL_DIG+1)
3070
;      precision = DBL_DIG+1;
3071
3072
 
3073
;   if (size >= precision+5) /* See the requirements below. */
3074
;   {
3075
;      if (fp < 0)
3076
;      {
3077
;         fp = -fp;
3078
;         *ascii++ = 45; /* '-'  PLUS 1 TOTAL 1 */
3079
;         --size;
3080
;      }
3081
3082
 
3083
;      {
3084
;         int exp_b10;   /* A base 10 exponent */
3085
;         double base;   /* 10^exp_b10 */
3086
3087
 
3088
	; the calculation below rounds down when converting
3089
	; from base 2 to base 10 (multiply by log10(2) -
3090
	; 0.3010, but 77/256 is 0.3008, so exp_b10 needs to
3091
	; be increased.  Note that the arithmetic shift
3092
	; performs a floor() unlike C arithmetic - using a
3093
	; C multiply would break the following for negative
3094
	; exponents.
3095
3096
 
3097
3098
 
3099
3100
 
3101
;         base = png_pow10(exp_b10); /* May underflow */
3102
3103
 
3104
;         {
3105
;            /* And this may overflow. */
3106
;            double test = png_pow10(exp_b10+1);
3107
3108
 
3109
;               ++exp_b10, base = test;
3110
3111
 
3112
;               break;
3113
;         }
3114
3115
 
3116
	; range [.1,1) and exp_b10 is both the exponent and the digit
3117
	; *before* which the decimal point should be inserted
3118
	; (starting with 0 for the first digit).  Note that this
3119
	; works even if 10^exp_b10 is out of range because of the
3120
	; test on DBL_MAX above.
3121
3122
 
3123
;         while (fp >= 1) fp /= 10, ++exp_b10;
3124
3125
 
3126
	; less than .1, this is ok because the code below can
3127
	; handle the leading zeros this generates, so no attempt
3128
	; is made to correct that here.
3129
3130
 
3131
;            uint czero, clead, cdigits;
3132
;            char exponent[10];
3133
3134
 
3135
	; the number compared to using E-n.
3136
3137
 
3138
;            {
3139
;               czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */
3140
;               exp_b10 = 0;      /* Dot added below before first output. */
3141
;            }
3142
;            else
3143
;               czero = 0;    /* No zeros to add */
3144
3145
 
3146
	; inserting a '.' before a digit if the exponent is 0.
3147
3148
 
3149
;            cdigits = 0;   /* Count of digits in list. */
3150
3151
 
3152
;            {
3153
;               double d;
3154
3155
 
3156
	; Use modf here, not floor and subtract, so that
3157
	; the separation is done in one step.  At the end
3158
	; of the loop don't break the number into parts so
3159
	; that the final digit is rounded.
3160
3161
 
3162
;                  fp = modf(fp, &d);
3163
3164
 
3165
;               {
3166
;                  d = floor(fp + .5);
3167
3168
 
3169
;                  {
3170
;                     /* Rounding up to 10, handle that here. */
3171
;                     if (czero > 0)
3172
;                     {
3173
;                        --czero, d = 1;
3174
;                        if (cdigits == 0) --clead;
3175
;                     }
3176
;                     else
3177
;                     {
3178
;                        while (cdigits > 0 && d > 9)
3179
;                        {
3180
;                           int ch = *--ascii;
3181
3182
 
3183
;                              ++exp_b10;
3184
3185
 
3186
;                           {
3187
;                              ch = *--ascii, ++size;
3188
;                              /* Advance exp_b10 to '1', so that the
3189
;                               * decimal point happens after the
3190
;                               * previous digit.
3191
3192
 
3193
;                           }
3194
3195
 
3196
;                           d = ch - 47;  /* I.e. 1+(ch-48) */
3197
;                        }
3198
3199
 
3200
;                         * exponent but take into account the leading
3201
;                         * decimal point.
3202
3203
 
3204
;                        {
3205
;                           if (exp_b10 == (-1))
3206
;                           {
3207
		; Leading decimal point (plus zeros?), if
3208
		; we lose the decimal point here it must
3209
		; be reentered below.
3210
3211
 
3212
3213
 
3214
;                                 ++size, exp_b10 = 1;
3215
3216
 
3217
;                               * still ok at (-1)
3218
3219
 
3220
;                           else
3221
;                              ++exp_b10;
3222
3223
 
3224
;                           d = 1;
3225
;                        }
3226
;                     }
3227
;                  }
3228
;                  fp = 0; /* Guarantees termination below. */
3229
;               }
3230
3231
 
3232
;               {
3233
;                  ++czero;
3234
;                  if (cdigits == 0) ++clead;
3235
;               }
3236
;               else
3237
;               {
3238
;                  /* Included embedded zeros in the digit count. */
3239
;                  cdigits += czero - clead;
3240
;                  clead = 0;
3241
3242
 
3243
;                  {
3244
		; exp_b10 == (-1) means we just output the decimal
3245
		; place - after the DP don't adjust 'exp_b10' any
3246
		; more!
3247
3248
 
3249
;                     {
3250
;                        if (exp_b10 == 0) *ascii++ = 46, --size;
3251
;                        /* PLUS 1: TOTAL 4 */
3252
;                        --exp_b10;
3253
;                     }
3254
;                     *ascii++ = 48, --czero;
3255
;                  }
3256
3257
 
3258
;                  {
3259
;                     if (exp_b10 == 0)
3260
;                        *ascii++ = 46, --size; /* counted above */
3261
3262
 
3263
;                  }
3264
;                  *ascii++ = (char)(48 + (int)d), ++cdigits;
3265
;               }
3266
;            }
3267
;            while (cdigits+czero < precision+clead && fp > DBL_MIN);
3268
3269
 
3270
3271
 
3272
	; done and just need to terminate the string.  At
3273
	; this point exp_b10==(-1) is effectively if flag - it got
3274
	; to '-1' because of the decrement after outputting
3275
	; the decimal point above (the exponent required is
3276
	; *not* -1!)
3277
3278
 
3279
;            {
3280
		; The following only happens if we didn't output the
3281
		; leading zeros above for negative exponent, so this
3282
		; doesn't add to the digit requirement.  Note that the
3283
		; two zeros here can only be output if the two leading
3284
		; zeros were *not* output, so this doesn't increase
3285
		; the output count.
3286
3287
 
3288
3289
 
3290
3291
 
3292
		; 5+precision - see check at the start.
3293
3294
 
3295
;            }
3296
3297
 
3298
	; the digits we output but did not count.  The total
3299
	; digit output here so far is at most 1+precision - no
3300
	; decimal point and no leading or trailing zeros have
3301
	; been output.
3302
3303
 
3304
;
3305
;            *ascii++ = 69, --size;    /* 'E': PLUS 1 TOTAL 2+precision */
3306
3307
 
3308
	; the signed arithmetic on exp_b10 and permits GCC at least to do
3309
	; better optimization.
3310
3311
 
3312
;               uint uexp_b10;
3313
3314
 
3315
;               {
3316
;                  *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
3317
;                  uexp_b10 = -exp_b10;
3318
;               }
3319
3320
 
3321
;                  uexp_b10 = exp_b10;
3322
3323
 
3324
3325
 
3326
;               {
3327
;                  exponent[cdigits++] = (char)(48 + uexp_b10 % 10);
3328
;                  uexp_b10 /= 10;
3329
;               }
3330
;            }
3331
3332
 
3333
	; this need not be considered above.
3334
3335
 
3336
;            {
3337
;               while (cdigits > 0) *ascii++ = exponent[--cdigits];
3338
3339
 
3340
3341
 
3342
;            }
3343
;         }
3344
;      }
3345
;      else if (!(fp >= DBL_MIN))
3346
;      {
3347
;         *ascii++ = 48; /* '0' */
3348
;         *ascii = 0;
3349
;         return;
3350
;      }
3351
;      else
3352
;      {
3353
;         *ascii++ = 105; /* 'i' */
3354
;         *ascii++ = 110; /* 'n' */
3355
;         *ascii++ = 102; /* 'f' */
3356
;         *ascii = 0;
3357
;         return;
3358
;      }
3359
;   }
3360
3361
 
3362
;   png_error(png_ptr, "ASCII conversion buffer too small");
3363
	ret
3364
endp
3365
3366
 
3367
3368
 
3369
3370
 
3371
align 4
3372
proc png_ascii_from_fixed, png_ptr:dword, ascii:dword, size:dword, fp:dword
3373
	; Require space for 10 decimal digits, a decimal point, a minus sign and a
3374
	; trailing \0, 13 characters:
3375
3376
 
3377
	jle .end0 ;if (..>..)
3378
;      uint_32 num;
3379
3380
 
3381
;      if (fp < 0)
3382
;         *ascii++ = 45, num = -fp;
3383
;      else
3384
;         num = fp;
3385
3386
 
3387
;      {
3388
;         uint ndigits = 0, first = 16 /* flag value */;
3389
;         char digits[10];
3390
3391
 
3392
;         {
3393
	; Split the low digit off num:
3394
;            uint tmp = num/10;
3395
;            num -= tmp*10;
3396
;            digits[ndigits++] = (char)(48 + num);
3397
	; Record the first non-zero digit, note that this is a number
3398
	; starting at 1, it's not actually the array index.
3399
3400
 
3401
;               first = ndigits;
3402
;            num = tmp;
3403
;         }
3404
3405
 
3406
;         {
3407
;            while (ndigits > 5) *ascii++ = digits[--ndigits];
3408
	; The remaining digits are fractional digits, ndigits is '5' or
3409
	; smaller at this point.  It is certainly not zero.  Check for a
3410
	; non-zero fractional digit:
3411
3412
 
3413
;            {
3414
;               uint i;
3415
;               *ascii++ = 46; /* decimal point */
3416
	; ndigits may be <5 for small numbers, output leading zeros
3417
	; then ndigits digits to first:
3418
3419
 
3420
;               while (ndigits < i) *ascii++ = 48, --i;
3421
;               while (ndigits >= first) *ascii++ = digits[--ndigits];
3422
	; Don't output the trailing zeros!
3423
;            }
3424
;         }
3425
;         else
3426
;            *ascii++ = 48;
3427
3428
 
3429
;         *ascii = 0;
3430
;         return;
3431
;      }
3432
	.end0:
3433
3434
 
3435
	png_error [png_ptr], 'ASCII conversion buffer too small'
3436
	ret
3437
endp
3438
;end if /* SCAL */
3439
3440
 
3441
align 4
3442
proc png_fixed, png_ptr:dword, fp:dword, text:dword
3443
;   double r = floor(100000 * fp + .5);
3444
3445
 
3446
;      png_fixed_error(png_ptr, text);
3447
3448
 
3449
	ret
3450
endp
3451
3452
 
3453
; This API takes signed arguments and rounds the result to the nearest
3454
; integer (or, for a fixed point number - the standard argument - to
3455
; the nearest .00001).  Overflow and divide by zero are signalled in
3456
; the result, a boolean - true on success, false on overflow.
3457
3458
 
3459
align 4
3460
proc png_muldiv, res:dword, a:dword, p3times:dword, divisor:dword
3461
	; Return a * times / divisor, rounded.
3462
;   if (divisor != 0)
3463
;   {
3464
;      if (a == 0 || p3times == 0)
3465
;      {
3466
;         *res = 0;
3467
;         return 1;
3468
;      }
3469
;      else
3470
;      {
3471
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3472
;         double r = a;
3473
;         r *= p3times;
3474
;         r /= divisor;
3475
;         r = floor(r+.5);
3476
3477
 
3478
;         if (r <= 2147483647. && r >= -2147483648.)
3479
;         {
3480
;            *res = (png_fixed_point)r;
3481
;            return 1;
3482
;         }
3483
else
3484
;         int negative = 0;
3485
;         uint_32 A, T, D;
3486
;         uint_32 s16, s32, s00;
3487
3488
 
3489
;            negative = 1, A = -a;
3490
;         else
3491
;            A = a;
3492
3493
 
3494
;            negative = !negative, T = -p3times;
3495
;         else
3496
;            T = p3times;
3497
3498
 
3499
;            negative = !negative, D = -divisor;
3500
;         else
3501
;            D = divisor;
3502
3503
 
3504
	; have 31 bits each, however the result may be 32 bits.
3505
3506
 
3507
;                           (A & 0xffff) * (T >> 16);
3508
	; Can't overflow because the a*times bit is only 30
3509
	; bits at most.
3510
3511
 
3512
;         s00 = (A & 0xffff) * (T & 0xffff);
3513
3514
 
3515
;         s00 += s16;
3516
3517
 
3518
;            ++s32; /* carry */
3519
3520
 
3521
;         {
3522
	; s32.s00 is now the 64-bit product, do a standard
3523
	; division, we know that s32 < D, so the maximum
3524
	; required shift is 31.
3525
3526
 
3527
;            png_fixed_point result = 0; /* NOTE: signed */
3528
3529
 
3530
;            {
3531
;               uint_32 d32, d00;
3532
3533
 
3534
;                  d32 = D >> (32-bitshift), d00 = D << bitshift;
3535
3536
 
3537
;                  d32 = 0, d00 = D;
3538
3539
 
3540
;               {
3541
;                  if (s00 < d00) --s32; /* carry */
3542
;                  s32 -= d32, s00 -= d00, result += 1<
3543
;               }
3544
3545
 
3546
;                  if (s32 == d32 && s00 >= d00)
3547
;                     s32 = 0, s00 -= d00, result += 1<
3548
;            }
3549
3550
 
3551
;            if (s00 >= (D >> 1))
3552
;               ++result;
3553
3554
 
3555
;               result = -result;
3556
3557
 
3558
;            if ((negative != 0 && result <= 0) ||
3559
;                (negative == 0 && result >= 0))
3560
;            {
3561
;               *res = result;
3562
;               return 1;
3563
;            }
3564
;         }
3565
end if
3566
;      }
3567
;   }
3568
3569
 
3570
	ret
3571
endp
3572
3573
 
3574
; result.
3575
3576
 
3577
;    int_32 divisor)
3578
align 4
3579
proc png_muldiv_warn, png_ptr:dword, a:dword, p3times:dword, divisor:dword
3580
;   png_fixed_point result;
3581
3582
 
3583
;      return result;
3584
3585
 
3586
	xor eax,eax
3587
	ret
3588
endp
3589
3590
 
3591
;png_fixed_point (png_fixed_point a)
3592
align 4
3593
proc png_reciprocal, a:dword
3594
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3595
;   double r = floor(1E10/a+.5);
3596
3597
 
3598
;      return (png_fixed_point)r;
3599
else
3600
;   png_fixed_point res;
3601
3602
 
3603
;      return res;
3604
end if
3605
3606
 
3607
	ret
3608
endp
3609
3610
 
3611
; it is worth doing gamma correction.
3612
3613
 
3614
align 4
3615
proc png_gamma_significant, gamma_val:dword
3616
;   return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
3617
;       gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
3618
	ret
3619
endp
3620
3621
 
3622
; A local convenience routine.
3623
;png_fixed_point (png_fixed_point a, png_fixed_point b)
3624
align 4
3625
proc png_product2, a:dword, b:dword
3626
	; The required result is 1/a * 1/b; the following preserves accuracy.
3627
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3628
;   double r = a * 1E-5;
3629
;   r *= b;
3630
;   r = floor(r+.5);
3631
3632
 
3633
;      return (png_fixed_point)r;
3634
else
3635
;   png_fixed_point res;
3636
3637
 
3638
;      return res;
3639
end if
3640
3641
 
3642
	ret
3643
endp
3644
3645
 
3646
;png_fixed_point (png_fixed_point a, png_fixed_point b)
3647
align 4
3648
proc png_reciprocal2, a:dword, b:dword
3649
	; The required result is 1/a * 1/b; the following preserves accuracy.
3650
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3651
;   if (a != 0 && b != 0)
3652
;   {
3653
;      double r = 1E15/a;
3654
;      r /= b;
3655
;      r = floor(r+.5);
3656
;
3657
;      if (r <= 2147483647. && r >= -2147483648.)
3658
;         return (png_fixed_point)r;
3659
;   }
3660
else
3661
	; This may overflow because the range of png_fixed_point isn't symmetric,
3662
	; but this API is only used for the product of file and screen gamma so it
3663
	; doesn't matter that the smallest number it can produce is 1/21474, not
3664
	; 1/100000
3665
3666
 
3667
3668
 
3669
;      return png_reciprocal(res);
3670
end if
3671
3672
 
3673
	ret
3674
endp
3675
;end if /* READ_GAMMA */
3676
3677
 
3678
;#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
3679
; Fixed point gamma.
3680
3681
 
3682
; contrib/tools/intgamma.sh
3683
3684
 
3685
; fixed point arithmetic.  This code has sufficient precision for either 8-bit
3686
; or 16-bit sample values.
3687
3688
 
3689
; precision floating point arithmetic would work fine.
3690
3691
 
3692
;   This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
3693
;   255, so it's the base 2 logarithm of a normalized 8-bit floating point
3694
;   mantissa.  The numbers are 32-bit fractions.
3695
3696
 
3697
;png_8bit_l2[128] =
3698
;   4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
3699
;   3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
3700
;   3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
3701
;   3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
3702
;   3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
3703
;   2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
3704
;   2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
3705
;   2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
3706
;   2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
3707
;   2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
3708
;   1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
3709
;   1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
3710
;   1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
3711
;   1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
3712
;   1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
3713
;   971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
3714
;   803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
3715
;   639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
3716
;   479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
3717
;   324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
3718
;   172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
3719
;   24347096U, 0U
3720
3721
 
3722
	; The following are the values for 16-bit tables - these work fine for the
3723
	; 8-bit conversions but produce very slightly larger errors in the 16-bit
3724
	; log (about 1.2 as opposed to 0.7 absolute error in the final value).  To
3725
	; use these all the shifts below must be adjusted appropriately.
3726
3727
 
3728
;   57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
3729
;   50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
3730
;   43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
3731
;   37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
3732
;   31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
3733
;   25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
3734
;   20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
3735
;   15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
3736
;   10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
3737
;   6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
3738
;   1119, 744, 372
3739
end if
3740
3741
 
3742
align 4
3743
proc png_log8bit, x:dword
3744
;   uint lg2 = 0;
3745
	; Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
3746
	; because the log is actually negate that means adding 1.  The final
3747
	; returned value thus has the range 0 (for 255 input) to 7.994 (for 1
3748
	; input), return -1 for the overflow (log 0) case, - so the result is
3749
	; always at most 19 bits.
3750
3751
 
3752
;      return -1;
3753
3754
 
3755
;      lg2  = 4, x <<= 4;
3756
3757
 
3758
;      lg2 += 2, x <<= 2;
3759
3760
 
3761
;      lg2 += 1, x <<= 1;
3762
3763
 
3764
;   return (int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));
3765
	ret
3766
endp
3767
3768
 
3769
; for 16-bit images we use the most significant 8 bits of the 16-bit value to
3770
; get an approximation then multiply the approximation by a correction factor
3771
; determined by the remaining up to 8 bits.  This requires an additional step
3772
; in the 16-bit case.
3773
3774
 
3775
3776
 
3777
;          = v' * f
3778
3779
 
3780
; to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
3781
; than 258.  The final factor also needs to correct for the fact that our 8-bit
3782
; value is scaled by 255, whereas the 16-bit values must be scaled by 65535.
3783
3784
 
3785
; scaling by 65536 to match the above table:
3786
3787
 
3788
3789
 
3790
; interpolation between the two end values 256/257 (result -368.61) and 258/257
3791
; (result 367.179).  The values used below are scaled by a further 64 to give
3792
; 16-bit precision in the interpolation:
3793
3794
 
3795
; Zero  (257):      0
3796
; End   (258):  23499
3797
3798
 
3799
align 4
3800
proc png_log16bit, x:dword
3801
;   uint lg2 = 0;
3802
3803
 
3804
;   if ((x &= 0xffff) == 0)
3805
;      return -1;
3806
3807
 
3808
;      lg2  = 8, x <<= 8;
3809
3810
 
3811
;      lg2 += 4, x <<= 4;
3812
3813
 
3814
;      lg2 += 2, x <<= 2;
3815
3816
 
3817
;      lg2 += 1, x <<= 1;
3818
3819
 
3820
	; value.
3821
3822
 
3823
;   lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;
3824
3825
 
3826
	; 8 bits.  Do this with maximum precision.
3827
3828
 
3829
3830
 
3831
	; the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly
3832
	; 16 bits to interpolate to get the low bits of the result.  Round the
3833
	; answer.  Note that the end point values are scaled by 64 to retain overall
3834
	; precision and that 'lg2' is current scaled by an extra 12 bits, so adjust
3835
	; the overall scaling by 6-12.  Round at every step.
3836
3837
 
3838
3839
 
3840
;      lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);
3841
3842
 
3843
;      lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
3844
3845
 
3846
;   return (int_32)((lg2 + 2048) >> 12);
3847
	ret
3848
endp
3849
3850
 
3851
; logarithmic value and returning a 16 or 8-bit number as appropriate.  In
3852
; each case only the low 16 bits are relevant - the fraction - since the
3853
; integer bits (the top 4) simply determine a shift.
3854
3855
 
3856
; requires perhaps spurious accuracy in the decoding of the logarithm to
3857
; distinguish log2(65535/65534.5) - 10^-5 or 17 bits.  There is little chance
3858
; of getting this accuracy in practice.
3859
3860
 
3861
; frational part of the logarithm by using an accurate 32-bit value from the
3862
; top four fractional bits then multiplying in the remaining bits.
3863
3864
 
3865
align 4
3866
png_32bit_exp dd 4294967295, 4112874773, 3938502376, 3771522796, 3611622603, 3458501653,\
3867
	3311872529, 3171459999, 3037000500, 2908241642, 2784941738, 2666869345,\
3868
	2553802834, 2445529972, 2341847524, 2242560872
3869
3870
 
3871
;#if 0
3872
;for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
3873
;   11 44937.64284865548751208448
3874
;   10 45180.98734845585101160448
3875
;    9 45303.31936980687359311872
3876
;    8 45364.65110595323018870784
3877
;    7 45395.35850361789624614912
3878
;    6 45410.72259715102037508096
3879
;    5 45418.40724413220722311168
3880
;    4 45422.25021786898173001728
3881
;    3 45424.17186732298419044352
3882
;    2 45425.13273269940811464704
3883
;    1 45425.61317555035558641664
3884
;    0 45425.85339951654943850496
3885
;end if
3886
3887
 
3888
align 4
3889
proc png_exp, x:dword
3890
;   if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
3891
;   {
3892
	; Obtain a 4-bit approximation
3893
;      uint_32 e = png_32bit_exp[(x >> 12) & 0x0f];
3894
3895
 
3896
	; multiplying by a number less than 1 if the bit is set.  The multiplier
3897
	; is determined by the above table and the shift. Notice that the values
3898
	; converge on 45426 and this is used to allow linear interpolation of the
3899
	; low bits.
3900
3901
 
3902
;         e -= (((e >> 16) * 44938U) +  16U) >> 5;
3903
3904
 
3905
;         e -= (((e >> 16) * 45181U) +  32U) >> 6;
3906
3907
 
3908
;         e -= (((e >> 16) * 45303U) +  64U) >> 7;
3909
3910
 
3911
;         e -= (((e >> 16) * 45365U) + 128U) >> 8;
3912
3913
 
3914
;         e -= (((e >> 16) * 45395U) + 256U) >> 9;
3915
3916
 
3917
;         e -= (((e >> 16) * 45410U) + 512U) >> 10;
3918
3919
 
3920
;      e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
3921
3922
 
3923
;      e >>= x >> 16;
3924
;      return e;
3925
;   }
3926
3927
 
3928
;   if (x <= 0)
3929
;      return png_32bit_exp[0];
3930
3931
 
3932
;   return 0;
3933
	ret
3934
endp
3935
3936
 
3937
align 4
3938
proc png_exp8bit, lg2:dword
3939
	; Get a 32-bit value:
3940
;   uint_32 x = png_exp(lg2);
3941
3942
 
3943
	; second, rounding, step can't overflow because of the first, subtraction,
3944
	; step.
3945
3946
 
3947
;   return (byte)(((x + 0x7fffffU) >> 24) & 0xff);
3948
	ret
3949
endp
3950
3951
 
3952
align 4
3953
proc png_exp16bit, lg2:dword
3954
	; Get a 32-bit value:
3955
;   uint_32 x = png_exp(lg2);
3956
3957
 
3958
;   x -= x >> 16;
3959
;   return (uint_16)((x + 32767U) >> 16);
3960
	ret
3961
endp
3962
;end if /* FLOATING_ARITHMETIC */
3963
3964
 
3965
align 4
3966
proc png_gamma_8bit_correct, value:dword, gamma_val:dword
3967
;   if (value > 0 && value < 255)
3968
;   {
3969
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
3970
	; 'value' is unsigned, ANSI-C90 requires the compiler to correctly
3971
	; convert this to a floating point value.  This includes values that
3972
	; would overflow if 'value' were to be converted to 'int'.
3973
3974
 
3975
	; on some (ARM) but not all (x86) platforms, possibly because of
3976
	; hardware FP limitations.  (E.g. if the hardware conversion always
3977
	; assumes the integer register contains a signed value.)  This results
3978
	; in ANSI-C undefined behavior for large values.
3979
3980
 
3981
	; conformant and therefore compile spurious extra code for the large
3982
	; values.
3983
3984
 
3985
	; won't be faster than an int to float one.  Therefore this code
3986
	; assumes responsibility for the undefined behavior, which it knows
3987
	; can't happen because of the check above.
3988
3989
 
3990
	; 16-bit platforms, it is assigned a value which might be out of
3991
	; range for an (int); that would result in undefined behavior in the
3992
	; caller if the *argument* ('value') were to be declared (int).
3993
3994
 
3995
;         return (byte)r;
3996
else
3997
;         int_32 lg2 = png_log8bit(value);
3998
;         png_fixed_point res;
3999
4000
 
4001
;            return png_exp8bit(res);
4002
4003
 
4004
;         value = 0;
4005
end if
4006
;   }
4007
4008
 
4009
	ret
4010
endp
4011
4012
 
4013
align 4
4014
proc png_gamma_16bit_correct, value:dword, gamma_val:dword
4015
;   if (value > 0 && value < 65535)
4016
;   {
4017
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
4018
	; The same (uint)->(double) constraints apply here as above,
4019
	; however in this case the (uint) to (int) conversion can
4020
	; overflow on an ANSI-C90 compliant system so the cast needs to ensure
4021
	; that this is not possible.
4022
4023
 
4024
;          gamma_val*.00001)+.5);
4025
;      return (uint_16)r;
4026
else
4027
;      int_32 lg2 = png_log16bit(value);
4028
;      png_fixed_point res;
4029
4030
 
4031
;         return png_exp16bit(res);
4032
4033
 
4034
;      value = 0;
4035
end if
4036
;   }
4037
4038
 
4039
	ret
4040
endp
4041
4042
 
4043
; png_struct, interpreting values as 8-bit or 16-bit.  While the result
4044
; is nominally a 16-bit value if bit depth is 8 then the result is
4045
; 8-bit (as are the arguments.)
4046
4047
 
4048
align 4
4049
proc png_gamma_correct, png_ptr:dword, value:dword, gamma_val:dword
4050
;   if (png_ptr->bit_depth == 8)
4051
;      return png_gamma_8bit_correct(value, gamma_val);
4052
;
4053
if PNG_16BIT_SUPPORTED eq 1
4054
;   else
4055
;      return png_gamma_16bit_correct(value, gamma_val);
4056
else
4057
	; should not reach this
4058
	xor eax,eax
4059
end if ;16BIT
4060
.end_f:
4061
	ret
4062
endp
4063
4064
 
4065
; Internal function to build a single 16-bit table - the table consists of
4066
; 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
4067
; to shift the input values right (or 16-number_of_signifiant_bits).
4068
4069
 
4070
; png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument
4071
; should be somewhere that will be cleaned.
4072
4073
 
4074
align 4
4075
proc png_build_16bit_table, png_ptr:dword, ptable:dword, shift:dword, gamma_val:dword
4076
	; Various values derived from 'shift':
4077
;    uint num = 1U << (8U - shift);
4078
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
4079
	; CSE the division and work round wacky GCC warnings (see the comments
4080
	; in png_gamma_8bit_correct for where these come from.)
4081
4082
 
4083
end if
4084
;    uint max = (1U << (16U - shift))-1U;
4085
;    uint max_by_2 = 1U << (15U-shift);
4086
;   uint i;
4087
4088
 
4089
;       (uint_16pp)png_calloc(png_ptr, num * (sizeof (uint_16p)));
4090
4091
 
4092
;   {
4093
;      uint_16p sub_table = table[i] =
4094
;          (uint_16p)png_malloc(png_ptr, 256 * (sizeof (uint_16)));
4095
4096
 
4097
	; the 16-bit tables even if the others don't hit it.
4098
4099
 
4100
;      {
4101
	; The old code would overflow at the end and this would cause the
4102
	; 'pow' function to return a result >1, resulting in an
4103
	; arithmetic error.  This code follows the spec exactly; ig is
4104
	; the recovered input sample, it always has 8-16 bits.
4105
4106
 
4107
	; bits (unsigned) so long as max <= 32767.
4108
4109
 
4110
;         for (j = 0; j < 256; j++)
4111
;         {
4112
;            uint_32 ig = (j << (8-shift)) + i;
4113
if PNG_FLOATING_ARITHMETIC_SUPPORTED eq 1
4114
		; Inline the 'max' scaling operation:
4115
		; See png_gamma_8bit_correct for why the cast to (int) is
4116
		; required here.
4117
4118
 
4119
;               sub_table[j] = (uint_16)d;
4120
else
4121
;               if (shift != 0)
4122
;                  ig = (ig * 65535U + max_by_2)/max;
4123
;
4124
;               sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
4125
end if
4126
;         }
4127
;      }
4128
;      else
4129
;      {
4130
		; We must still build a table, but do it the fast way.
4131
;         uint j;
4132
;
4133
;         for (j = 0; j < 256; j++)
4134
;         {
4135
;            uint_32 ig = (j << (8-shift)) + i;
4136
;
4137
;            if (shift != 0)
4138
;               ig = (ig * 65535U + max_by_2)/max;
4139
;
4140
;            sub_table[j] = (uint_16)ig;
4141
;         }
4142
;      }
4143
;   }
4144
	ret
4145
endp
4146
4147
 
4148
; required.
4149
4150
 
4151
align 4
4152
proc png_build_16to8_table, png_ptr:dword, ptable:dword, shift:dword, gamma_val:dword
4153
;   uint num = 1U << (8U - shift);
4154
;   uint max = (1U << (16U - shift))-1U;
4155
;   uint i;
4156
;   uint_32 last;
4157
4158
 
4159
;       (uint_16pp)png_calloc(png_ptr, num * (sizeof (uint_16p)));
4160
4161
 
4162
	; bits of the input 16-bit value used to select a table.  Each table is
4163
	; itself indexed by the high 8 bits of the value.
4164
4165
 
4166
;      table[i] = (uint_16p)png_malloc(png_ptr,
4167
;          256 * (sizeof (uint_16)));
4168
4169
 
4170
	; pow(out,g) is an *input* value.  'last' is the last input value set.
4171
	;
4172
	; In the loop 'i' is used to find output values.  Since the output is
4173
	; 8-bit there are only 256 possible values.  The tables are set up to
4174
	; select the closest possible output value for each input by finding
4175
	; the input value at the boundary between each pair of output values
4176
	; and filling the table up to that boundary with the lower output
4177
	; value.
4178
4179
 
4180
	; values the code below uses a 16-bit value in i; the values start at
4181
	; 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
4182
	; entries are filled with 255).  Start i at 128 and fill all 'last'
4183
	; table entries <= 'max'
4184
4185
 
4186
;   for (i = 0; i < 255; ++i) /* 8-bit output value */
4187
;   {
4188
	; Find the corresponding maximum input value
4189
;      uint_16 out = (uint_16)(i * 257U); /* 16-bit output value */
4190
4191
 
4192
;      uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);
4193
4194
 
4195
;      bound = (bound * max + 32768U)/65535U + 1U;
4196
;
4197
;      while (last < bound)
4198
;      {
4199
;         table[last & (0xffU >> shift)][last >> (8U - shift)] = out;
4200
;         last++;
4201
;      }
4202
;   }
4203
4204
 
4205
;   while (last < (num << 8))
4206
;   {
4207
;      table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;
4208
;      last++;
4209
;   }
4210
	ret
4211
endp
4212
;end if /* 16BIT */
4213
4214
 
4215
; typically much faster).  Note that libpng currently does no sBIT processing
4216
; (apparently contrary to the spec) so a 256-entry table is always generated.
4217
4218
 
4219
align 4
4220
proc png_build_8bit_table, png_ptr:dword, ptable:dword, gamma_val:dword
4221
;   uint i;
4222
;   bytep table = *ptable = (bytep)png_malloc(png_ptr, 256);
4223
4224
 
4225
;      for (i=0; i<256; i++)
4226
;         table[i] = png_gamma_8bit_correct(i, gamma_val);
4227
4228
 
4229
;      for (i=0; i<256; ++i)
4230
;         table[i] = (byte)(i & 0xff);
4231
	ret
4232
endp
4233
4234
 
4235
; tables.
4236
4237
 
4238
align 4
4239
proc png_destroy_gamma_table, png_ptr:dword
4240
;   png_free(png_ptr, png_ptr->gamma_table);
4241
;   png_ptr->gamma_table = NULL;
4242
4243
 
4244
;   if (png_ptr->gamma_16_table != NULL)
4245
;   {
4246
;      int i;
4247
;      int istop = (1 << (8 - png_ptr->gamma_shift));
4248
;      for (i = 0; i < istop; i++)
4249
;      {
4250
;         png_free(png_ptr, png_ptr->gamma_16_table[i]);
4251
;      }
4252
;   png_free(png_ptr, png_ptr->gamma_16_table);
4253
;   png_ptr->gamma_16_table = NULL;
4254
;   }
4255
end if ;16BIT
4256
4257
 
4258
;   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
4259
;   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4260
;   png_free(png_ptr, png_ptr->gamma_from_1);
4261
;   png_ptr->gamma_from_1 = NULL;
4262
;   png_free(png_ptr, png_ptr->gamma_to_1);
4263
;   png_ptr->gamma_to_1 = NULL;
4264
4265
 
4266
;   if (png_ptr->gamma_16_from_1 != NULL)
4267
;   {
4268
;      int i;
4269
;      int istop = (1 << (8 - png_ptr->gamma_shift));
4270
;      for (i = 0; i < istop; i++)
4271
;      {
4272
;         png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
4273
;      }
4274
;   png_free(png_ptr, png_ptr->gamma_16_from_1);
4275
;   png_ptr->gamma_16_from_1 = NULL;
4276
;   }
4277
;   if (png_ptr->gamma_16_to_1 != NULL)
4278
;   {
4279
;      int i;
4280
;      int istop = (1 << (8 - png_ptr->gamma_shift));
4281
;      for (i = 0; i < istop; i++)
4282
;      {
4283
;         png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
4284
;      }
4285
;   png_free(png_ptr, png_ptr->gamma_16_to_1);
4286
;   png_ptr->gamma_16_to_1 = NULL;
4287
;   }
4288
end if ;16BIT
4289
;end if /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
4290
	ret
4291
endp
4292
4293
 
4294
; tables, we don't make a full table if we are reducing to 8-bit in
4295
; the future.  Note also how the gamma_16 tables are segmented so that
4296
; we don't need to allocate > 64K chunks for a full 16-bit table.
4297
4298
 
4299
align 4
4300
proc png_build_gamma_table, png_ptr:dword, bit_depth:dword
4301
	png_debug 1, 'in png_build_gamma_table'
4302
4303
 
4304
	; png_read_update_info. The warning is because building the gamma tables
4305
	; multiple times is a performance hit - it's harmless but the ability to
4306
	; call png_read_update_info() multiple times is new in 1.5.6 so it seems
4307
	; sensible to warn if the app introduces such a hit.
4308
4309
 
4310
;   {
4311
;      png_warning(png_ptr, "gamma table being rebuilt");
4312
;      png_destroy_gamma_table(png_ptr);
4313
;   }
4314
4315
 
4316
;   {
4317
;      png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
4318
;          png_ptr->screen_gamma > 0 ?
4319
;          png_reciprocal2(png_ptr->colorspace.gamma,
4320
;          png_ptr->screen_gamma) : PNG_FP_1);
4321
;
4322
if (PNG_READ_BACKGROUND_SUPPORTED eq 1) | (PNG_READ_ALPHA_MODE_SUPPORTED eq 1) | (PNG_READ_RGB_TO_GRAY_SUPPORTED eq 1)
4323
;      if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
4324
;      {
4325
;         png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
4326
;             png_reciprocal(png_ptr->colorspace.gamma));
4327
;
4328
;         png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
4329
;             png_ptr->screen_gamma > 0 ?
4330
;             png_reciprocal(png_ptr->screen_gamma) :
4331
;             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
4332
;      }
4333
end if ;READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY
4334
;   }
4335
if PNG_16BIT_SUPPORTED eq 1
4336
;   else
4337
;   {
4338
;      byte shift, sig_bit;
4339
;
4340
;      if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
4341
;      {
4342
;         sig_bit = png_ptr->sig_bit.red;
4343
;
4344
;         if (png_ptr->sig_bit.green > sig_bit)
4345
;            sig_bit = png_ptr->sig_bit.green;
4346
;
4347
;         if (png_ptr->sig_bit.blue > sig_bit)
4348
;            sig_bit = png_ptr->sig_bit.blue;
4349
;      }
4350
;      else
4351
;         sig_bit = png_ptr->sig_bit.gray;
4352
4353
 
4354
4355
 
4356
4357
 
4358
	; pow(iv, gamma).
4359
4360
 
4361
	; is selected by the (8-gamma_shift) most significant of the low 8 bits
4362
	; of the color value then indexed by the upper 8 bits:
4363
	;
4364
	;   table[low bits][high 8 bits]
4365
4366
 
4367
4368
 
4369
4370
 
4371
 
4372
;         /* shift == insignificant bits */
4373
;         shift = (byte)((16U - sig_bit) & 0xff);
4374
4375
 
4376
;         shift = 0; /* keep all 16 bits */
4377
4378
 
4379
;      {
4380
	; PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
4381
	; the significant bits in the *input* when the output will
4382
	; eventually be 8 bits.  By default it is 11.
4383
4384
 
4385
;            shift = (16U - PNG_MAX_GAMMA_8);
4386
;      }
4387
4388
 
4389
;         shift = 8U; /* Guarantees at least one table! */
4390
4391
 
4392
4393
 
4394
	; PNG_COMPOSE).  This effectively smashed the background calculation for
4395
	; 16-bit output because the 8-bit table assumes the result will be
4396
	; reduced to 8 bits.
4397
4398
 
4399
;          png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
4400
;          png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma,
4401
;          png_ptr->screen_gamma) : PNG_FP_1);
4402
;
4403
;      else
4404
;          png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
4405
;          png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,
4406
;          png_ptr->screen_gamma) : PNG_FP_1);
4407
;
4408
if (PNG_READ_BACKGROUND_SUPPORTED eq 1) | (PNG_READ_ALPHA_MODE_SUPPORTED eq 1) | (PNG_READ_RGB_TO_GRAY_SUPPORTED eq 1)
4409
;      if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
4410
;      {
4411
;         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
4412
;             png_reciprocal(png_ptr->colorspace.gamma));
4413
4414
 
4415
	; the lookup on this table still uses gamma_shift, so it can't be.
4416
	; TODO: fix this.
4417
4418
 
4419
;             png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
4420
;             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
4421
;      }
4422
end if ;READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY
4423
;   }
4424
end if ;16BIT
4425
	ret
4426
endp
4427
;end if /* READ_GAMMA */
4428
4429
 
4430
;int (png_structrp png_ptr, int option, int onoff)
4431
align 4
4432
proc png_set_option uses ecx, png_ptr:dword, option:dword, onoff:dword
4433
	mov eax,[png_ptr]
4434
	cmp eax,0
4435
	je @f
4436
	mov ecx,[option]
4437
	cmp ecx,0
4438
	jl @f
4439
	cmp ecx,PNG_OPTION_NEXT
4440
	jge @f
4441
	bt ecx,0 ;cmp (ecx & 1), 0
4442
	jc @f ;if (..!=0 && ..>=0 && ..<.. && ..==0)
4443
;      int mask = 3 << option;
4444
;      int setting = (2 + (onoff != 0)) << option;
4445
;      int current = png_ptr->options;
4446
4447
 
4448
4449
 
4450
		jmp .end_f
4451
	@@:
4452
	mov eax,PNG_OPTION_INVALID
4453
.end_f:
4454
	ret
4455
endp
4456
4457
 
4458
if (PNG_SIMPLIFIED_READ_SUPPORTED eq 1) | (PNG_SIMPLIFIED_WRITE_SUPPORTED eq 1)
4459
; sRGB conversion tables; these are machine generated with the code in
4460
; contrib/tools/makesRGB.c.  The actual sRGB transfer curve defined in the
4461
; specification (see the article at http://en.wikipedia.org/wiki/SRGB)
4462
; is used, not the gamma=1/2.2 approximation use elsewhere in libpng.
4463
; The sRGB to linear table is exact (to the nearest 16-bit linear fraction).
4464
; The inverse (linear to sRGB) table has accuracies as follows:
4465
4466
 
4467
;    error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact
4468
4469
 
4470
;    error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact
4471
4472
 
4473
4474
 
4475
 
4476
; The convert-to-sRGB table is only currently required for read.
4477
align 4
4478
png_sRGB_table dw 0,20,40,60,80,99,119,139,\
4479
	159,179,199,219,241,264,288,313,\
4480
	340,367,396,427,458,491,526,562,\
4481
	599,637,677,718,761,805,851,898,\
4482
	947,997,1048,1101,1156,1212,1270,1330,\
4483
	1391,1453,1517,1583,1651,1720,1790,1863,\
4484
	1937,2013,2090,2170,2250,2333,2418,2504,\
4485
	2592,2681,2773,2866,2961,3058,3157,3258,\
4486
	3360,3464,3570,3678,3788,3900,4014,4129,\
4487
	4247,4366,4488,4611,4736,4864,4993,5124,\
4488
	5257,5392,5530,5669,5810,5953,6099,6246,\
4489
	6395,6547,6700,6856,7014,7174,7335,7500,\
4490
	7666,7834,8004,8177,8352,8528,8708,8889,\
4491
	9072,9258,9445,9635,9828,10022,10219,10417,\
4492
	10619,10822,11028,11235,11446,11658,11873,12090,\
4493
	12309,12530,12754,12980,13209,13440,13673,13909,\
4494
	14146,14387,14629,14874,15122,15371,15623,15878,\
4495
	16135,16394,16656,16920,17187,17456,17727,18001,\
4496
	18277,18556,18837,19121,19407,19696,19987,20281,\
4497
	20577,20876,21177,21481,21787,22096,22407,22721,\
4498
	23038,23357,23678,24002,24329,24658,24990,25325,\
4499
	25662,26001,26344,26688,27036,27386,27739,28094,\
4500
	28452,28813,29176,29542,29911,30282,30656,31033,\
4501
	31412,31794,32179,32567,32957,33350,33745,34143,\
4502
	34544,34948,35355,35764,36176,36591,37008,37429,\
4503
	37852,38278,38706,39138,39572,40009,40449,40891,\
4504
	41337,41785,42236,42690,43147,43606,44069,44534,\
4505
	45002,45473,45947,46423,46903,47385,47871,48359,\
4506
	48850,49344,49841,50341,50844,51349,51858,52369,\
4507
	52884,53401,53921,54445,54971,55500,56032,56567,\
4508
	57105,57646,58190,58737,59287,59840,60396,60955,\
4509
	61517,62082,62650,63221,63795,64372,64952,65535
4510
end if ;SIMPLIFIED_READ
4511
4512
 
4513
; only the simplified versions.)
4514
align 4
4515
png_sRGB_base dw 128,1782,3383,4644,5675,6564,7357,8074,\
4516
	8732,9346,9921,10463,10977,11466,11935,12384,\
4517
	12816,13233,13634,14024,14402,14769,15125,15473,\
4518
	15812,16142,16466,16781,17090,17393,17690,17981,\
4519
	18266,18546,18822,19093,19359,19621,19879,20133,\
4520
	20383,20630,20873,21113,21349,21583,21813,22041,\
4521
	22265,22487,22707,22923,23138,23350,23559,23767,\
4522
	23972,24175,24376,24575,24772,24967,25160,25352,\
4523
	25542,25730,25916,26101,26284,26465,26645,26823,\
4524
	27000,27176,27350,27523,27695,27865,28034,28201,\
4525
	28368,28533,28697,28860,29021,29182,29341,29500,\
4526
	29657,29813,29969,30123,30276,30429,30580,30730,\
4527
	30880,31028,31176,31323,31469,31614,31758,31902,\
4528
	32045,32186,32327,32468,32607,32746,32884,33021,\
4529
	33158,33294,33429,33564,33697,33831,33963,34095,\
4530
	34226,34357,34486,34616,34744,34873,35000,35127,\
4531
	35253,35379,35504,35629,35753,35876,35999,36122,\
4532
	36244,36365,36486,36606,36726,36845,36964,37083,\
4533
	37201,37318,37435,37551,37668,37783,37898,38013,\
4534
	38127,38241,38354,38467,38580,38692,38803,38915,\
4535
	39026,39136,39246,39356,39465,39574,39682,39790,\
4536
	39898,40005,40112,40219,40325,40431,40537,40642,\
4537
	40747,40851,40955,41059,41163,41266,41369,41471,\
4538
	41573,41675,41777,41878,41979,42079,42179,42279,\
4539
	42379,42478,42577,42676,42775,42873,42971,43068,\
4540
	43165,43262,43359,43456,43552,43648,43743,43839,\
4541
	43934,44028,44123,44217,44311,44405,44499,44592,\
4542
	44685,44778,44870,44962,45054,45146,45238,45329,\
4543
	45420,45511,45601,45692,45782,45872,45961,46051,\
4544
	46140,46229,46318,46406,46494,46583,46670,46758,\
4545
	46846,46933,47020,47107,47193,47280,47366,47452,\
4546
	47538,47623,47709,47794,47879,47964,48048,48133,\
4547
	48217,48301,48385,48468,48552,48635,48718,48801,\
4548
	48884,48966,49048,49131,49213,49294,49376,49458,\
4549
	49539,49620,49701,49782,49862,49943,50023,50103,\
4550
	50183,50263,50342,50422,50501,50580,50659,50738,\
4551
	50816,50895,50973,51051,51129,51207,51285,51362,\
4552
	51439,51517,51594,51671,51747,51824,51900,51977,\
4553
	52053,52129,52205,52280,52356,52432,52507,52582,\
4554
	52657,52732,52807,52881,52956,53030,53104,53178,\
4555
	53252,53326,53400,53473,53546,53620,53693,53766,\
4556
	53839,53911,53984,54056,54129,54201,54273,54345,\
4557
	54417,54489,54560,54632,54703,54774,54845,54916,\
4558
	54987,55058,55129,55199,55269,55340,55410,55480,\
4559
	55550,55620,55689,55759,55828,55898,55967,56036,\
4560
	56105,56174,56243,56311,56380,56448,56517,56585,\
4561
	56653,56721,56789,56857,56924,56992,57059,57127,\
4562
	57194,57261,57328,57395,57462,57529,57595,57662,\
4563
	57728,57795,57861,57927,57993,58059,58125,58191,\
4564
	58256,58322,58387,58453,58518,58583,58648,58713,\
4565
	58778,58843,58908,58972,59037,59101,59165,59230,\
4566
	59294,59358,59422,59486,59549,59613,59677,59740,\
4567
	59804,59867,59930,59993,60056,60119,60182,60245,\
4568
	60308,60370,60433,60495,60558,60620,60682,60744,\
4569
	60806,60868,60930,60992,61054,61115,61177,61238,\
4570
	61300,61361,61422,61483,61544,61605,61666,61727,\
4571
	61788,61848,61909,61969,62030,62090,62150,62211,\
4572
	62271,62331,62391,62450,62510,62570,62630,62689,\
4573
	62749,62808,62867,62927,62986,63045,63104,63163,\
4574
	63222,63281,63340,63398,63457,63515,63574,63632,\
4575
	63691,63749,63807,63865,63923,63981,64039,64097,\
4576
	64155,64212,64270,64328,64385,64443,64500,64557,\
4577
	64614,64672,64729,64786,64843,64900,64956,65013,\
4578
	65070,65126,65183,65239,65296,65352,65409,65465
4579
align 4
4580
png_sRGB_delta db 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54,\
4581
	52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36,\
4582
	35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28,\
4583
	28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24,\
4584
	23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21,\
4585
	21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,\
4586
	19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,\
4587
	17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,\
4588
	16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,\
4589
	15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,\
4590
	14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,\
4591
	13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,\
4592
	12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,\
4593
	12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,\
4594
	11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,\
4595
	11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,\
4596
	11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\
4597
	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\
4598
	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\
4599
	10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\
4600
	9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\
4601
	9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\
4602
	9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\
4603
	9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4604
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4605
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4606
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4607
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\
4608
	8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,\
4609
	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\
4610
	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\
4611
	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
4612
4613
 
4614
4615
 
4616
;int (voidp argument)
4617
align 4
4618
proc png_image_free_function uses ebx ecx edi esi, argument:dword
4619
locals
4620
;   png_imagep image = argument;
4621
;   png_controlp cp = image->opaque;
4622
	c png_control
4623
endl
4624
	; Double check that we have a png_ptr - it should be impossible to get here
4625
	; without one.
4626
4627
 
4628
	mov esi,[ebx+png_image.opaque] ;esi = cp
4629
	cmp dword[esi+png_control.png_ptr],0
4630
	jne @f ;if (..==0)
4631
		xor eax,eax
4632
		jmp .end_f
4633
	@@:
4634
4635
 
4636
if PNG_STDIO_SUPPORTED eq 1
4637
;      if (cp->owned_file != 0)
4638
;      {
4639
;         FILE *fp = cp->png_ptr->io_ptr;
4640
;         cp->owned_file = 0;
4641
4642
 
4643
;         if (fp != NULL)
4644
;         {
4645
;            cp->png_ptr->io_ptr = NULL;
4646
;            (void)fclose(fp);
4647
;         }
4648
;      }
4649
end if
4650
4651
 
4652
	; safely freed.  Notice that a png_error here stops the remainder of the
4653
	; cleanup, but this is probably fine because that would indicate bad memory
4654
	; problems anyway.
4655
4656
 
4657
	mov edi,ebp
4658
	sub edi,ecx ;edi = &c
4659
	rep movsb
4660
	sub edi,sizeof.png_control
4661
	sub esi,sizeof.png_control
4662
	mov dword[ebx+png_image.opaque],edi
4663
	stdcall png_free, [edi+png_control.png_ptr], esi
4664
4665
 
4666
;   if (c.for_write != 0)
4667
;   {
4668
if PNG_SIMPLIFIED_WRITE_SUPPORTED eq 1
4669
;         png_destroy_write_struct(&c.png_ptr, &c.info_ptr);
4670
else
4671
;         png_error(c.png_ptr, "simplified write not supported");
4672
end if
4673
		jmp .end2
4674
	.end1: ;else
4675
if PNG_SIMPLIFIED_READ_SUPPORTED eq 1
4676
;         png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL);
4677
else
4678
;         png_error(c.png_ptr, "simplified read not supported");
4679
end if
4680
	.end2:
4681
4682
 
4683
	xor eax,eax
4684
	inc eax
4685
.end_f:
4686
	ret
4687
endp
4688
4689
 
4690
align 4
4691
proc png_image_free uses eax ebx, image:dword
4692
	; Safely call the real function, but only if doing so is safe at this point
4693
	; (if not inside an error handling context).  Otherwise assume
4694
	; png_safe_execute will call this API after the return.
4695
4696
 
4697
	cmp ebx,0
4698
	je @f
4699
	cmp dword[ebx+png_image.opaque],0
4700
	je @f
4701
	mov eax,[ebx+png_image.opaque]
4702
	cmp dword[eax+png_control.error_buf],0
4703
	jne @f ;if (..!=0 && ..!=0 && ..==0)
4704
		; Ignore errors here:
4705
		stdcall png_safe_execute, ebx, png_image_free_function, ebx
4706
		mov dword[ebx+png_image.opaque],0
4707
	@@:
4708
	ret
4709
endp
4710
4711
 
4712
align 4
4713
proc png_image_error uses ebx, image:dword, error_message:dword
4714
	; Utility to log an error.
4715
	mov ebx,[image]
4716
	mov eax,ebx
4717
	add eax,png_image.message
4718
	stdcall png_safecat, eax, sizeof.png_image.message, 0, [error_message]
4719
	or dword[ebx+png_image.warning_or_error], PNG_IMAGE_ERROR
4720
	stdcall png_image_free, ebx
4721
	xor eax,eax
4722
	ret
4723
endp
4724
4725
 
4726
>