fukasawa e60969
/* contrib/arm-neon/linux.c
fukasawa e60969
 *
fukasawa e60969
 * Copyright (c) 2014 Glenn Randers-Pehrson
fukasawa e60969
 * Written by John Bowler, 2014.
fukasawa e60969
 * Last changed in libpng 1.6.16 [December 22, 2014]
fukasawa e60969
 *
fukasawa e60969
 * This code is released under the libpng license.
fukasawa e60969
 * For conditions of distribution and use, see the disclaimer
fukasawa e60969
 * and license in png.h
fukasawa e60969
 *
fukasawa e60969
 * SEE contrib/arm-neon/README before reporting bugs
fukasawa e60969
 *
fukasawa e60969
 * STATUS: SUPPORTED
fukasawa e60969
 * BUG REPORTS: png-mng-implement@sourceforge.net
fukasawa e60969
 *
fukasawa e60969
 * png_have_neon implemented for Linux by reading the widely available
fukasawa e60969
 * pseudo-file /proc/cpuinfo.
fukasawa e60969
 *
fukasawa e60969
 * This code is strict ANSI-C and is probably moderately portable; it does
fukasawa e60969
 * however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.</stdio.h>
fukasawa e60969
 */
fukasawa e60969
#include <stdio.h></stdio.h>
fukasawa e60969
fukasawa e60969
static int
fukasawa e60969
png_have_neon(png_structp png_ptr)
fukasawa e60969
{
fukasawa e60969
   FILE *f = fopen("/proc/cpuinfo", "rb");
fukasawa e60969
fukasawa e60969
   if (f != NULL)
fukasawa e60969
   {
fukasawa e60969
      /* This is a simple state machine which reads the input byte-by-byte until
fukasawa e60969
       * it gets a match on the 'neon' feature or reaches the end of the stream.
fukasawa e60969
       */
fukasawa e60969
      static const char ch_feature[] = { 70, 69, 65, 84, 85, 82, 69, 83 };
fukasawa e60969
      static const char ch_neon[] = { 78, 69, 79, 78 };
fukasawa e60969
fukasawa e60969
      enum
fukasawa e60969
      {
fukasawa e60969
         StartLine, Feature, Colon, StartTag, Neon, HaveNeon, SkipTag, SkipLine
fukasawa e60969
      }  state;
fukasawa e60969
      int counter;
fukasawa e60969
fukasawa e60969
      for (state=StartLine, counter=0;;)
fukasawa e60969
      {
fukasawa e60969
         int ch = fgetc(f);
fukasawa e60969
fukasawa e60969
         if (ch == EOF)
fukasawa e60969
         {
fukasawa e60969
            /* EOF means error or end-of-file, return false; neon at EOF is
fukasawa e60969
             * assumed to be a mistake.
fukasawa e60969
             */
fukasawa e60969
            fclose(f);
fukasawa e60969
            return 0;
fukasawa e60969
         }
fukasawa e60969
fukasawa e60969
         switch (state)
fukasawa e60969
         {
fukasawa e60969
            case StartLine:
fukasawa e60969
               /* Match spaces at the start of line */
fukasawa e60969
               if (ch <= 32) /* skip control characters and space */
fukasawa e60969
                  break;
fukasawa e60969
fukasawa e60969
               counter=0;
fukasawa e60969
               state = Feature;
fukasawa e60969
               /* FALL THROUGH */
fukasawa e60969
fukasawa e60969
            case Feature:
fukasawa e60969
               /* Match 'FEATURE', ASCII case insensitive. */
fukasawa e60969
               if ((ch & ~0x20) == ch_feature[counter])
fukasawa e60969
               {
fukasawa e60969
                  if (++counter == (sizeof ch_feature))
fukasawa e60969
                     state = Colon;
fukasawa e60969
                  break;
fukasawa e60969
               }
fukasawa e60969
fukasawa e60969
               /* did not match 'feature' */
fukasawa e60969
               state = SkipLine;
fukasawa e60969
               /* FALL THROUGH */
fukasawa e60969
fukasawa e60969
            case SkipLine:
fukasawa e60969
            skipLine:
fukasawa e60969
               /* Skip everything until we see linefeed or carriage return */
fukasawa e60969
               if (ch != 10 && ch != 13)
fukasawa e60969
                  break;
fukasawa e60969
fukasawa e60969
               state = StartLine;
fukasawa e60969
               break;
fukasawa e60969
fukasawa e60969
            case Colon:
fukasawa e60969
               /* Match any number of space or tab followed by ':' */
fukasawa e60969
               if (ch == 32 || ch == 9)
fukasawa e60969
                  break;
fukasawa e60969
fukasawa e60969
               if (ch == 58) /* i.e. ':' */
fukasawa e60969
               {
fukasawa e60969
                  state = StartTag;
fukasawa e60969
                  break;
fukasawa e60969
               }
fukasawa e60969
fukasawa e60969
               /* Either a bad line format or a 'feature' prefix followed by
fukasawa e60969
                * other characters.
fukasawa e60969
                */
fukasawa e60969
               state = SkipLine;
fukasawa e60969
               goto skipLine;
fukasawa e60969
fukasawa e60969
            case StartTag:
fukasawa e60969
               /* Skip space characters before a tag */
fukasawa e60969
               if (ch == 32 || ch == 9)
fukasawa e60969
                  break;
fukasawa e60969
fukasawa e60969
               state = Neon;
fukasawa e60969
               counter = 0;
fukasawa e60969
               /* FALL THROUGH */
fukasawa e60969
fukasawa e60969
            case Neon:
fukasawa e60969
               /* Look for 'neon' tag */
fukasawa e60969
               if ((ch & ~0x20) == ch_neon[counter])
fukasawa e60969
               {
fukasawa e60969
                  if (++counter == (sizeof ch_neon))
fukasawa e60969
                     state = HaveNeon;
fukasawa e60969
                  break;
fukasawa e60969
               }
fukasawa e60969
fukasawa e60969
               state = SkipTag;
fukasawa e60969
               /* FALL THROUGH */
fukasawa e60969
fukasawa e60969
            case SkipTag:
fukasawa e60969
               /* Skip non-space characters */
fukasawa e60969
               if (ch == 10 || ch == 13)
fukasawa e60969
                  state = StartLine;
fukasawa e60969
fukasawa e60969
               else if (ch == 32 || ch == 9)
fukasawa e60969
                  state = StartTag;
fukasawa e60969
               break;
fukasawa e60969
fukasawa e60969
            case HaveNeon:
fukasawa e60969
               /* Have seen a 'neon' prefix, but there must be a space or new
fukasawa e60969
                * line character to terminate it.
fukasawa e60969
                */
fukasawa e60969
               if (ch == 10 || ch == 13 || ch == 32 || ch == 9)
fukasawa e60969
               {
fukasawa e60969
                  fclose(f);
fukasawa e60969
                  return 1;
fukasawa e60969
               }
fukasawa e60969
fukasawa e60969
               state = SkipTag;
fukasawa e60969
               break;
fukasawa e60969
fukasawa e60969
            default:
fukasawa e60969
               png_error(png_ptr, "png_have_neon: internal error (bug)");
fukasawa e60969
         }
fukasawa e60969
      }
fukasawa e60969
   }
fukasawa e60969
fukasawa e60969
#ifdef PNG_WARNINGS_SUPPORTED
fukasawa e60969
   else
fukasawa e60969
      png_warning(png_ptr, "/proc/cpuinfo open failed");
fukasawa e60969
#endif
fukasawa e60969
fukasawa e60969
   return 0;
fukasawa e60969
}