1 /* contrib/arm-neon/linux.c
2  *
3  * Copyright (c) 2014 Glenn Randers-Pehrson
4  * Written by John Bowler, 2014.
5  * Last changed in libpng 1.6.16 [December 22, 2014]
6  *
7  * This code is released under the libpng license.
8  * For conditions of distribution and use, see the disclaimer
9  * and license in png.h
10  *
11  * SEE contrib/arm-neon/README before reporting bugs
12  *
13  * STATUS: SUPPORTED
14  * BUG REPORTS: png-mng-implement@sourceforge.net
15  *
16  * png_have_neon implemented for Linux by reading the widely available
17  * pseudo-file /proc/cpuinfo.
18  *
19  * This code is strict ANSI-C and is probably moderately portable; it does
20  * however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.
21  */
22 #include <stdio.h>
23 
24 static int
png_have_neon(png_structp png_ptr)25 png_have_neon(png_structp png_ptr)
26 {
27    FILE *f = fopen("/proc/cpuinfo", "rb");
28 
29    if (f != NULL)
30    {
31       /* This is a simple state machine which reads the input byte-by-byte until
32        * it gets a match on the 'neon' feature or reaches the end of the stream.
33        */
34       static const char ch_feature[] = { 70, 69, 65, 84, 85, 82, 69, 83 };
35       static const char ch_neon[] = { 78, 69, 79, 78 };
36 
37       enum
38       {
39          StartLine, Feature, Colon, StartTag, Neon, HaveNeon, SkipTag, SkipLine
40       }  state;
41       int counter;
42 
43       for (state=StartLine, counter=0;;)
44       {
45          int ch = fgetc(f);
46 
47          if (ch == EOF)
48          {
49             /* EOF means error or end-of-file, return false; neon at EOF is
50              * assumed to be a mistake.
51              */
52             fclose(f);
53             return 0;
54          }
55 
56          switch (state)
57          {
58             case StartLine:
59                /* Match spaces at the start of line */
60                if (ch <= 32) /* skip control characters and space */
61                   break;
62 
63                counter=0;
64                state = Feature;
65                /* FALL THROUGH */
66 
67             case Feature:
68                /* Match 'FEATURE', ASCII case insensitive. */
69                if ((ch & ~0x20) == ch_feature[counter])
70                {
71                   if (++counter == (sizeof ch_feature))
72                      state = Colon;
73                   break;
74                }
75 
76                /* did not match 'feature' */
77                state = SkipLine;
78                /* FALL THROUGH */
79 
80             case SkipLine:
81             skipLine:
82                /* Skip everything until we see linefeed or carriage return */
83                if (ch != 10 && ch != 13)
84                   break;
85 
86                state = StartLine;
87                break;
88 
89             case Colon:
90                /* Match any number of space or tab followed by ':' */
91                if (ch == 32 || ch == 9)
92                   break;
93 
94                if (ch == 58) /* i.e. ':' */
95                {
96                   state = StartTag;
97                   break;
98                }
99 
100                /* Either a bad line format or a 'feature' prefix followed by
101                 * other characters.
102                 */
103                state = SkipLine;
104                goto skipLine;
105 
106             case StartTag:
107                /* Skip space characters before a tag */
108                if (ch == 32 || ch == 9)
109                   break;
110 
111                state = Neon;
112                counter = 0;
113                /* FALL THROUGH */
114 
115             case Neon:
116                /* Look for 'neon' tag */
117                if ((ch & ~0x20) == ch_neon[counter])
118                {
119                   if (++counter == (sizeof ch_neon))
120                      state = HaveNeon;
121                   break;
122                }
123 
124                state = SkipTag;
125                /* FALL THROUGH */
126 
127             case SkipTag:
128                /* Skip non-space characters */
129                if (ch == 10 || ch == 13)
130                   state = StartLine;
131 
132                else if (ch == 32 || ch == 9)
133                   state = StartTag;
134                break;
135 
136             case HaveNeon:
137                /* Have seen a 'neon' prefix, but there must be a space or new
138                 * line character to terminate it.
139                 */
140                if (ch == 10 || ch == 13 || ch == 32 || ch == 9)
141                {
142                   fclose(f);
143                   return 1;
144                }
145 
146                state = SkipTag;
147                break;
148 
149             default:
150                png_error(png_ptr, "png_have_neon: internal error (bug)");
151          }
152       }
153    }
154 
155 #ifdef PNG_WARNINGS_SUPPORTED
156    else
157       png_warning(png_ptr, "/proc/cpuinfo open failed");
158 #endif
159 
160    return 0;
161 }
162