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