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