• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <androidfw/ResourceTypes.h>
18 #include <ctype.h>
19 
20 #include "AaptConfig.h"
21 #include "AaptAssets.h"
22 #include "AaptUtil.h"
23 #include "ResourceFilter.h"
24 
25 using android::String8;
26 using android::Vector;
27 using android::ResTable_config;
28 
29 namespace AaptConfig {
30 
31 static const char* kWildcardName = "any";
32 
parse(const String8 & str,ConfigDescription * out)33 bool parse(const String8& str, ConfigDescription* out) {
34     Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '-');
35 
36     ConfigDescription config;
37     AaptLocaleValue locale;
38     ssize_t index = 0;
39     ssize_t localeIndex = 0;
40     const ssize_t N = parts.size();
41     const char* part = parts[index].string();
42 
43     if (str.length() == 0) {
44         goto success;
45     }
46 
47     if (parseMcc(part, &config)) {
48         index++;
49         if (index == N) {
50             goto success;
51         }
52         part = parts[index].string();
53     }
54 
55     if (parseMnc(part, &config)) {
56         index++;
57         if (index == N) {
58             goto success;
59         }
60         part = parts[index].string();
61     }
62 
63     // Locale spans a few '-' separators, so we let it
64     // control the index.
65     localeIndex = locale.initFromDirName(parts, index);
66     if (localeIndex < 0) {
67         return false;
68     } else if (localeIndex > index) {
69         locale.writeTo(&config);
70         index = localeIndex;
71         if (index >= N) {
72             goto success;
73         }
74         part = parts[index].string();
75     }
76 
77     if (parseLayoutDirection(part, &config)) {
78         index++;
79         if (index == N) {
80             goto success;
81         }
82         part = parts[index].string();
83     }
84 
85     if (parseSmallestScreenWidthDp(part, &config)) {
86         index++;
87         if (index == N) {
88             goto success;
89         }
90         part = parts[index].string();
91     }
92 
93     if (parseScreenWidthDp(part, &config)) {
94         index++;
95         if (index == N) {
96             goto success;
97         }
98         part = parts[index].string();
99     }
100 
101     if (parseScreenHeightDp(part, &config)) {
102         index++;
103         if (index == N) {
104             goto success;
105         }
106         part = parts[index].string();
107     }
108 
109     if (parseScreenLayoutSize(part, &config)) {
110         index++;
111         if (index == N) {
112             goto success;
113         }
114         part = parts[index].string();
115     }
116 
117     if (parseScreenLayoutLong(part, &config)) {
118         index++;
119         if (index == N) {
120             goto success;
121         }
122         part = parts[index].string();
123     }
124 
125     if (parseOrientation(part, &config)) {
126         index++;
127         if (index == N) {
128             goto success;
129         }
130         part = parts[index].string();
131     }
132 
133     if (parseUiModeType(part, &config)) {
134         index++;
135         if (index == N) {
136             goto success;
137         }
138         part = parts[index].string();
139     }
140 
141     if (parseUiModeNight(part, &config)) {
142         index++;
143         if (index == N) {
144             goto success;
145         }
146         part = parts[index].string();
147     }
148 
149     if (parseDensity(part, &config)) {
150         index++;
151         if (index == N) {
152             goto success;
153         }
154         part = parts[index].string();
155     }
156 
157     if (parseTouchscreen(part, &config)) {
158         index++;
159         if (index == N) {
160             goto success;
161         }
162         part = parts[index].string();
163     }
164 
165     if (parseKeysHidden(part, &config)) {
166         index++;
167         if (index == N) {
168             goto success;
169         }
170         part = parts[index].string();
171     }
172 
173     if (parseKeyboard(part, &config)) {
174         index++;
175         if (index == N) {
176             goto success;
177         }
178         part = parts[index].string();
179     }
180 
181     if (parseNavHidden(part, &config)) {
182         index++;
183         if (index == N) {
184             goto success;
185         }
186         part = parts[index].string();
187     }
188 
189     if (parseNavigation(part, &config)) {
190         index++;
191         if (index == N) {
192             goto success;
193         }
194         part = parts[index].string();
195     }
196 
197     if (parseScreenSize(part, &config)) {
198         index++;
199         if (index == N) {
200             goto success;
201         }
202         part = parts[index].string();
203     }
204 
205     if (parseVersion(part, &config)) {
206         index++;
207         if (index == N) {
208             goto success;
209         }
210         part = parts[index].string();
211     }
212 
213     // Unrecognized.
214     return false;
215 
216 success:
217     if (out != NULL) {
218         applyVersionForCompatibility(&config);
219         *out = config;
220     }
221     return true;
222 }
223 
parseCommaSeparatedList(const String8 & str,std::set<ConfigDescription> * outSet)224 bool parseCommaSeparatedList(const String8& str, std::set<ConfigDescription>* outSet) {
225     Vector<String8> parts = AaptUtil::splitAndLowerCase(str, ',');
226     const size_t N = parts.size();
227     for (size_t i = 0; i < N; i++) {
228         ConfigDescription config;
229         if (!parse(parts[i], &config)) {
230             return false;
231         }
232         outSet->insert(config);
233     }
234     return true;
235 }
236 
applyVersionForCompatibility(ConfigDescription * config)237 void applyVersionForCompatibility(ConfigDescription* config) {
238     if (config == NULL) {
239         return;
240     }
241 
242     uint16_t minSdk = 0;
243     if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
244             || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
245             || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
246         minSdk = SDK_HONEYCOMB_MR2;
247     } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
248                 != ResTable_config::UI_MODE_TYPE_ANY
249             ||  (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT)
250                 != ResTable_config::UI_MODE_NIGHT_ANY) {
251         minSdk = SDK_FROYO;
252     } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE)
253                 != ResTable_config::SCREENSIZE_ANY
254             ||  (config->screenLayout & ResTable_config::MASK_SCREENLONG)
255                 != ResTable_config::SCREENLONG_ANY
256             || config->density != ResTable_config::DENSITY_DEFAULT) {
257         minSdk = SDK_DONUT;
258     } else if ((config->density == ResTable_config::DENSITY_ANY)) {
259         minSdk = SDK_L;
260     }
261 
262     if (minSdk > config->sdkVersion) {
263         config->sdkVersion = minSdk;
264     }
265 }
266 
parseMcc(const char * name,ResTable_config * out)267 bool parseMcc(const char* name, ResTable_config* out) {
268     if (strcmp(name, kWildcardName) == 0) {
269         if (out) out->mcc = 0;
270         return true;
271     }
272     const char* c = name;
273     if (tolower(*c) != 'm') return false;
274     c++;
275     if (tolower(*c) != 'c') return false;
276     c++;
277     if (tolower(*c) != 'c') return false;
278     c++;
279 
280     const char* val = c;
281 
282     while (*c >= '0' && *c <= '9') {
283         c++;
284     }
285     if (*c != 0) return false;
286     if (c-val != 3) return false;
287 
288     int d = atoi(val);
289     if (d != 0) {
290         if (out) out->mcc = d;
291         return true;
292     }
293 
294     return false;
295 }
296 
parseMnc(const char * name,ResTable_config * out)297 bool parseMnc(const char* name, ResTable_config* out) {
298     if (strcmp(name, kWildcardName) == 0) {
299         if (out) out->mcc = 0;
300         return true;
301     }
302     const char* c = name;
303     if (tolower(*c) != 'm') return false;
304     c++;
305     if (tolower(*c) != 'n') return false;
306     c++;
307     if (tolower(*c) != 'c') return false;
308     c++;
309 
310     const char* val = c;
311 
312     while (*c >= '0' && *c <= '9') {
313         c++;
314     }
315     if (*c != 0) return false;
316     if (c-val == 0 || c-val > 3) return false;
317 
318     if (out) {
319         out->mnc = atoi(val);
320         if (out->mnc == 0) {
321             out->mnc = ACONFIGURATION_MNC_ZERO;
322         }
323     }
324 
325     return true;
326 }
327 
parseLayoutDirection(const char * name,ResTable_config * out)328 bool parseLayoutDirection(const char* name, ResTable_config* out) {
329     if (strcmp(name, kWildcardName) == 0) {
330         if (out) out->screenLayout =
331                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
332                 | ResTable_config::LAYOUTDIR_ANY;
333         return true;
334     } else if (strcmp(name, "ldltr") == 0) {
335         if (out) out->screenLayout =
336                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
337                 | ResTable_config::LAYOUTDIR_LTR;
338         return true;
339     } else if (strcmp(name, "ldrtl") == 0) {
340         if (out) out->screenLayout =
341                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
342                 | ResTable_config::LAYOUTDIR_RTL;
343         return true;
344     }
345 
346     return false;
347 }
348 
parseScreenLayoutSize(const char * name,ResTable_config * out)349 bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
350     if (strcmp(name, kWildcardName) == 0) {
351         if (out) out->screenLayout =
352                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
353                 | ResTable_config::SCREENSIZE_ANY;
354         return true;
355     } else if (strcmp(name, "small") == 0) {
356         if (out) out->screenLayout =
357                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
358                 | ResTable_config::SCREENSIZE_SMALL;
359         return true;
360     } else if (strcmp(name, "normal") == 0) {
361         if (out) out->screenLayout =
362                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
363                 | ResTable_config::SCREENSIZE_NORMAL;
364         return true;
365     } else if (strcmp(name, "large") == 0) {
366         if (out) out->screenLayout =
367                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
368                 | ResTable_config::SCREENSIZE_LARGE;
369         return true;
370     } else if (strcmp(name, "xlarge") == 0) {
371         if (out) out->screenLayout =
372                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
373                 | ResTable_config::SCREENSIZE_XLARGE;
374         return true;
375     }
376 
377     return false;
378 }
379 
parseScreenLayoutLong(const char * name,ResTable_config * out)380 bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
381     if (strcmp(name, kWildcardName) == 0) {
382         if (out) out->screenLayout =
383                 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
384                 | ResTable_config::SCREENLONG_ANY;
385         return true;
386     } else if (strcmp(name, "long") == 0) {
387         if (out) out->screenLayout =
388                 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
389                 | ResTable_config::SCREENLONG_YES;
390         return true;
391     } else if (strcmp(name, "notlong") == 0) {
392         if (out) out->screenLayout =
393                 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
394                 | ResTable_config::SCREENLONG_NO;
395         return true;
396     }
397 
398     return false;
399 }
400 
parseOrientation(const char * name,ResTable_config * out)401 bool parseOrientation(const char* name, ResTable_config* out) {
402     if (strcmp(name, kWildcardName) == 0) {
403         if (out) out->orientation = out->ORIENTATION_ANY;
404         return true;
405     } else if (strcmp(name, "port") == 0) {
406         if (out) out->orientation = out->ORIENTATION_PORT;
407         return true;
408     } else if (strcmp(name, "land") == 0) {
409         if (out) out->orientation = out->ORIENTATION_LAND;
410         return true;
411     } else if (strcmp(name, "square") == 0) {
412         if (out) out->orientation = out->ORIENTATION_SQUARE;
413         return true;
414     }
415 
416     return false;
417 }
418 
parseUiModeType(const char * name,ResTable_config * out)419 bool parseUiModeType(const char* name, ResTable_config* out) {
420     if (strcmp(name, kWildcardName) == 0) {
421         if (out) out->uiMode =
422                 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
423                 | ResTable_config::UI_MODE_TYPE_ANY;
424         return true;
425     } else if (strcmp(name, "desk") == 0) {
426       if (out) out->uiMode =
427               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
428               | ResTable_config::UI_MODE_TYPE_DESK;
429         return true;
430     } else if (strcmp(name, "car") == 0) {
431       if (out) out->uiMode =
432               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
433               | ResTable_config::UI_MODE_TYPE_CAR;
434         return true;
435     } else if (strcmp(name, "television") == 0) {
436       if (out) out->uiMode =
437               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
438               | ResTable_config::UI_MODE_TYPE_TELEVISION;
439         return true;
440     } else if (strcmp(name, "appliance") == 0) {
441       if (out) out->uiMode =
442               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
443               | ResTable_config::UI_MODE_TYPE_APPLIANCE;
444         return true;
445     } else if (strcmp(name, "watch") == 0) {
446       if (out) out->uiMode =
447               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
448               | ResTable_config::UI_MODE_TYPE_WATCH;
449         return true;
450     }
451 
452     return false;
453 }
454 
parseUiModeNight(const char * name,ResTable_config * out)455 bool parseUiModeNight(const char* name, ResTable_config* out) {
456     if (strcmp(name, kWildcardName) == 0) {
457         if (out) out->uiMode =
458                 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
459                 | ResTable_config::UI_MODE_NIGHT_ANY;
460         return true;
461     } else if (strcmp(name, "night") == 0) {
462         if (out) out->uiMode =
463                 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
464                 | ResTable_config::UI_MODE_NIGHT_YES;
465         return true;
466     } else if (strcmp(name, "notnight") == 0) {
467       if (out) out->uiMode =
468               (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
469               | ResTable_config::UI_MODE_NIGHT_NO;
470         return true;
471     }
472 
473     return false;
474 }
475 
parseDensity(const char * name,ResTable_config * out)476 bool parseDensity(const char* name, ResTable_config* out) {
477     if (strcmp(name, kWildcardName) == 0) {
478         if (out) out->density = ResTable_config::DENSITY_DEFAULT;
479         return true;
480     }
481 
482     if (strcmp(name, "anydpi") == 0) {
483         if (out) out->density = ResTable_config::DENSITY_ANY;
484         return true;
485     }
486 
487     if (strcmp(name, "nodpi") == 0) {
488         if (out) out->density = ResTable_config::DENSITY_NONE;
489         return true;
490     }
491 
492     if (strcmp(name, "ldpi") == 0) {
493         if (out) out->density = ResTable_config::DENSITY_LOW;
494         return true;
495     }
496 
497     if (strcmp(name, "mdpi") == 0) {
498         if (out) out->density = ResTable_config::DENSITY_MEDIUM;
499         return true;
500     }
501 
502     if (strcmp(name, "tvdpi") == 0) {
503         if (out) out->density = ResTable_config::DENSITY_TV;
504         return true;
505     }
506 
507     if (strcmp(name, "hdpi") == 0) {
508         if (out) out->density = ResTable_config::DENSITY_HIGH;
509         return true;
510     }
511 
512     if (strcmp(name, "xhdpi") == 0) {
513         if (out) out->density = ResTable_config::DENSITY_XHIGH;
514         return true;
515     }
516 
517     if (strcmp(name, "xxhdpi") == 0) {
518         if (out) out->density = ResTable_config::DENSITY_XXHIGH;
519         return true;
520     }
521 
522     if (strcmp(name, "xxxhdpi") == 0) {
523         if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
524         return true;
525     }
526 
527     char* c = (char*)name;
528     while (*c >= '0' && *c <= '9') {
529         c++;
530     }
531 
532     // check that we have 'dpi' after the last digit.
533     if (toupper(c[0]) != 'D' ||
534             toupper(c[1]) != 'P' ||
535             toupper(c[2]) != 'I' ||
536             c[3] != 0) {
537         return false;
538     }
539 
540     // temporarily replace the first letter with \0 to
541     // use atoi.
542     char tmp = c[0];
543     c[0] = '\0';
544 
545     int d = atoi(name);
546     c[0] = tmp;
547 
548     if (d != 0) {
549         if (out) out->density = d;
550         return true;
551     }
552 
553     return false;
554 }
555 
parseTouchscreen(const char * name,ResTable_config * out)556 bool parseTouchscreen(const char* name, ResTable_config* out) {
557     if (strcmp(name, kWildcardName) == 0) {
558         if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
559         return true;
560     } else if (strcmp(name, "notouch") == 0) {
561         if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
562         return true;
563     } else if (strcmp(name, "stylus") == 0) {
564         if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
565         return true;
566     } else if (strcmp(name, "finger") == 0) {
567         if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
568         return true;
569     }
570 
571     return false;
572 }
573 
parseKeysHidden(const char * name,ResTable_config * out)574 bool parseKeysHidden(const char* name, ResTable_config* out) {
575     uint8_t mask = 0;
576     uint8_t value = 0;
577     if (strcmp(name, kWildcardName) == 0) {
578         mask = ResTable_config::MASK_KEYSHIDDEN;
579         value = ResTable_config::KEYSHIDDEN_ANY;
580     } else if (strcmp(name, "keysexposed") == 0) {
581         mask = ResTable_config::MASK_KEYSHIDDEN;
582         value = ResTable_config::KEYSHIDDEN_NO;
583     } else if (strcmp(name, "keyshidden") == 0) {
584         mask = ResTable_config::MASK_KEYSHIDDEN;
585         value = ResTable_config::KEYSHIDDEN_YES;
586     } else if (strcmp(name, "keyssoft") == 0) {
587         mask = ResTable_config::MASK_KEYSHIDDEN;
588         value = ResTable_config::KEYSHIDDEN_SOFT;
589     }
590 
591     if (mask != 0) {
592         if (out) out->inputFlags = (out->inputFlags&~mask) | value;
593         return true;
594     }
595 
596     return false;
597 }
598 
parseKeyboard(const char * name,ResTable_config * out)599 bool parseKeyboard(const char* name, ResTable_config* out) {
600     if (strcmp(name, kWildcardName) == 0) {
601         if (out) out->keyboard = out->KEYBOARD_ANY;
602         return true;
603     } else if (strcmp(name, "nokeys") == 0) {
604         if (out) out->keyboard = out->KEYBOARD_NOKEYS;
605         return true;
606     } else if (strcmp(name, "qwerty") == 0) {
607         if (out) out->keyboard = out->KEYBOARD_QWERTY;
608         return true;
609     } else if (strcmp(name, "12key") == 0) {
610         if (out) out->keyboard = out->KEYBOARD_12KEY;
611         return true;
612     }
613 
614     return false;
615 }
616 
parseNavHidden(const char * name,ResTable_config * out)617 bool parseNavHidden(const char* name, ResTable_config* out) {
618     uint8_t mask = 0;
619     uint8_t value = 0;
620     if (strcmp(name, kWildcardName) == 0) {
621         mask = ResTable_config::MASK_NAVHIDDEN;
622         value = ResTable_config::NAVHIDDEN_ANY;
623     } else if (strcmp(name, "navexposed") == 0) {
624         mask = ResTable_config::MASK_NAVHIDDEN;
625         value = ResTable_config::NAVHIDDEN_NO;
626     } else if (strcmp(name, "navhidden") == 0) {
627         mask = ResTable_config::MASK_NAVHIDDEN;
628         value = ResTable_config::NAVHIDDEN_YES;
629     }
630 
631     if (mask != 0) {
632         if (out) out->inputFlags = (out->inputFlags&~mask) | value;
633         return true;
634     }
635 
636     return false;
637 }
638 
parseNavigation(const char * name,ResTable_config * out)639 bool parseNavigation(const char* name, ResTable_config* out) {
640     if (strcmp(name, kWildcardName) == 0) {
641         if (out) out->navigation = out->NAVIGATION_ANY;
642         return true;
643     } else if (strcmp(name, "nonav") == 0) {
644         if (out) out->navigation = out->NAVIGATION_NONAV;
645         return true;
646     } else if (strcmp(name, "dpad") == 0) {
647         if (out) out->navigation = out->NAVIGATION_DPAD;
648         return true;
649     } else if (strcmp(name, "trackball") == 0) {
650         if (out) out->navigation = out->NAVIGATION_TRACKBALL;
651         return true;
652     } else if (strcmp(name, "wheel") == 0) {
653         if (out) out->navigation = out->NAVIGATION_WHEEL;
654         return true;
655     }
656 
657     return false;
658 }
659 
parseScreenSize(const char * name,ResTable_config * out)660 bool parseScreenSize(const char* name, ResTable_config* out) {
661     if (strcmp(name, kWildcardName) == 0) {
662         if (out) {
663             out->screenWidth = out->SCREENWIDTH_ANY;
664             out->screenHeight = out->SCREENHEIGHT_ANY;
665         }
666         return true;
667     }
668 
669     const char* x = name;
670     while (*x >= '0' && *x <= '9') x++;
671     if (x == name || *x != 'x') return false;
672     String8 xName(name, x-name);
673     x++;
674 
675     const char* y = x;
676     while (*y >= '0' && *y <= '9') y++;
677     if (y == name || *y != 0) return false;
678     String8 yName(x, y-x);
679 
680     uint16_t w = (uint16_t)atoi(xName.string());
681     uint16_t h = (uint16_t)atoi(yName.string());
682     if (w < h) {
683         return false;
684     }
685 
686     if (out) {
687         out->screenWidth = w;
688         out->screenHeight = h;
689     }
690 
691     return true;
692 }
693 
parseSmallestScreenWidthDp(const char * name,ResTable_config * out)694 bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
695     if (strcmp(name, kWildcardName) == 0) {
696         if (out) {
697             out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
698         }
699         return true;
700     }
701 
702     if (*name != 's') return false;
703     name++;
704     if (*name != 'w') return false;
705     name++;
706     const char* x = name;
707     while (*x >= '0' && *x <= '9') x++;
708     if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
709     String8 xName(name, x-name);
710 
711     if (out) {
712         out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
713     }
714 
715     return true;
716 }
717 
parseScreenWidthDp(const char * name,ResTable_config * out)718 bool parseScreenWidthDp(const char* name, ResTable_config* out) {
719     if (strcmp(name, kWildcardName) == 0) {
720         if (out) {
721             out->screenWidthDp = out->SCREENWIDTH_ANY;
722         }
723         return true;
724     }
725 
726     if (*name != 'w') return false;
727     name++;
728     const char* x = name;
729     while (*x >= '0' && *x <= '9') x++;
730     if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
731     String8 xName(name, x-name);
732 
733     if (out) {
734         out->screenWidthDp = (uint16_t)atoi(xName.string());
735     }
736 
737     return true;
738 }
739 
parseScreenHeightDp(const char * name,ResTable_config * out)740 bool parseScreenHeightDp(const char* name, ResTable_config* out) {
741     if (strcmp(name, kWildcardName) == 0) {
742         if (out) {
743             out->screenHeightDp = out->SCREENWIDTH_ANY;
744         }
745         return true;
746     }
747 
748     if (*name != 'h') return false;
749     name++;
750     const char* x = name;
751     while (*x >= '0' && *x <= '9') x++;
752     if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
753     String8 xName(name, x-name);
754 
755     if (out) {
756         out->screenHeightDp = (uint16_t)atoi(xName.string());
757     }
758 
759     return true;
760 }
761 
parseVersion(const char * name,ResTable_config * out)762 bool parseVersion(const char* name, ResTable_config* out) {
763     if (strcmp(name, kWildcardName) == 0) {
764         if (out) {
765             out->sdkVersion = out->SDKVERSION_ANY;
766             out->minorVersion = out->MINORVERSION_ANY;
767         }
768         return true;
769     }
770 
771     if (*name != 'v') {
772         return false;
773     }
774 
775     name++;
776     const char* s = name;
777     while (*s >= '0' && *s <= '9') s++;
778     if (s == name || *s != 0) return false;
779     String8 sdkName(name, s-name);
780 
781     if (out) {
782         out->sdkVersion = (uint16_t)atoi(sdkName.string());
783         out->minorVersion = 0;
784     }
785 
786     return true;
787 }
788 
getVersion(const ResTable_config & config)789 String8 getVersion(const ResTable_config& config) {
790     return String8::format("v%u", config.sdkVersion);
791 }
792 
isSameExcept(const ResTable_config & a,const ResTable_config & b,int axisMask)793 bool isSameExcept(const ResTable_config& a, const ResTable_config& b, int axisMask) {
794     return a.diff(b) == axisMask;
795 }
796 
797 } // namespace AaptConfig
798