mirror of
				https://git.code.sf.net/p/libpng/code.git
				synced 2025-07-10 18:04:09 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			246 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			246 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <assert.h>
 | 
						|
#include <stdint.h>
 | 
						|
 | 
						|
#include "pnglibconf.h.prebuilt"
 | 
						|
#include "../pngpriv.h"
 | 
						|
 | 
						|
static const struct
 | 
						|
{
 | 
						|
   png_uint_32    name;
 | 
						|
}
 | 
						|
png_known_chunks[] =
 | 
						|
/* See pngchunk.h for how this works: */
 | 
						|
#define PNG_CHUNK_END(n, c1, c2, c3, c4, before, after)\
 | 
						|
   { png_ ##n }
 | 
						|
#define PNG_CHUNK(n, c1, c2, c3, c4, before, after)\
 | 
						|
   PNG_CHUNK_END(n, c1, c2, c3, c4, before, after),
 | 
						|
#define PNG_CHUNK_BEGIN(n, c1, c2, c3, c4, before, after)\
 | 
						|
   PNG_CHUNK_END(n, c1, c2, c3, c4, before, after),
 | 
						|
{
 | 
						|
#  include "../pngchunk.h"
 | 
						|
};
 | 
						|
 | 
						|
#define C_KNOWN ((sizeof png_known_chunks)/(sizeof png_known_chunks[0]))
 | 
						|
 | 
						|
static unsigned int
 | 
						|
index_of(png_uint_32 name)
 | 
						|
{
 | 
						|
   unsigned int i;
 | 
						|
 | 
						|
   if (name == 0)
 | 
						|
      return 0;
 | 
						|
 | 
						|
   for (i=0; i<C_KNOWN; ++i) if (png_known_chunks[i].name == name) return i;
 | 
						|
 | 
						|
   assert("not reached" && 0);
 | 
						|
}
 | 
						|
 | 
						|
static unsigned int bitorder[32];
 | 
						|
 | 
						|
#define PNG_CHUNK_HASH(n,shift,s1,s2,s3,s4,s5)\
 | 
						|
   (0x3f & (((n += n >> shift),n += n >> s1),n += n >> s2))
 | 
						|
 | 
						|
inline unsigned int hash(png_uint_32 name, unsigned int shift, unsigned int s1,
 | 
						|
   unsigned int s2, unsigned int s3, unsigned int s4, unsigned int s5)
 | 
						|
{
 | 
						|
   /* Running the search gives (shift,s1,s2) (2,8,16) */
 | 
						|
   //return PNG_CHUNK_HASH(name, shift, s1, s2, s3, s4, s5);
 | 
						|
   name += name >> shift;
 | 
						|
   name += name >> s1;
 | 
						|
   name += name >> s2;
 | 
						|
   //name += name >> s3;
 | 
						|
   return 0x3f & name;
 | 
						|
   /*return 0x3f & ((name) + (
 | 
						|
            ((name >>  bitorder[s1])    & 0x01) +
 | 
						|
            ((name >> (bitorder[s2]-1)) & 0x02) +
 | 
						|
            ((name >> (bitorder[s3]-2)) & 0x04) +
 | 
						|
            ((name >> (bitorder[s4]-3)) & 0x08) +
 | 
						|
            ((name >> (bitorder[s5]-4)) & 0x10)));*/
 | 
						|
}
 | 
						|
 | 
						|
int main(void) {
 | 
						|
   unsigned int s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0;
 | 
						|
   unsigned int shift = 0;
 | 
						|
   png_uint_32 mask;
 | 
						|
   unsigned int bitcount;
 | 
						|
   unsigned int mineq;
 | 
						|
   png_uint_32 sarray;
 | 
						|
   unsigned int shift_save;
 | 
						|
   png_uint_32 reverse_index_save[64];
 | 
						|
 | 
						|
   assert(C_KNOWN <= 64);
 | 
						|
 | 
						|
   /* Check IDAT: */
 | 
						|
   assert(index_of(png_IDAT) == 0);
 | 
						|
 | 
						|
   /* Build a mask of all the bits that differ in at least one of the known
 | 
						|
    * names.
 | 
						|
    */
 | 
						|
   {
 | 
						|
      png_uint_32 set, unset;
 | 
						|
      int i;
 | 
						|
 | 
						|
      for (i=0, set=unset=0; i<C_KNOWN; ++i)
 | 
						|
      {
 | 
						|
         set |= png_known_chunks[i].name;
 | 
						|
         unset |= ~png_known_chunks[i].name;
 | 
						|
      }
 | 
						|
 | 
						|
      mask = set ^ ~unset;
 | 
						|
   }
 | 
						|
 | 
						|
   //printf("C_KNOWN = %lu, 0x%.8x\n", C_KNOWN, mask);
 | 
						|
 | 
						|
   assert(mask == 0x3f1f1f3f);
 | 
						|
 | 
						|
   /* Print the bit array */
 | 
						|
   {
 | 
						|
      unsigned int i;
 | 
						|
      unsigned int ones[32];
 | 
						|
 | 
						|
      memset(ones, 0, sizeof ones);
 | 
						|
 | 
						|
      for (i=0; i<C_KNOWN; ++i)
 | 
						|
      {
 | 
						|
         png_uint_32 name = png_known_chunks[i].name;
 | 
						|
         int j, k;
 | 
						|
         char s[5], b[33];
 | 
						|
 | 
						|
         PNG_CSTRING_FROM_CHUNK(s, name);
 | 
						|
         for (j=k=0; j<32; ++j)
 | 
						|
         {
 | 
						|
            if ((name >> j) & 1)
 | 
						|
               ++ones[j];
 | 
						|
 | 
						|
            if ((mask >> (31-j)) & 1)
 | 
						|
               b[k++] = ((name >> (31-j)) & 1) ? 'o' : ' ';
 | 
						|
         }
 | 
						|
 | 
						|
         b[k] = 0;
 | 
						|
 | 
						|
         //printf("%s: %s\n", s, b);
 | 
						|
      }
 | 
						|
 | 
						|
      memset(bitorder, 0, sizeof bitorder);
 | 
						|
      bitcount = 0;
 | 
						|
 | 
						|
      for (i=0; i<C_KNOWN; ++i) if (((C_KNOWN-i) & 1) == 0)
 | 
						|
      {
 | 
						|
         unsigned int lo = (C_KNOWN - i)>>1;
 | 
						|
         unsigned int hi = (C_KNOWN + i)>>1;
 | 
						|
         int j;
 | 
						|
 | 
						|
         for (j=0; j<32; ++j) if (ones[j] == lo || ones[j] == hi)
 | 
						|
         {
 | 
						|
            //printf(" %2d,", j);
 | 
						|
            bitorder[bitcount++] = j;
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      //printf("\nbitcount=%u, C_KNOWN=%lu\n", bitcount, C_KNOWN);
 | 
						|
   }
 | 
						|
 | 
						|
   /* s? are masks to exclude bits from the hash, one for each byte: */
 | 
						|
   mineq = C_KNOWN;
 | 
						|
   sarray = 0;
 | 
						|
   for (shift=0; shift<32; ++shift)
 | 
						|
   for (s1=0; s1<32; ++s1)
 | 
						|
   for (s2=s1+1; s2<32; ++s2)
 | 
						|
   //for (s3=s2+1; s3<32; ++s3)
 | 
						|
   //for (s4=s3+1; s4<bitcount; ++s4)
 | 
						|
   //for (s5=s4+1; s5<bitcount; ++s5)
 | 
						|
   {
 | 
						|
      int i, eq;
 | 
						|
      png_uint_32 reverse_index[64];
 | 
						|
 | 
						|
      memset(reverse_index, 0, sizeof reverse_index);
 | 
						|
 | 
						|
      for (i=eq=0; i<C_KNOWN; ++i)
 | 
						|
      {
 | 
						|
         png_uint_32 name = png_known_chunks[i].name;
 | 
						|
         unsigned int h = hash(name, shift, s1, s2, s3, s4, s5);
 | 
						|
 | 
						|
         if (reverse_index[h] == 0)
 | 
						|
            reverse_index[h] = name;
 | 
						|
 | 
						|
         else
 | 
						|
            ++eq;
 | 
						|
      }
 | 
						|
 | 
						|
      if (eq == 0)
 | 
						|
      {
 | 
						|
         /* Print the LUT: */
 | 
						|
         printf("static const png_byte png_chunk_lut[64] =\n{   \n   ");
 | 
						|
         for (i=0; i<63; ++i)
 | 
						|
         {
 | 
						|
            printf("%2u, ", index_of(reverse_index[i]));
 | 
						|
            if ((i+1 & 0xf) == 0) printf("\n   ");
 | 
						|
         }
 | 
						|
         printf("%2u\n};\n\n", index_of(reverse_index[63]));
 | 
						|
 | 
						|
         //printf("hash: %u, %u, %u, %u, %u, %u\n", shift, s1, s2, s3, s4, s5);
 | 
						|
         printf("#define PNG_CHUNK_HASH(n)\\\n   png_chunk_lut[0x3f &"
 | 
						|
                " (((n += n >> %u),n += n >> %u),n += n >> %u)]\n\n",
 | 
						|
                shift, s1, s2);
 | 
						|
         printf("static png_byte\n"
 | 
						|
                "png_chunk_index(png_uint_32 name)\n"
 | 
						|
                "{\n"
 | 
						|
                "   name += name >> %u;\n"
 | 
						|
                "   name += name >> %u;\n"
 | 
						|
                "   name += name >> %u;\n"
 | 
						|
                "   return png_chunk_lut[name & 0x3f];\n"
 | 
						|
                "}\n", shift, s1, s2);
 | 
						|
 | 
						|
         return 0;
 | 
						|
      }
 | 
						|
 | 
						|
      if (eq < mineq)
 | 
						|
      {
 | 
						|
         mineq = eq;
 | 
						|
         sarray = s1 + bitcount * (s2 + bitcount * (s3 + bitcount *
 | 
						|
                  (s4 + bitcount *s5)));
 | 
						|
         memcpy(reverse_index_save, reverse_index, sizeof reverse_index_save);
 | 
						|
         shift_save = shift;
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   s1 = sarray % bitcount;
 | 
						|
   s2 = (sarray / bitcount) % bitcount;
 | 
						|
   s3 = (sarray / bitcount / bitcount) % bitcount;
 | 
						|
   s4 = (sarray / bitcount / bitcount / bitcount) % bitcount;
 | 
						|
   s5 = (sarray / bitcount / bitcount / bitcount / bitcount) % bitcount;
 | 
						|
 | 
						|
   printf("best: %u clashes with bits: %u, %u, %u, %u, %u, %u\n",
 | 
						|
      mineq, shift_save, s1, s2, s3, s4, s5);
 | 
						|
 | 
						|
   {
 | 
						|
      int i;
 | 
						|
      png_uint_32 reverse_index[64];
 | 
						|
 | 
						|
      memset(reverse_index, 0, sizeof reverse_index);
 | 
						|
 | 
						|
      for (i=0; i<C_KNOWN; ++i)
 | 
						|
      {
 | 
						|
         png_uint_32 name = png_known_chunks[i].name;
 | 
						|
         unsigned int h = hash(name, shift_save, s1, s2, s3, s4, s5);
 | 
						|
 | 
						|
         if (reverse_index[h] == 0)
 | 
						|
            reverse_index[h] = name;
 | 
						|
 | 
						|
         else
 | 
						|
         {
 | 
						|
            char n1[5], n2[5];
 | 
						|
 | 
						|
            PNG_CSTRING_FROM_CHUNK(n1, reverse_index[h]);
 | 
						|
            PNG_CSTRING_FROM_CHUNK(n2, name);
 | 
						|
            printf("%d <- %s and %s\n", h, n1, n2);
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
   }
 | 
						|
 | 
						|
   return 1;
 | 
						|
}
 |