xref: /aosp_15_r20/frameworks/base/tools/aapt/AaptAssets.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker //
2*d57664e9SAndroid Build Coastguard Worker // Copyright 2006 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker //
4*d57664e9SAndroid Build Coastguard Worker 
5*d57664e9SAndroid Build Coastguard Worker #include "AaptAssets.h"
6*d57664e9SAndroid Build Coastguard Worker #include "AaptConfig.h"
7*d57664e9SAndroid Build Coastguard Worker #include "AaptUtil.h"
8*d57664e9SAndroid Build Coastguard Worker #include "Main.h"
9*d57664e9SAndroid Build Coastguard Worker #include "ResourceFilter.h"
10*d57664e9SAndroid Build Coastguard Worker #include "Utils.h"
11*d57664e9SAndroid Build Coastguard Worker 
12*d57664e9SAndroid Build Coastguard Worker #include <androidfw/PathUtils.h>
13*d57664e9SAndroid Build Coastguard Worker #include <utils/misc.h>
14*d57664e9SAndroid Build Coastguard Worker #include <utils/SortedVector.h>
15*d57664e9SAndroid Build Coastguard Worker 
16*d57664e9SAndroid Build Coastguard Worker #include <ctype.h>
17*d57664e9SAndroid Build Coastguard Worker #include <dirent.h>
18*d57664e9SAndroid Build Coastguard Worker #include <errno.h>
19*d57664e9SAndroid Build Coastguard Worker 
20*d57664e9SAndroid Build Coastguard Worker static const char* kAssetDir = "assets";
21*d57664e9SAndroid Build Coastguard Worker static const char* kResourceDir = "res";
22*d57664e9SAndroid Build Coastguard Worker static const char* kValuesDir = "values";
23*d57664e9SAndroid Build Coastguard Worker static const char* kMipmapDir = "mipmap";
24*d57664e9SAndroid Build Coastguard Worker static const char* kInvalidChars = "/\\:";
25*d57664e9SAndroid Build Coastguard Worker static const size_t kMaxAssetFileName = 100;
26*d57664e9SAndroid Build Coastguard Worker 
27*d57664e9SAndroid Build Coastguard Worker static const String8 kResString(kResourceDir);
28*d57664e9SAndroid Build Coastguard Worker 
29*d57664e9SAndroid Build Coastguard Worker /*
30*d57664e9SAndroid Build Coastguard Worker  * Names of asset files must meet the following criteria:
31*d57664e9SAndroid Build Coastguard Worker  *
32*d57664e9SAndroid Build Coastguard Worker  *  - the filename length must be less than kMaxAssetFileName bytes long
33*d57664e9SAndroid Build Coastguard Worker  *    (and can't be empty)
34*d57664e9SAndroid Build Coastguard Worker  *  - all characters must be 7-bit printable ASCII
35*d57664e9SAndroid Build Coastguard Worker  *  - none of { '/' '\\' ':' }
36*d57664e9SAndroid Build Coastguard Worker  *
37*d57664e9SAndroid Build Coastguard Worker  * Pass in just the filename, not the full path.
38*d57664e9SAndroid Build Coastguard Worker  */
validateFileName(const char * fileName)39*d57664e9SAndroid Build Coastguard Worker static bool validateFileName(const char* fileName)
40*d57664e9SAndroid Build Coastguard Worker {
41*d57664e9SAndroid Build Coastguard Worker     const char* cp = fileName;
42*d57664e9SAndroid Build Coastguard Worker     size_t len = 0;
43*d57664e9SAndroid Build Coastguard Worker 
44*d57664e9SAndroid Build Coastguard Worker     while (*cp != '\0') {
45*d57664e9SAndroid Build Coastguard Worker         if ((*cp & 0x80) != 0)
46*d57664e9SAndroid Build Coastguard Worker             return false;           // reject high ASCII
47*d57664e9SAndroid Build Coastguard Worker         if (*cp < 0x20 || *cp >= 0x7f)
48*d57664e9SAndroid Build Coastguard Worker             return false;           // reject control chars and 0x7f
49*d57664e9SAndroid Build Coastguard Worker         if (strchr(kInvalidChars, *cp) != NULL)
50*d57664e9SAndroid Build Coastguard Worker             return false;           // reject path sep chars
51*d57664e9SAndroid Build Coastguard Worker         cp++;
52*d57664e9SAndroid Build Coastguard Worker         len++;
53*d57664e9SAndroid Build Coastguard Worker     }
54*d57664e9SAndroid Build Coastguard Worker 
55*d57664e9SAndroid Build Coastguard Worker     if (len < 1 || len > kMaxAssetFileName)
56*d57664e9SAndroid Build Coastguard Worker         return false;               // reject empty or too long
57*d57664e9SAndroid Build Coastguard Worker 
58*d57664e9SAndroid Build Coastguard Worker     return true;
59*d57664e9SAndroid Build Coastguard Worker }
60*d57664e9SAndroid Build Coastguard Worker 
61*d57664e9SAndroid Build Coastguard Worker // The default to use if no other ignore pattern is defined.
62*d57664e9SAndroid Build Coastguard Worker const char * const gDefaultIgnoreAssets =
63*d57664e9SAndroid Build Coastguard Worker     "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~";
64*d57664e9SAndroid Build Coastguard Worker // The ignore pattern that can be passed via --ignore-assets in Main.cpp
65*d57664e9SAndroid Build Coastguard Worker const char * gUserIgnoreAssets = NULL;
66*d57664e9SAndroid Build Coastguard Worker 
isHidden(const char * root,const char * path)67*d57664e9SAndroid Build Coastguard Worker static bool isHidden(const char *root, const char *path)
68*d57664e9SAndroid Build Coastguard Worker {
69*d57664e9SAndroid Build Coastguard Worker     // Patterns syntax:
70*d57664e9SAndroid Build Coastguard Worker     // - Delimiter is :
71*d57664e9SAndroid Build Coastguard Worker     // - Entry can start with the flag ! to avoid printing a warning
72*d57664e9SAndroid Build Coastguard Worker     //   about the file being ignored.
73*d57664e9SAndroid Build Coastguard Worker     // - Entry can have the flag "<dir>" to match only directories
74*d57664e9SAndroid Build Coastguard Worker     //   or <file> to match only files. Default is to match both.
75*d57664e9SAndroid Build Coastguard Worker     // - Entry can be a simplified glob "<prefix>*" or "*<suffix>"
76*d57664e9SAndroid Build Coastguard Worker     //   where prefix/suffix must have at least 1 character (so that
77*d57664e9SAndroid Build Coastguard Worker     //   we don't match a '*' catch-all pattern.)
78*d57664e9SAndroid Build Coastguard Worker     // - The special filenames "." and ".." are always ignored.
79*d57664e9SAndroid Build Coastguard Worker     // - Otherwise the full string is matched.
80*d57664e9SAndroid Build Coastguard Worker     // - match is not case-sensitive.
81*d57664e9SAndroid Build Coastguard Worker 
82*d57664e9SAndroid Build Coastguard Worker     if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) {
83*d57664e9SAndroid Build Coastguard Worker         return true;
84*d57664e9SAndroid Build Coastguard Worker     }
85*d57664e9SAndroid Build Coastguard Worker 
86*d57664e9SAndroid Build Coastguard Worker     const char *delim = ":";
87*d57664e9SAndroid Build Coastguard Worker     const char *p = gUserIgnoreAssets;
88*d57664e9SAndroid Build Coastguard Worker     if (!p || !p[0]) {
89*d57664e9SAndroid Build Coastguard Worker         p = getenv("ANDROID_AAPT_IGNORE");
90*d57664e9SAndroid Build Coastguard Worker     }
91*d57664e9SAndroid Build Coastguard Worker     if (!p || !p[0]) {
92*d57664e9SAndroid Build Coastguard Worker         p = gDefaultIgnoreAssets;
93*d57664e9SAndroid Build Coastguard Worker     }
94*d57664e9SAndroid Build Coastguard Worker     char *patterns = strdup(p);
95*d57664e9SAndroid Build Coastguard Worker 
96*d57664e9SAndroid Build Coastguard Worker     bool ignore = false;
97*d57664e9SAndroid Build Coastguard Worker     bool chatty = true;
98*d57664e9SAndroid Build Coastguard Worker     char *matchedPattern = NULL;
99*d57664e9SAndroid Build Coastguard Worker 
100*d57664e9SAndroid Build Coastguard Worker     String8 fullPath(root);
101*d57664e9SAndroid Build Coastguard Worker     appendPath(fullPath, String8(path));
102*d57664e9SAndroid Build Coastguard Worker     FileType type = getFileType(fullPath.c_str());
103*d57664e9SAndroid Build Coastguard Worker 
104*d57664e9SAndroid Build Coastguard Worker     int plen = strlen(path);
105*d57664e9SAndroid Build Coastguard Worker 
106*d57664e9SAndroid Build Coastguard Worker     // Note: we don't have strtok_r under mingw.
107*d57664e9SAndroid Build Coastguard Worker     for(char *token = strtok(patterns, delim);
108*d57664e9SAndroid Build Coastguard Worker             !ignore && token != NULL;
109*d57664e9SAndroid Build Coastguard Worker             token = strtok(NULL, delim)) {
110*d57664e9SAndroid Build Coastguard Worker         chatty = token[0] != '!';
111*d57664e9SAndroid Build Coastguard Worker         if (!chatty) token++; // skip !
112*d57664e9SAndroid Build Coastguard Worker         if (strncasecmp(token, "<dir>" , 5) == 0) {
113*d57664e9SAndroid Build Coastguard Worker             if (type != kFileTypeDirectory) continue;
114*d57664e9SAndroid Build Coastguard Worker             token += 5;
115*d57664e9SAndroid Build Coastguard Worker         }
116*d57664e9SAndroid Build Coastguard Worker         if (strncasecmp(token, "<file>", 6) == 0) {
117*d57664e9SAndroid Build Coastguard Worker             if (type != kFileTypeRegular) continue;
118*d57664e9SAndroid Build Coastguard Worker             token += 6;
119*d57664e9SAndroid Build Coastguard Worker         }
120*d57664e9SAndroid Build Coastguard Worker 
121*d57664e9SAndroid Build Coastguard Worker         matchedPattern = token;
122*d57664e9SAndroid Build Coastguard Worker         int n = strlen(token);
123*d57664e9SAndroid Build Coastguard Worker 
124*d57664e9SAndroid Build Coastguard Worker         if (token[0] == '*') {
125*d57664e9SAndroid Build Coastguard Worker             // Match *suffix
126*d57664e9SAndroid Build Coastguard Worker             token++;
127*d57664e9SAndroid Build Coastguard Worker             n--;
128*d57664e9SAndroid Build Coastguard Worker             if (n <= plen) {
129*d57664e9SAndroid Build Coastguard Worker                 ignore = strncasecmp(token, path + plen - n, n) == 0;
130*d57664e9SAndroid Build Coastguard Worker             }
131*d57664e9SAndroid Build Coastguard Worker         } else if (n > 1 && token[n - 1] == '*') {
132*d57664e9SAndroid Build Coastguard Worker             // Match prefix*
133*d57664e9SAndroid Build Coastguard Worker             ignore = strncasecmp(token, path, n - 1) == 0;
134*d57664e9SAndroid Build Coastguard Worker         } else {
135*d57664e9SAndroid Build Coastguard Worker             ignore = strcasecmp(token, path) == 0;
136*d57664e9SAndroid Build Coastguard Worker         }
137*d57664e9SAndroid Build Coastguard Worker     }
138*d57664e9SAndroid Build Coastguard Worker 
139*d57664e9SAndroid Build Coastguard Worker     if (ignore && chatty) {
140*d57664e9SAndroid Build Coastguard Worker         fprintf(stderr, "    (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n",
141*d57664e9SAndroid Build Coastguard Worker                 type == kFileTypeDirectory ? "dir" : "file",
142*d57664e9SAndroid Build Coastguard Worker                 path,
143*d57664e9SAndroid Build Coastguard Worker                 matchedPattern ? matchedPattern : "");
144*d57664e9SAndroid Build Coastguard Worker     }
145*d57664e9SAndroid Build Coastguard Worker 
146*d57664e9SAndroid Build Coastguard Worker     free(patterns);
147*d57664e9SAndroid Build Coastguard Worker     return ignore;
148*d57664e9SAndroid Build Coastguard Worker }
149*d57664e9SAndroid Build Coastguard Worker 
150*d57664e9SAndroid Build Coastguard Worker // =========================================================================
151*d57664e9SAndroid Build Coastguard Worker // =========================================================================
152*d57664e9SAndroid Build Coastguard Worker // =========================================================================
153*d57664e9SAndroid Build Coastguard Worker 
154*d57664e9SAndroid Build Coastguard Worker /* static */
isAlpha(const String8 & string)155*d57664e9SAndroid Build Coastguard Worker inline bool isAlpha(const String8& string) {
156*d57664e9SAndroid Build Coastguard Worker      const size_t length = string.length();
157*d57664e9SAndroid Build Coastguard Worker      for (size_t i = 0; i < length; ++i) {
158*d57664e9SAndroid Build Coastguard Worker           if (!isalpha(string[i])) {
159*d57664e9SAndroid Build Coastguard Worker               return false;
160*d57664e9SAndroid Build Coastguard Worker           }
161*d57664e9SAndroid Build Coastguard Worker      }
162*d57664e9SAndroid Build Coastguard Worker 
163*d57664e9SAndroid Build Coastguard Worker      return true;
164*d57664e9SAndroid Build Coastguard Worker }
165*d57664e9SAndroid Build Coastguard Worker 
166*d57664e9SAndroid Build Coastguard Worker /* static */
isNumber(const String8 & string)167*d57664e9SAndroid Build Coastguard Worker inline bool isNumber(const String8& string) {
168*d57664e9SAndroid Build Coastguard Worker      const size_t length = string.length();
169*d57664e9SAndroid Build Coastguard Worker      for (size_t i = 0; i < length; ++i) {
170*d57664e9SAndroid Build Coastguard Worker           if (!isdigit(string[i])) {
171*d57664e9SAndroid Build Coastguard Worker               return false;
172*d57664e9SAndroid Build Coastguard Worker           }
173*d57664e9SAndroid Build Coastguard Worker      }
174*d57664e9SAndroid Build Coastguard Worker 
175*d57664e9SAndroid Build Coastguard Worker      return true;
176*d57664e9SAndroid Build Coastguard Worker }
177*d57664e9SAndroid Build Coastguard Worker 
setLanguage(const char * languageChars)178*d57664e9SAndroid Build Coastguard Worker void AaptLocaleValue::setLanguage(const char* languageChars) {
179*d57664e9SAndroid Build Coastguard Worker      size_t i = 0;
180*d57664e9SAndroid Build Coastguard Worker      while ((*languageChars) != '\0' && i < sizeof(language)/sizeof(language[0])) {
181*d57664e9SAndroid Build Coastguard Worker           language[i++] = tolower(*languageChars);
182*d57664e9SAndroid Build Coastguard Worker           languageChars++;
183*d57664e9SAndroid Build Coastguard Worker      }
184*d57664e9SAndroid Build Coastguard Worker }
185*d57664e9SAndroid Build Coastguard Worker 
setRegion(const char * regionChars)186*d57664e9SAndroid Build Coastguard Worker void AaptLocaleValue::setRegion(const char* regionChars) {
187*d57664e9SAndroid Build Coastguard Worker     size_t i = 0;
188*d57664e9SAndroid Build Coastguard Worker     while ((*regionChars) != '\0' && i < sizeof(region)/sizeof(region[0])) {
189*d57664e9SAndroid Build Coastguard Worker          region[i++] = toupper(*regionChars);
190*d57664e9SAndroid Build Coastguard Worker          regionChars++;
191*d57664e9SAndroid Build Coastguard Worker     }
192*d57664e9SAndroid Build Coastguard Worker }
193*d57664e9SAndroid Build Coastguard Worker 
setScript(const char * scriptChars)194*d57664e9SAndroid Build Coastguard Worker void AaptLocaleValue::setScript(const char* scriptChars) {
195*d57664e9SAndroid Build Coastguard Worker     size_t i = 0;
196*d57664e9SAndroid Build Coastguard Worker     while ((*scriptChars) != '\0' && i < sizeof(script)/sizeof(script[0])) {
197*d57664e9SAndroid Build Coastguard Worker          if (i == 0) {
198*d57664e9SAndroid Build Coastguard Worker              script[i++] = toupper(*scriptChars);
199*d57664e9SAndroid Build Coastguard Worker          } else {
200*d57664e9SAndroid Build Coastguard Worker              script[i++] = tolower(*scriptChars);
201*d57664e9SAndroid Build Coastguard Worker          }
202*d57664e9SAndroid Build Coastguard Worker          scriptChars++;
203*d57664e9SAndroid Build Coastguard Worker     }
204*d57664e9SAndroid Build Coastguard Worker }
205*d57664e9SAndroid Build Coastguard Worker 
setVariant(const char * variantChars)206*d57664e9SAndroid Build Coastguard Worker void AaptLocaleValue::setVariant(const char* variantChars) {
207*d57664e9SAndroid Build Coastguard Worker      size_t i = 0;
208*d57664e9SAndroid Build Coastguard Worker      while ((*variantChars) != '\0' && i < sizeof(variant)/sizeof(variant[0])) {
209*d57664e9SAndroid Build Coastguard Worker           variant[i++] = *variantChars;
210*d57664e9SAndroid Build Coastguard Worker           variantChars++;
211*d57664e9SAndroid Build Coastguard Worker      }
212*d57664e9SAndroid Build Coastguard Worker }
213*d57664e9SAndroid Build Coastguard Worker 
initFromFilterString(const String8 & str)214*d57664e9SAndroid Build Coastguard Worker bool AaptLocaleValue::initFromFilterString(const String8& str) {
215*d57664e9SAndroid Build Coastguard Worker      // A locale (as specified in the filter) is an underscore separated name such
216*d57664e9SAndroid Build Coastguard Worker      // as "en_US", "en_Latn_US", or "en_US_POSIX".
217*d57664e9SAndroid Build Coastguard Worker      Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '_');
218*d57664e9SAndroid Build Coastguard Worker 
219*d57664e9SAndroid Build Coastguard Worker      const int numTags = parts.size();
220*d57664e9SAndroid Build Coastguard Worker      bool valid = false;
221*d57664e9SAndroid Build Coastguard Worker      if (numTags >= 1) {
222*d57664e9SAndroid Build Coastguard Worker          const String8& lang = parts[0];
223*d57664e9SAndroid Build Coastguard Worker          if (isAlpha(lang) && (lang.length() == 2 || lang.length() == 3)) {
224*d57664e9SAndroid Build Coastguard Worker              setLanguage(lang.c_str());
225*d57664e9SAndroid Build Coastguard Worker              valid = true;
226*d57664e9SAndroid Build Coastguard Worker          }
227*d57664e9SAndroid Build Coastguard Worker      }
228*d57664e9SAndroid Build Coastguard Worker 
229*d57664e9SAndroid Build Coastguard Worker      if (!valid || numTags == 1) {
230*d57664e9SAndroid Build Coastguard Worker          return valid;
231*d57664e9SAndroid Build Coastguard Worker      }
232*d57664e9SAndroid Build Coastguard Worker 
233*d57664e9SAndroid Build Coastguard Worker      // At this point, valid == true && numTags > 1.
234*d57664e9SAndroid Build Coastguard Worker      const String8& part2 = parts[1];
235*d57664e9SAndroid Build Coastguard Worker      if ((part2.length() == 2 && isAlpha(part2)) ||
236*d57664e9SAndroid Build Coastguard Worker          (part2.length() == 3 && isNumber(part2))) {
237*d57664e9SAndroid Build Coastguard Worker          setRegion(part2.c_str());
238*d57664e9SAndroid Build Coastguard Worker      } else if (part2.length() == 4 && isAlpha(part2)) {
239*d57664e9SAndroid Build Coastguard Worker          setScript(part2.c_str());
240*d57664e9SAndroid Build Coastguard Worker      } else if (part2.length() >= 4 && part2.length() <= 8) {
241*d57664e9SAndroid Build Coastguard Worker          setVariant(part2.c_str());
242*d57664e9SAndroid Build Coastguard Worker      } else {
243*d57664e9SAndroid Build Coastguard Worker          valid = false;
244*d57664e9SAndroid Build Coastguard Worker      }
245*d57664e9SAndroid Build Coastguard Worker 
246*d57664e9SAndroid Build Coastguard Worker      if (!valid || numTags == 2) {
247*d57664e9SAndroid Build Coastguard Worker          return valid;
248*d57664e9SAndroid Build Coastguard Worker      }
249*d57664e9SAndroid Build Coastguard Worker 
250*d57664e9SAndroid Build Coastguard Worker      // At this point, valid == true && numTags > 1.
251*d57664e9SAndroid Build Coastguard Worker      const String8& part3 = parts[2];
252*d57664e9SAndroid Build Coastguard Worker      if (((part3.length() == 2 && isAlpha(part3)) ||
253*d57664e9SAndroid Build Coastguard Worker          (part3.length() == 3 && isNumber(part3))) && script[0]) {
254*d57664e9SAndroid Build Coastguard Worker          setRegion(part3.c_str());
255*d57664e9SAndroid Build Coastguard Worker      } else if (part3.length() >= 4 && part3.length() <= 8) {
256*d57664e9SAndroid Build Coastguard Worker          setVariant(part3.c_str());
257*d57664e9SAndroid Build Coastguard Worker      } else {
258*d57664e9SAndroid Build Coastguard Worker          valid = false;
259*d57664e9SAndroid Build Coastguard Worker      }
260*d57664e9SAndroid Build Coastguard Worker 
261*d57664e9SAndroid Build Coastguard Worker      if (!valid || numTags == 3) {
262*d57664e9SAndroid Build Coastguard Worker          return valid;
263*d57664e9SAndroid Build Coastguard Worker      }
264*d57664e9SAndroid Build Coastguard Worker 
265*d57664e9SAndroid Build Coastguard Worker      const String8& part4 = parts[3];
266*d57664e9SAndroid Build Coastguard Worker      if (part4.length() >= 4 && part4.length() <= 8) {
267*d57664e9SAndroid Build Coastguard Worker          setVariant(part4.c_str());
268*d57664e9SAndroid Build Coastguard Worker      } else {
269*d57664e9SAndroid Build Coastguard Worker          valid = false;
270*d57664e9SAndroid Build Coastguard Worker      }
271*d57664e9SAndroid Build Coastguard Worker 
272*d57664e9SAndroid Build Coastguard Worker      if (!valid || numTags > 4) {
273*d57664e9SAndroid Build Coastguard Worker          return false;
274*d57664e9SAndroid Build Coastguard Worker      }
275*d57664e9SAndroid Build Coastguard Worker 
276*d57664e9SAndroid Build Coastguard Worker      return true;
277*d57664e9SAndroid Build Coastguard Worker }
278*d57664e9SAndroid Build Coastguard Worker 
initFromDirName(const Vector<String8> & parts,const int startIndex)279*d57664e9SAndroid Build Coastguard Worker int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int startIndex) {
280*d57664e9SAndroid Build Coastguard Worker     const int size = parts.size();
281*d57664e9SAndroid Build Coastguard Worker     int currentIndex = startIndex;
282*d57664e9SAndroid Build Coastguard Worker 
283*d57664e9SAndroid Build Coastguard Worker     String8 part = parts[currentIndex];
284*d57664e9SAndroid Build Coastguard Worker     if (part[0] == 'b' && part[1] == '+') {
285*d57664e9SAndroid Build Coastguard Worker         // This is a "modified" BCP 47 language tag. Same semantics as BCP 47 tags,
286*d57664e9SAndroid Build Coastguard Worker         // except that the separator is "+" and not "-".
287*d57664e9SAndroid Build Coastguard Worker         Vector<String8> subtags = AaptUtil::splitAndLowerCase(part, '+');
288*d57664e9SAndroid Build Coastguard Worker         subtags.removeItemsAt(0);
289*d57664e9SAndroid Build Coastguard Worker         if (subtags.size() == 1) {
290*d57664e9SAndroid Build Coastguard Worker             setLanguage(subtags[0].c_str());
291*d57664e9SAndroid Build Coastguard Worker         } else if (subtags.size() == 2) {
292*d57664e9SAndroid Build Coastguard Worker             setLanguage(subtags[0].c_str());
293*d57664e9SAndroid Build Coastguard Worker 
294*d57664e9SAndroid Build Coastguard Worker             // The second tag can either be a region, a variant or a script.
295*d57664e9SAndroid Build Coastguard Worker             switch (subtags[1].size()) {
296*d57664e9SAndroid Build Coastguard Worker                 case 2:
297*d57664e9SAndroid Build Coastguard Worker                 case 3:
298*d57664e9SAndroid Build Coastguard Worker                     setRegion(subtags[1].c_str());
299*d57664e9SAndroid Build Coastguard Worker                     break;
300*d57664e9SAndroid Build Coastguard Worker                 case 4:
301*d57664e9SAndroid Build Coastguard Worker                     if (isAlpha(subtags[1])) {
302*d57664e9SAndroid Build Coastguard Worker                         setScript(subtags[1].c_str());
303*d57664e9SAndroid Build Coastguard Worker                         break;
304*d57664e9SAndroid Build Coastguard Worker                     }
305*d57664e9SAndroid Build Coastguard Worker                     // This is not alphabetical, so we fall through to variant
306*d57664e9SAndroid Build Coastguard Worker                     [[fallthrough]];
307*d57664e9SAndroid Build Coastguard Worker                 case 5:
308*d57664e9SAndroid Build Coastguard Worker                 case 6:
309*d57664e9SAndroid Build Coastguard Worker                 case 7:
310*d57664e9SAndroid Build Coastguard Worker                 case 8:
311*d57664e9SAndroid Build Coastguard Worker                     setVariant(subtags[1].c_str());
312*d57664e9SAndroid Build Coastguard Worker                     break;
313*d57664e9SAndroid Build Coastguard Worker                 default:
314*d57664e9SAndroid Build Coastguard Worker                     fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n",
315*d57664e9SAndroid Build Coastguard Worker                             part.c_str());
316*d57664e9SAndroid Build Coastguard Worker                     return -1;
317*d57664e9SAndroid Build Coastguard Worker             }
318*d57664e9SAndroid Build Coastguard Worker         } else if (subtags.size() == 3) {
319*d57664e9SAndroid Build Coastguard Worker             // The language is always the first subtag.
320*d57664e9SAndroid Build Coastguard Worker             setLanguage(subtags[0].c_str());
321*d57664e9SAndroid Build Coastguard Worker 
322*d57664e9SAndroid Build Coastguard Worker             // The second subtag can either be a script or a region code.
323*d57664e9SAndroid Build Coastguard Worker             // If its size is 4, it's a script code, else it's a region code.
324*d57664e9SAndroid Build Coastguard Worker             if (subtags[1].size() == 4) {
325*d57664e9SAndroid Build Coastguard Worker                 setScript(subtags[1].c_str());
326*d57664e9SAndroid Build Coastguard Worker             } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
327*d57664e9SAndroid Build Coastguard Worker                 setRegion(subtags[1].c_str());
328*d57664e9SAndroid Build Coastguard Worker             } else {
329*d57664e9SAndroid Build Coastguard Worker                 fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n", part.c_str());
330*d57664e9SAndroid Build Coastguard Worker                 return -1;
331*d57664e9SAndroid Build Coastguard Worker             }
332*d57664e9SAndroid Build Coastguard Worker 
333*d57664e9SAndroid Build Coastguard Worker             // The third tag can either be a region code (if the second tag was
334*d57664e9SAndroid Build Coastguard Worker             // a script), else a variant code.
335*d57664e9SAndroid Build Coastguard Worker             if (subtags[2].size() >= 4) {
336*d57664e9SAndroid Build Coastguard Worker                 setVariant(subtags[2].c_str());
337*d57664e9SAndroid Build Coastguard Worker             } else {
338*d57664e9SAndroid Build Coastguard Worker                 setRegion(subtags[2].c_str());
339*d57664e9SAndroid Build Coastguard Worker             }
340*d57664e9SAndroid Build Coastguard Worker         } else if (subtags.size() == 4) {
341*d57664e9SAndroid Build Coastguard Worker             setLanguage(subtags[0].c_str());
342*d57664e9SAndroid Build Coastguard Worker             setScript(subtags[1].c_str());
343*d57664e9SAndroid Build Coastguard Worker             setRegion(subtags[2].c_str());
344*d57664e9SAndroid Build Coastguard Worker             setVariant(subtags[3].c_str());
345*d57664e9SAndroid Build Coastguard Worker         } else {
346*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name: %s\n", part.c_str());
347*d57664e9SAndroid Build Coastguard Worker             return -1;
348*d57664e9SAndroid Build Coastguard Worker         }
349*d57664e9SAndroid Build Coastguard Worker 
350*d57664e9SAndroid Build Coastguard Worker         return ++currentIndex;
351*d57664e9SAndroid Build Coastguard Worker     } else {
352*d57664e9SAndroid Build Coastguard Worker         if ((part.length() == 2 || part.length() == 3)
353*d57664e9SAndroid Build Coastguard Worker                && isAlpha(part) && strcmp("car", part.c_str())) {
354*d57664e9SAndroid Build Coastguard Worker             setLanguage(part.c_str());
355*d57664e9SAndroid Build Coastguard Worker             if (++currentIndex == size) {
356*d57664e9SAndroid Build Coastguard Worker                 return size;
357*d57664e9SAndroid Build Coastguard Worker             }
358*d57664e9SAndroid Build Coastguard Worker         } else {
359*d57664e9SAndroid Build Coastguard Worker             return currentIndex;
360*d57664e9SAndroid Build Coastguard Worker         }
361*d57664e9SAndroid Build Coastguard Worker 
362*d57664e9SAndroid Build Coastguard Worker         part = parts[currentIndex];
363*d57664e9SAndroid Build Coastguard Worker         if (part.c_str()[0] == 'r' && part.length() == 3) {
364*d57664e9SAndroid Build Coastguard Worker             setRegion(part.c_str() + 1);
365*d57664e9SAndroid Build Coastguard Worker             if (++currentIndex == size) {
366*d57664e9SAndroid Build Coastguard Worker                 return size;
367*d57664e9SAndroid Build Coastguard Worker             }
368*d57664e9SAndroid Build Coastguard Worker         }
369*d57664e9SAndroid Build Coastguard Worker     }
370*d57664e9SAndroid Build Coastguard Worker 
371*d57664e9SAndroid Build Coastguard Worker     return currentIndex;
372*d57664e9SAndroid Build Coastguard Worker }
373*d57664e9SAndroid Build Coastguard Worker 
initFromResTable(const ResTable_config & config)374*d57664e9SAndroid Build Coastguard Worker void AaptLocaleValue::initFromResTable(const ResTable_config& config) {
375*d57664e9SAndroid Build Coastguard Worker     config.unpackLanguage(language);
376*d57664e9SAndroid Build Coastguard Worker     config.unpackRegion(region);
377*d57664e9SAndroid Build Coastguard Worker     if (config.localeScript[0] && !config.localeScriptWasComputed) {
378*d57664e9SAndroid Build Coastguard Worker         memcpy(script, config.localeScript, sizeof(config.localeScript));
379*d57664e9SAndroid Build Coastguard Worker     }
380*d57664e9SAndroid Build Coastguard Worker 
381*d57664e9SAndroid Build Coastguard Worker     if (config.localeVariant[0]) {
382*d57664e9SAndroid Build Coastguard Worker         memcpy(variant, config.localeVariant, sizeof(config.localeVariant));
383*d57664e9SAndroid Build Coastguard Worker     }
384*d57664e9SAndroid Build Coastguard Worker }
385*d57664e9SAndroid Build Coastguard Worker 
writeTo(ResTable_config * out) const386*d57664e9SAndroid Build Coastguard Worker void AaptLocaleValue::writeTo(ResTable_config* out) const {
387*d57664e9SAndroid Build Coastguard Worker     out->packLanguage(language);
388*d57664e9SAndroid Build Coastguard Worker     out->packRegion(region);
389*d57664e9SAndroid Build Coastguard Worker 
390*d57664e9SAndroid Build Coastguard Worker     if (script[0]) {
391*d57664e9SAndroid Build Coastguard Worker         memcpy(out->localeScript, script, sizeof(out->localeScript));
392*d57664e9SAndroid Build Coastguard Worker     }
393*d57664e9SAndroid Build Coastguard Worker 
394*d57664e9SAndroid Build Coastguard Worker     if (variant[0]) {
395*d57664e9SAndroid Build Coastguard Worker         memcpy(out->localeVariant, variant, sizeof(out->localeVariant));
396*d57664e9SAndroid Build Coastguard Worker     }
397*d57664e9SAndroid Build Coastguard Worker }
398*d57664e9SAndroid Build Coastguard Worker 
399*d57664e9SAndroid Build Coastguard Worker bool
initFromDirName(const char * dir,String8 * resType)400*d57664e9SAndroid Build Coastguard Worker AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
401*d57664e9SAndroid Build Coastguard Worker {
402*d57664e9SAndroid Build Coastguard Worker     const char* q = strchr(dir, '-');
403*d57664e9SAndroid Build Coastguard Worker     size_t typeLen;
404*d57664e9SAndroid Build Coastguard Worker     if (q != NULL) {
405*d57664e9SAndroid Build Coastguard Worker         typeLen = q - dir;
406*d57664e9SAndroid Build Coastguard Worker     } else {
407*d57664e9SAndroid Build Coastguard Worker         typeLen = strlen(dir);
408*d57664e9SAndroid Build Coastguard Worker     }
409*d57664e9SAndroid Build Coastguard Worker 
410*d57664e9SAndroid Build Coastguard Worker     String8 type(dir, typeLen);
411*d57664e9SAndroid Build Coastguard Worker     if (!isValidResourceType(type)) {
412*d57664e9SAndroid Build Coastguard Worker         return false;
413*d57664e9SAndroid Build Coastguard Worker     }
414*d57664e9SAndroid Build Coastguard Worker 
415*d57664e9SAndroid Build Coastguard Worker     if (q != NULL) {
416*d57664e9SAndroid Build Coastguard Worker         if (!AaptConfig::parse(String8(q + 1), &mParams)) {
417*d57664e9SAndroid Build Coastguard Worker             return false;
418*d57664e9SAndroid Build Coastguard Worker         }
419*d57664e9SAndroid Build Coastguard Worker     }
420*d57664e9SAndroid Build Coastguard Worker 
421*d57664e9SAndroid Build Coastguard Worker     *resType = type;
422*d57664e9SAndroid Build Coastguard Worker     return true;
423*d57664e9SAndroid Build Coastguard Worker }
424*d57664e9SAndroid Build Coastguard Worker 
425*d57664e9SAndroid Build Coastguard Worker String8
toDirName(const String8 & resType) const426*d57664e9SAndroid Build Coastguard Worker AaptGroupEntry::toDirName(const String8& resType) const
427*d57664e9SAndroid Build Coastguard Worker {
428*d57664e9SAndroid Build Coastguard Worker     String8 s = resType;
429*d57664e9SAndroid Build Coastguard Worker     String8 params = mParams.toString();
430*d57664e9SAndroid Build Coastguard Worker     if (params.length() > 0) {
431*d57664e9SAndroid Build Coastguard Worker         if (s.length() > 0) {
432*d57664e9SAndroid Build Coastguard Worker             s += "-";
433*d57664e9SAndroid Build Coastguard Worker         }
434*d57664e9SAndroid Build Coastguard Worker         s += params;
435*d57664e9SAndroid Build Coastguard Worker     }
436*d57664e9SAndroid Build Coastguard Worker     return s;
437*d57664e9SAndroid Build Coastguard Worker }
438*d57664e9SAndroid Build Coastguard Worker 
439*d57664e9SAndroid Build Coastguard Worker 
440*d57664e9SAndroid Build Coastguard Worker // =========================================================================
441*d57664e9SAndroid Build Coastguard Worker // =========================================================================
442*d57664e9SAndroid Build Coastguard Worker // =========================================================================
443*d57664e9SAndroid Build Coastguard Worker 
editData(size_t size)444*d57664e9SAndroid Build Coastguard Worker void* AaptFile::editData(size_t size)
445*d57664e9SAndroid Build Coastguard Worker {
446*d57664e9SAndroid Build Coastguard Worker     if (size <= mBufferSize) {
447*d57664e9SAndroid Build Coastguard Worker         mDataSize = size;
448*d57664e9SAndroid Build Coastguard Worker         return mData;
449*d57664e9SAndroid Build Coastguard Worker     }
450*d57664e9SAndroid Build Coastguard Worker     size_t allocSize = (size*3)/2;
451*d57664e9SAndroid Build Coastguard Worker     void* buf = realloc(mData, allocSize);
452*d57664e9SAndroid Build Coastguard Worker     if (buf == NULL) {
453*d57664e9SAndroid Build Coastguard Worker         return NULL;
454*d57664e9SAndroid Build Coastguard Worker     }
455*d57664e9SAndroid Build Coastguard Worker     mData = buf;
456*d57664e9SAndroid Build Coastguard Worker     mDataSize = size;
457*d57664e9SAndroid Build Coastguard Worker     mBufferSize = allocSize;
458*d57664e9SAndroid Build Coastguard Worker     return buf;
459*d57664e9SAndroid Build Coastguard Worker }
460*d57664e9SAndroid Build Coastguard Worker 
editDataInRange(size_t offset,size_t size)461*d57664e9SAndroid Build Coastguard Worker void* AaptFile::editDataInRange(size_t offset, size_t size)
462*d57664e9SAndroid Build Coastguard Worker {
463*d57664e9SAndroid Build Coastguard Worker     return (void*)(((uint8_t*) editData(offset + size)) + offset);
464*d57664e9SAndroid Build Coastguard Worker }
465*d57664e9SAndroid Build Coastguard Worker 
editData(size_t * outSize)466*d57664e9SAndroid Build Coastguard Worker void* AaptFile::editData(size_t* outSize)
467*d57664e9SAndroid Build Coastguard Worker {
468*d57664e9SAndroid Build Coastguard Worker     if (outSize) {
469*d57664e9SAndroid Build Coastguard Worker         *outSize = mDataSize;
470*d57664e9SAndroid Build Coastguard Worker     }
471*d57664e9SAndroid Build Coastguard Worker     return mData;
472*d57664e9SAndroid Build Coastguard Worker }
473*d57664e9SAndroid Build Coastguard Worker 
padData(size_t wordSize)474*d57664e9SAndroid Build Coastguard Worker void* AaptFile::padData(size_t wordSize)
475*d57664e9SAndroid Build Coastguard Worker {
476*d57664e9SAndroid Build Coastguard Worker     const size_t extra = mDataSize%wordSize;
477*d57664e9SAndroid Build Coastguard Worker     if (extra == 0) {
478*d57664e9SAndroid Build Coastguard Worker         return mData;
479*d57664e9SAndroid Build Coastguard Worker     }
480*d57664e9SAndroid Build Coastguard Worker 
481*d57664e9SAndroid Build Coastguard Worker     size_t initial = mDataSize;
482*d57664e9SAndroid Build Coastguard Worker     void* data = editData(initial+(wordSize-extra));
483*d57664e9SAndroid Build Coastguard Worker     if (data != NULL) {
484*d57664e9SAndroid Build Coastguard Worker         memset(((uint8_t*)data) + initial, 0, wordSize-extra);
485*d57664e9SAndroid Build Coastguard Worker     }
486*d57664e9SAndroid Build Coastguard Worker     return data;
487*d57664e9SAndroid Build Coastguard Worker }
488*d57664e9SAndroid Build Coastguard Worker 
writeData(const void * data,size_t size)489*d57664e9SAndroid Build Coastguard Worker status_t AaptFile::writeData(const void* data, size_t size)
490*d57664e9SAndroid Build Coastguard Worker {
491*d57664e9SAndroid Build Coastguard Worker     size_t end = mDataSize;
492*d57664e9SAndroid Build Coastguard Worker     size_t total = size + end;
493*d57664e9SAndroid Build Coastguard Worker     void* buf = editData(total);
494*d57664e9SAndroid Build Coastguard Worker     if (buf == NULL) {
495*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
496*d57664e9SAndroid Build Coastguard Worker     }
497*d57664e9SAndroid Build Coastguard Worker     memcpy(((char*)buf)+end, data, size);
498*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
499*d57664e9SAndroid Build Coastguard Worker }
500*d57664e9SAndroid Build Coastguard Worker 
clearData()501*d57664e9SAndroid Build Coastguard Worker void AaptFile::clearData()
502*d57664e9SAndroid Build Coastguard Worker {
503*d57664e9SAndroid Build Coastguard Worker     if (mData != NULL) free(mData);
504*d57664e9SAndroid Build Coastguard Worker     mData = NULL;
505*d57664e9SAndroid Build Coastguard Worker     mDataSize = 0;
506*d57664e9SAndroid Build Coastguard Worker     mBufferSize = 0;
507*d57664e9SAndroid Build Coastguard Worker }
508*d57664e9SAndroid Build Coastguard Worker 
getPrintableSource() const509*d57664e9SAndroid Build Coastguard Worker String8 AaptFile::getPrintableSource() const
510*d57664e9SAndroid Build Coastguard Worker {
511*d57664e9SAndroid Build Coastguard Worker     if (hasData()) {
512*d57664e9SAndroid Build Coastguard Worker         String8 name(mGroupEntry.toDirName(String8()));
513*d57664e9SAndroid Build Coastguard Worker         appendPath(name, mPath);
514*d57664e9SAndroid Build Coastguard Worker         name.append(" #generated");
515*d57664e9SAndroid Build Coastguard Worker         return name;
516*d57664e9SAndroid Build Coastguard Worker     }
517*d57664e9SAndroid Build Coastguard Worker     return mSourceFile;
518*d57664e9SAndroid Build Coastguard Worker }
519*d57664e9SAndroid Build Coastguard Worker 
520*d57664e9SAndroid Build Coastguard Worker // =========================================================================
521*d57664e9SAndroid Build Coastguard Worker // =========================================================================
522*d57664e9SAndroid Build Coastguard Worker // =========================================================================
523*d57664e9SAndroid Build Coastguard Worker 
addFile(const sp<AaptFile> & file,const bool overwriteDuplicate)524*d57664e9SAndroid Build Coastguard Worker status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplicate)
525*d57664e9SAndroid Build Coastguard Worker {
526*d57664e9SAndroid Build Coastguard Worker     ssize_t index = mFiles.indexOfKey(file->getGroupEntry());
527*d57664e9SAndroid Build Coastguard Worker     if (index >= 0 && overwriteDuplicate) {
528*d57664e9SAndroid Build Coastguard Worker         fprintf(stderr, "warning: overwriting '%s' with '%s'\n",
529*d57664e9SAndroid Build Coastguard Worker                 mFiles[index]->getSourceFile().c_str(),
530*d57664e9SAndroid Build Coastguard Worker                 file->getSourceFile().c_str());
531*d57664e9SAndroid Build Coastguard Worker         removeFile(index);
532*d57664e9SAndroid Build Coastguard Worker         index = -1;
533*d57664e9SAndroid Build Coastguard Worker     }
534*d57664e9SAndroid Build Coastguard Worker 
535*d57664e9SAndroid Build Coastguard Worker     if (index < 0) {
536*d57664e9SAndroid Build Coastguard Worker         file->mPath = mPath;
537*d57664e9SAndroid Build Coastguard Worker         mFiles.add(file->getGroupEntry(), file);
538*d57664e9SAndroid Build Coastguard Worker         return NO_ERROR;
539*d57664e9SAndroid Build Coastguard Worker     }
540*d57664e9SAndroid Build Coastguard Worker 
541*d57664e9SAndroid Build Coastguard Worker     // Check if the version is automatically applied. This is a common source of
542*d57664e9SAndroid Build Coastguard Worker     // error.
543*d57664e9SAndroid Build Coastguard Worker     ConfigDescription withoutVersion = file->getGroupEntry().toParams();
544*d57664e9SAndroid Build Coastguard Worker     withoutVersion.version = 0;
545*d57664e9SAndroid Build Coastguard Worker     AaptConfig::applyVersionForCompatibility(&withoutVersion);
546*d57664e9SAndroid Build Coastguard Worker 
547*d57664e9SAndroid Build Coastguard Worker     const sp<AaptFile>& originalFile = mFiles.valueAt(index);
548*d57664e9SAndroid Build Coastguard Worker     SourcePos(file->getSourceFile(), -1)
549*d57664e9SAndroid Build Coastguard Worker             .error("Duplicate file.\n%s: Original is here. %s",
550*d57664e9SAndroid Build Coastguard Worker                    originalFile->getPrintableSource().c_str(),
551*d57664e9SAndroid Build Coastguard Worker                    (withoutVersion.version != 0) ? "The version qualifier may be implied." : "");
552*d57664e9SAndroid Build Coastguard Worker     return UNKNOWN_ERROR;
553*d57664e9SAndroid Build Coastguard Worker }
554*d57664e9SAndroid Build Coastguard Worker 
removeFile(size_t index)555*d57664e9SAndroid Build Coastguard Worker void AaptGroup::removeFile(size_t index)
556*d57664e9SAndroid Build Coastguard Worker {
557*d57664e9SAndroid Build Coastguard Worker 	mFiles.removeItemsAt(index);
558*d57664e9SAndroid Build Coastguard Worker }
559*d57664e9SAndroid Build Coastguard Worker 
print(const String8 & prefix) const560*d57664e9SAndroid Build Coastguard Worker void AaptGroup::print(const String8& prefix) const
561*d57664e9SAndroid Build Coastguard Worker {
562*d57664e9SAndroid Build Coastguard Worker     printf("%s%s\n", prefix.c_str(), getPath().c_str());
563*d57664e9SAndroid Build Coastguard Worker     const size_t N=mFiles.size();
564*d57664e9SAndroid Build Coastguard Worker     size_t i;
565*d57664e9SAndroid Build Coastguard Worker     for (i=0; i<N; i++) {
566*d57664e9SAndroid Build Coastguard Worker         sp<AaptFile> file = mFiles.valueAt(i);
567*d57664e9SAndroid Build Coastguard Worker         const AaptGroupEntry& e = file->getGroupEntry();
568*d57664e9SAndroid Build Coastguard Worker         if (file->hasData()) {
569*d57664e9SAndroid Build Coastguard Worker             printf("%s  Gen: (%s) %d bytes\n", prefix.c_str(), e.toDirName(String8()).c_str(),
570*d57664e9SAndroid Build Coastguard Worker                     (int)file->getSize());
571*d57664e9SAndroid Build Coastguard Worker         } else {
572*d57664e9SAndroid Build Coastguard Worker             printf("%s  Src: (%s) %s\n", prefix.c_str(), e.toDirName(String8()).c_str(),
573*d57664e9SAndroid Build Coastguard Worker                     file->getPrintableSource().c_str());
574*d57664e9SAndroid Build Coastguard Worker         }
575*d57664e9SAndroid Build Coastguard Worker         //printf("%s  File Group Entry: %s\n", prefix.c_str(),
576*d57664e9SAndroid Build Coastguard Worker         //        file->getGroupEntry().toDirName(String8()).c_str());
577*d57664e9SAndroid Build Coastguard Worker     }
578*d57664e9SAndroid Build Coastguard Worker }
579*d57664e9SAndroid Build Coastguard Worker 
getPrintableSource() const580*d57664e9SAndroid Build Coastguard Worker String8 AaptGroup::getPrintableSource() const
581*d57664e9SAndroid Build Coastguard Worker {
582*d57664e9SAndroid Build Coastguard Worker     if (mFiles.size() > 0) {
583*d57664e9SAndroid Build Coastguard Worker         // Arbitrarily pull the first source file out of the list.
584*d57664e9SAndroid Build Coastguard Worker         return mFiles.valueAt(0)->getPrintableSource();
585*d57664e9SAndroid Build Coastguard Worker     }
586*d57664e9SAndroid Build Coastguard Worker 
587*d57664e9SAndroid Build Coastguard Worker     // Should never hit this case, but to be safe...
588*d57664e9SAndroid Build Coastguard Worker     return getPath();
589*d57664e9SAndroid Build Coastguard Worker 
590*d57664e9SAndroid Build Coastguard Worker }
591*d57664e9SAndroid Build Coastguard Worker 
592*d57664e9SAndroid Build Coastguard Worker // =========================================================================
593*d57664e9SAndroid Build Coastguard Worker // =========================================================================
594*d57664e9SAndroid Build Coastguard Worker // =========================================================================
595*d57664e9SAndroid Build Coastguard Worker 
addFile(const String8 & name,const sp<AaptGroup> & file)596*d57664e9SAndroid Build Coastguard Worker status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
597*d57664e9SAndroid Build Coastguard Worker {
598*d57664e9SAndroid Build Coastguard Worker     if (mFiles.indexOfKey(name) >= 0) {
599*d57664e9SAndroid Build Coastguard Worker         return ALREADY_EXISTS;
600*d57664e9SAndroid Build Coastguard Worker     }
601*d57664e9SAndroid Build Coastguard Worker     mFiles.add(name, file);
602*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
603*d57664e9SAndroid Build Coastguard Worker }
604*d57664e9SAndroid Build Coastguard Worker 
addDir(const String8 & name,const sp<AaptDir> & dir)605*d57664e9SAndroid Build Coastguard Worker status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
606*d57664e9SAndroid Build Coastguard Worker {
607*d57664e9SAndroid Build Coastguard Worker     if (mDirs.indexOfKey(name) >= 0) {
608*d57664e9SAndroid Build Coastguard Worker         return ALREADY_EXISTS;
609*d57664e9SAndroid Build Coastguard Worker     }
610*d57664e9SAndroid Build Coastguard Worker     mDirs.add(name, dir);
611*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
612*d57664e9SAndroid Build Coastguard Worker }
613*d57664e9SAndroid Build Coastguard Worker 
makeDir(const String8 & path)614*d57664e9SAndroid Build Coastguard Worker sp<AaptDir> AaptDir::makeDir(const String8& path)
615*d57664e9SAndroid Build Coastguard Worker {
616*d57664e9SAndroid Build Coastguard Worker     String8 name;
617*d57664e9SAndroid Build Coastguard Worker     String8 remain = path;
618*d57664e9SAndroid Build Coastguard Worker 
619*d57664e9SAndroid Build Coastguard Worker     sp<AaptDir> subdir = this;
620*d57664e9SAndroid Build Coastguard Worker     while (name = walkPath(remain, &remain), remain != "") {
621*d57664e9SAndroid Build Coastguard Worker         subdir = subdir->makeDir(name);
622*d57664e9SAndroid Build Coastguard Worker     }
623*d57664e9SAndroid Build Coastguard Worker 
624*d57664e9SAndroid Build Coastguard Worker     ssize_t i = subdir->mDirs.indexOfKey(name);
625*d57664e9SAndroid Build Coastguard Worker     if (i >= 0) {
626*d57664e9SAndroid Build Coastguard Worker         return subdir->mDirs.valueAt(i);
627*d57664e9SAndroid Build Coastguard Worker     }
628*d57664e9SAndroid Build Coastguard Worker     sp<AaptDir> dir = new AaptDir(name, appendPathCopy(subdir->mPath, name));
629*d57664e9SAndroid Build Coastguard Worker     subdir->mDirs.add(name, dir);
630*d57664e9SAndroid Build Coastguard Worker     return dir;
631*d57664e9SAndroid Build Coastguard Worker }
632*d57664e9SAndroid Build Coastguard Worker 
removeFile(const String8 & name)633*d57664e9SAndroid Build Coastguard Worker void AaptDir::removeFile(const String8& name)
634*d57664e9SAndroid Build Coastguard Worker {
635*d57664e9SAndroid Build Coastguard Worker     mFiles.removeItem(name);
636*d57664e9SAndroid Build Coastguard Worker }
637*d57664e9SAndroid Build Coastguard Worker 
removeDir(const String8 & name)638*d57664e9SAndroid Build Coastguard Worker void AaptDir::removeDir(const String8& name)
639*d57664e9SAndroid Build Coastguard Worker {
640*d57664e9SAndroid Build Coastguard Worker     mDirs.removeItem(name);
641*d57664e9SAndroid Build Coastguard Worker }
642*d57664e9SAndroid Build Coastguard Worker 
addLeafFile(const String8 & leafName,const sp<AaptFile> & file,const bool overwrite)643*d57664e9SAndroid Build Coastguard Worker status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file,
644*d57664e9SAndroid Build Coastguard Worker         const bool overwrite)
645*d57664e9SAndroid Build Coastguard Worker {
646*d57664e9SAndroid Build Coastguard Worker     sp<AaptGroup> group;
647*d57664e9SAndroid Build Coastguard Worker     if (mFiles.indexOfKey(leafName) >= 0) {
648*d57664e9SAndroid Build Coastguard Worker         group = mFiles.valueFor(leafName);
649*d57664e9SAndroid Build Coastguard Worker     } else {
650*d57664e9SAndroid Build Coastguard Worker         group = new AaptGroup(leafName, appendPathCopy(mPath, leafName));
651*d57664e9SAndroid Build Coastguard Worker         mFiles.add(leafName, group);
652*d57664e9SAndroid Build Coastguard Worker     }
653*d57664e9SAndroid Build Coastguard Worker 
654*d57664e9SAndroid Build Coastguard Worker     return group->addFile(file, overwrite);
655*d57664e9SAndroid Build Coastguard Worker }
656*d57664e9SAndroid Build Coastguard Worker 
slurpFullTree(Bundle * bundle,const String8 & srcDir,const AaptGroupEntry & kind,const String8 & resType,sp<FilePathStore> & fullResPaths,const bool overwrite)657*d57664e9SAndroid Build Coastguard Worker ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
658*d57664e9SAndroid Build Coastguard Worker                             const AaptGroupEntry& kind, const String8& resType,
659*d57664e9SAndroid Build Coastguard Worker                             sp<FilePathStore>& fullResPaths, const bool overwrite)
660*d57664e9SAndroid Build Coastguard Worker {
661*d57664e9SAndroid Build Coastguard Worker     Vector<String8> fileNames;
662*d57664e9SAndroid Build Coastguard Worker     {
663*d57664e9SAndroid Build Coastguard Worker         DIR* dir = NULL;
664*d57664e9SAndroid Build Coastguard Worker 
665*d57664e9SAndroid Build Coastguard Worker         dir = opendir(srcDir.c_str());
666*d57664e9SAndroid Build Coastguard Worker         if (dir == NULL) {
667*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.c_str(), strerror(errno));
668*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
669*d57664e9SAndroid Build Coastguard Worker         }
670*d57664e9SAndroid Build Coastguard Worker 
671*d57664e9SAndroid Build Coastguard Worker         /*
672*d57664e9SAndroid Build Coastguard Worker          * Slurp the filenames out of the directory.
673*d57664e9SAndroid Build Coastguard Worker          */
674*d57664e9SAndroid Build Coastguard Worker         while (1) {
675*d57664e9SAndroid Build Coastguard Worker             struct dirent* entry;
676*d57664e9SAndroid Build Coastguard Worker 
677*d57664e9SAndroid Build Coastguard Worker             entry = readdir(dir);
678*d57664e9SAndroid Build Coastguard Worker             if (entry == NULL)
679*d57664e9SAndroid Build Coastguard Worker                 break;
680*d57664e9SAndroid Build Coastguard Worker 
681*d57664e9SAndroid Build Coastguard Worker             if (isHidden(srcDir.c_str(), entry->d_name))
682*d57664e9SAndroid Build Coastguard Worker                 continue;
683*d57664e9SAndroid Build Coastguard Worker 
684*d57664e9SAndroid Build Coastguard Worker             String8 name(entry->d_name);
685*d57664e9SAndroid Build Coastguard Worker             fileNames.add(name);
686*d57664e9SAndroid Build Coastguard Worker             // Add fully qualified path for dependency purposes
687*d57664e9SAndroid Build Coastguard Worker             // if we're collecting them
688*d57664e9SAndroid Build Coastguard Worker             if (fullResPaths != NULL) {
689*d57664e9SAndroid Build Coastguard Worker                 fullResPaths->add(appendPathCopy(srcDir, name));
690*d57664e9SAndroid Build Coastguard Worker             }
691*d57664e9SAndroid Build Coastguard Worker         }
692*d57664e9SAndroid Build Coastguard Worker         closedir(dir);
693*d57664e9SAndroid Build Coastguard Worker     }
694*d57664e9SAndroid Build Coastguard Worker 
695*d57664e9SAndroid Build Coastguard Worker     ssize_t count = 0;
696*d57664e9SAndroid Build Coastguard Worker 
697*d57664e9SAndroid Build Coastguard Worker     /*
698*d57664e9SAndroid Build Coastguard Worker      * Stash away the files and recursively descend into subdirectories.
699*d57664e9SAndroid Build Coastguard Worker      */
700*d57664e9SAndroid Build Coastguard Worker     const size_t N = fileNames.size();
701*d57664e9SAndroid Build Coastguard Worker     size_t i;
702*d57664e9SAndroid Build Coastguard Worker     for (i = 0; i < N; i++) {
703*d57664e9SAndroid Build Coastguard Worker         String8 pathName(srcDir);
704*d57664e9SAndroid Build Coastguard Worker         FileType type;
705*d57664e9SAndroid Build Coastguard Worker 
706*d57664e9SAndroid Build Coastguard Worker         appendPath(pathName, fileNames[i]);
707*d57664e9SAndroid Build Coastguard Worker         type = getFileType(pathName.c_str());
708*d57664e9SAndroid Build Coastguard Worker         if (type == kFileTypeDirectory) {
709*d57664e9SAndroid Build Coastguard Worker             sp<AaptDir> subdir;
710*d57664e9SAndroid Build Coastguard Worker             bool notAdded = false;
711*d57664e9SAndroid Build Coastguard Worker             if (mDirs.indexOfKey(fileNames[i]) >= 0) {
712*d57664e9SAndroid Build Coastguard Worker                 subdir = mDirs.valueFor(fileNames[i]);
713*d57664e9SAndroid Build Coastguard Worker             } else {
714*d57664e9SAndroid Build Coastguard Worker                 subdir = new AaptDir(fileNames[i], appendPathCopy(mPath, fileNames[i]));
715*d57664e9SAndroid Build Coastguard Worker                 notAdded = true;
716*d57664e9SAndroid Build Coastguard Worker             }
717*d57664e9SAndroid Build Coastguard Worker             ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
718*d57664e9SAndroid Build Coastguard Worker                                                 resType, fullResPaths, overwrite);
719*d57664e9SAndroid Build Coastguard Worker             if (res < NO_ERROR) {
720*d57664e9SAndroid Build Coastguard Worker                 return res;
721*d57664e9SAndroid Build Coastguard Worker             }
722*d57664e9SAndroid Build Coastguard Worker             if (res > 0 && notAdded) {
723*d57664e9SAndroid Build Coastguard Worker                 mDirs.add(fileNames[i], subdir);
724*d57664e9SAndroid Build Coastguard Worker             }
725*d57664e9SAndroid Build Coastguard Worker             count += res;
726*d57664e9SAndroid Build Coastguard Worker         } else if (type == kFileTypeRegular) {
727*d57664e9SAndroid Build Coastguard Worker             sp<AaptFile> file = new AaptFile(pathName, kind, resType);
728*d57664e9SAndroid Build Coastguard Worker             status_t err = addLeafFile(fileNames[i], file, overwrite);
729*d57664e9SAndroid Build Coastguard Worker             if (err != NO_ERROR) {
730*d57664e9SAndroid Build Coastguard Worker                 return err;
731*d57664e9SAndroid Build Coastguard Worker             }
732*d57664e9SAndroid Build Coastguard Worker 
733*d57664e9SAndroid Build Coastguard Worker             count++;
734*d57664e9SAndroid Build Coastguard Worker 
735*d57664e9SAndroid Build Coastguard Worker         } else {
736*d57664e9SAndroid Build Coastguard Worker             if (bundle->getVerbose())
737*d57664e9SAndroid Build Coastguard Worker                 printf("   (ignoring non-file/dir '%s')\n", pathName.c_str());
738*d57664e9SAndroid Build Coastguard Worker         }
739*d57664e9SAndroid Build Coastguard Worker     }
740*d57664e9SAndroid Build Coastguard Worker 
741*d57664e9SAndroid Build Coastguard Worker     return count;
742*d57664e9SAndroid Build Coastguard Worker }
743*d57664e9SAndroid Build Coastguard Worker 
validate() const744*d57664e9SAndroid Build Coastguard Worker status_t AaptDir::validate() const
745*d57664e9SAndroid Build Coastguard Worker {
746*d57664e9SAndroid Build Coastguard Worker     const size_t NF = mFiles.size();
747*d57664e9SAndroid Build Coastguard Worker     const size_t ND = mDirs.size();
748*d57664e9SAndroid Build Coastguard Worker     size_t i;
749*d57664e9SAndroid Build Coastguard Worker     for (i = 0; i < NF; i++) {
750*d57664e9SAndroid Build Coastguard Worker         if (!validateFileName(mFiles.valueAt(i)->getLeaf().c_str())) {
751*d57664e9SAndroid Build Coastguard Worker             SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
752*d57664e9SAndroid Build Coastguard Worker                     "Invalid filename.  Unable to add.");
753*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
754*d57664e9SAndroid Build Coastguard Worker         }
755*d57664e9SAndroid Build Coastguard Worker 
756*d57664e9SAndroid Build Coastguard Worker         size_t j;
757*d57664e9SAndroid Build Coastguard Worker         for (j = i+1; j < NF; j++) {
758*d57664e9SAndroid Build Coastguard Worker             if (strcasecmp(mFiles.valueAt(i)->getLeaf().c_str(),
759*d57664e9SAndroid Build Coastguard Worker                            mFiles.valueAt(j)->getLeaf().c_str()) == 0) {
760*d57664e9SAndroid Build Coastguard Worker                 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
761*d57664e9SAndroid Build Coastguard Worker                         "File is case-insensitive equivalent to: %s",
762*d57664e9SAndroid Build Coastguard Worker                         mFiles.valueAt(j)->getPrintableSource().c_str());
763*d57664e9SAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
764*d57664e9SAndroid Build Coastguard Worker             }
765*d57664e9SAndroid Build Coastguard Worker 
766*d57664e9SAndroid Build Coastguard Worker             // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
767*d57664e9SAndroid Build Coastguard Worker             // (this is mostly caught by the "marked" stuff, below)
768*d57664e9SAndroid Build Coastguard Worker         }
769*d57664e9SAndroid Build Coastguard Worker 
770*d57664e9SAndroid Build Coastguard Worker         for (j = 0; j < ND; j++) {
771*d57664e9SAndroid Build Coastguard Worker             if (strcasecmp(mFiles.valueAt(i)->getLeaf().c_str(),
772*d57664e9SAndroid Build Coastguard Worker                            mDirs.valueAt(j)->getLeaf().c_str()) == 0) {
773*d57664e9SAndroid Build Coastguard Worker                 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
774*d57664e9SAndroid Build Coastguard Worker                         "File conflicts with dir from: %s",
775*d57664e9SAndroid Build Coastguard Worker                         mDirs.valueAt(j)->getPrintableSource().c_str());
776*d57664e9SAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
777*d57664e9SAndroid Build Coastguard Worker             }
778*d57664e9SAndroid Build Coastguard Worker         }
779*d57664e9SAndroid Build Coastguard Worker     }
780*d57664e9SAndroid Build Coastguard Worker 
781*d57664e9SAndroid Build Coastguard Worker     for (i = 0; i < ND; i++) {
782*d57664e9SAndroid Build Coastguard Worker         if (!validateFileName(mDirs.valueAt(i)->getLeaf().c_str())) {
783*d57664e9SAndroid Build Coastguard Worker             SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
784*d57664e9SAndroid Build Coastguard Worker                     "Invalid directory name, unable to add.");
785*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
786*d57664e9SAndroid Build Coastguard Worker         }
787*d57664e9SAndroid Build Coastguard Worker 
788*d57664e9SAndroid Build Coastguard Worker         size_t j;
789*d57664e9SAndroid Build Coastguard Worker         for (j = i+1; j < ND; j++) {
790*d57664e9SAndroid Build Coastguard Worker             if (strcasecmp(mDirs.valueAt(i)->getLeaf().c_str(),
791*d57664e9SAndroid Build Coastguard Worker                            mDirs.valueAt(j)->getLeaf().c_str()) == 0) {
792*d57664e9SAndroid Build Coastguard Worker                 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
793*d57664e9SAndroid Build Coastguard Worker                         "Directory is case-insensitive equivalent to: %s",
794*d57664e9SAndroid Build Coastguard Worker                         mDirs.valueAt(j)->getPrintableSource().c_str());
795*d57664e9SAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
796*d57664e9SAndroid Build Coastguard Worker             }
797*d57664e9SAndroid Build Coastguard Worker         }
798*d57664e9SAndroid Build Coastguard Worker 
799*d57664e9SAndroid Build Coastguard Worker         status_t err = mDirs.valueAt(i)->validate();
800*d57664e9SAndroid Build Coastguard Worker         if (err != NO_ERROR) {
801*d57664e9SAndroid Build Coastguard Worker             return err;
802*d57664e9SAndroid Build Coastguard Worker         }
803*d57664e9SAndroid Build Coastguard Worker     }
804*d57664e9SAndroid Build Coastguard Worker 
805*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
806*d57664e9SAndroid Build Coastguard Worker }
807*d57664e9SAndroid Build Coastguard Worker 
print(const String8 & prefix) const808*d57664e9SAndroid Build Coastguard Worker void AaptDir::print(const String8& prefix) const
809*d57664e9SAndroid Build Coastguard Worker {
810*d57664e9SAndroid Build Coastguard Worker     const size_t ND=getDirs().size();
811*d57664e9SAndroid Build Coastguard Worker     size_t i;
812*d57664e9SAndroid Build Coastguard Worker     for (i=0; i<ND; i++) {
813*d57664e9SAndroid Build Coastguard Worker         getDirs().valueAt(i)->print(prefix);
814*d57664e9SAndroid Build Coastguard Worker     }
815*d57664e9SAndroid Build Coastguard Worker 
816*d57664e9SAndroid Build Coastguard Worker     const size_t NF=getFiles().size();
817*d57664e9SAndroid Build Coastguard Worker     for (i=0; i<NF; i++) {
818*d57664e9SAndroid Build Coastguard Worker         getFiles().valueAt(i)->print(prefix);
819*d57664e9SAndroid Build Coastguard Worker     }
820*d57664e9SAndroid Build Coastguard Worker }
821*d57664e9SAndroid Build Coastguard Worker 
getPrintableSource() const822*d57664e9SAndroid Build Coastguard Worker String8 AaptDir::getPrintableSource() const
823*d57664e9SAndroid Build Coastguard Worker {
824*d57664e9SAndroid Build Coastguard Worker     if (mFiles.size() > 0) {
825*d57664e9SAndroid Build Coastguard Worker         // Arbitrarily pull the first file out of the list as the source dir.
826*d57664e9SAndroid Build Coastguard Worker         return getPathDir(mFiles.valueAt(0)->getPrintableSource());
827*d57664e9SAndroid Build Coastguard Worker     }
828*d57664e9SAndroid Build Coastguard Worker     if (mDirs.size() > 0) {
829*d57664e9SAndroid Build Coastguard Worker         // Or arbitrarily pull the first dir out of the list as the source dir.
830*d57664e9SAndroid Build Coastguard Worker         return getPathDir(mDirs.valueAt(0)->getPrintableSource());
831*d57664e9SAndroid Build Coastguard Worker     }
832*d57664e9SAndroid Build Coastguard Worker 
833*d57664e9SAndroid Build Coastguard Worker     // Should never hit this case, but to be safe...
834*d57664e9SAndroid Build Coastguard Worker     return mPath;
835*d57664e9SAndroid Build Coastguard Worker 
836*d57664e9SAndroid Build Coastguard Worker }
837*d57664e9SAndroid Build Coastguard Worker 
838*d57664e9SAndroid Build Coastguard Worker // =========================================================================
839*d57664e9SAndroid Build Coastguard Worker // =========================================================================
840*d57664e9SAndroid Build Coastguard Worker // =========================================================================
841*d57664e9SAndroid Build Coastguard Worker 
applyJavaSymbols(const sp<AaptSymbols> & javaSymbols)842*d57664e9SAndroid Build Coastguard Worker status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
843*d57664e9SAndroid Build Coastguard Worker {
844*d57664e9SAndroid Build Coastguard Worker     status_t err = NO_ERROR;
845*d57664e9SAndroid Build Coastguard Worker     size_t N = javaSymbols->mSymbols.size();
846*d57664e9SAndroid Build Coastguard Worker     for (size_t i=0; i<N; i++) {
847*d57664e9SAndroid Build Coastguard Worker         const String8& name = javaSymbols->mSymbols.keyAt(i);
848*d57664e9SAndroid Build Coastguard Worker         const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
849*d57664e9SAndroid Build Coastguard Worker         ssize_t pos = mSymbols.indexOfKey(name);
850*d57664e9SAndroid Build Coastguard Worker         if (pos < 0) {
851*d57664e9SAndroid Build Coastguard Worker             entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.c_str());
852*d57664e9SAndroid Build Coastguard Worker             err = UNKNOWN_ERROR;
853*d57664e9SAndroid Build Coastguard Worker             continue;
854*d57664e9SAndroid Build Coastguard Worker         }
855*d57664e9SAndroid Build Coastguard Worker         //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
856*d57664e9SAndroid Build Coastguard Worker         //        i, N, name.c_str(), entry.isJavaSymbol ? 1 : 0);
857*d57664e9SAndroid Build Coastguard Worker         mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
858*d57664e9SAndroid Build Coastguard Worker     }
859*d57664e9SAndroid Build Coastguard Worker 
860*d57664e9SAndroid Build Coastguard Worker     N = javaSymbols->mNestedSymbols.size();
861*d57664e9SAndroid Build Coastguard Worker     for (size_t i=0; i<N; i++) {
862*d57664e9SAndroid Build Coastguard Worker         const String8& name = javaSymbols->mNestedSymbols.keyAt(i);
863*d57664e9SAndroid Build Coastguard Worker         const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i);
864*d57664e9SAndroid Build Coastguard Worker         ssize_t pos = mNestedSymbols.indexOfKey(name);
865*d57664e9SAndroid Build Coastguard Worker         if (pos < 0) {
866*d57664e9SAndroid Build Coastguard Worker             SourcePos pos;
867*d57664e9SAndroid Build Coastguard Worker             pos.error("Java symbol dir %s not defined\n", name.c_str());
868*d57664e9SAndroid Build Coastguard Worker             err = UNKNOWN_ERROR;
869*d57664e9SAndroid Build Coastguard Worker             continue;
870*d57664e9SAndroid Build Coastguard Worker         }
871*d57664e9SAndroid Build Coastguard Worker         //printf("**** applying java symbols in dir %s\n", name.c_str());
872*d57664e9SAndroid Build Coastguard Worker         status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
873*d57664e9SAndroid Build Coastguard Worker         if (myerr != NO_ERROR) {
874*d57664e9SAndroid Build Coastguard Worker             err = myerr;
875*d57664e9SAndroid Build Coastguard Worker         }
876*d57664e9SAndroid Build Coastguard Worker     }
877*d57664e9SAndroid Build Coastguard Worker 
878*d57664e9SAndroid Build Coastguard Worker     return err;
879*d57664e9SAndroid Build Coastguard Worker }
880*d57664e9SAndroid Build Coastguard Worker 
881*d57664e9SAndroid Build Coastguard Worker // =========================================================================
882*d57664e9SAndroid Build Coastguard Worker // =========================================================================
883*d57664e9SAndroid Build Coastguard Worker // =========================================================================
884*d57664e9SAndroid Build Coastguard Worker 
AaptAssets()885*d57664e9SAndroid Build Coastguard Worker AaptAssets::AaptAssets()
886*d57664e9SAndroid Build Coastguard Worker     : AaptDir(String8(), String8()),
887*d57664e9SAndroid Build Coastguard Worker       mHavePrivateSymbols(false),
888*d57664e9SAndroid Build Coastguard Worker       mChanged(false), mHaveIncludedAssets(false),
889*d57664e9SAndroid Build Coastguard Worker       mRes(NULL) {}
890*d57664e9SAndroid Build Coastguard Worker 
getGroupEntries() const891*d57664e9SAndroid Build Coastguard Worker const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
892*d57664e9SAndroid Build Coastguard Worker     if (mChanged) {
893*d57664e9SAndroid Build Coastguard Worker     }
894*d57664e9SAndroid Build Coastguard Worker     return mGroupEntries;
895*d57664e9SAndroid Build Coastguard Worker }
896*d57664e9SAndroid Build Coastguard Worker 
addFile(const String8 & name,const sp<AaptGroup> & file)897*d57664e9SAndroid Build Coastguard Worker status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file)
898*d57664e9SAndroid Build Coastguard Worker {
899*d57664e9SAndroid Build Coastguard Worker     mChanged = true;
900*d57664e9SAndroid Build Coastguard Worker     return AaptDir::addFile(name, file);
901*d57664e9SAndroid Build Coastguard Worker }
902*d57664e9SAndroid Build Coastguard Worker 
addFile(const String8 & filePath,const AaptGroupEntry & entry,const String8 & srcDir,sp<AaptGroup> * outGroup,const String8 & resType)903*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> AaptAssets::addFile(
904*d57664e9SAndroid Build Coastguard Worker         const String8& filePath, const AaptGroupEntry& entry,
905*d57664e9SAndroid Build Coastguard Worker         const String8& srcDir, sp<AaptGroup>* outGroup,
906*d57664e9SAndroid Build Coastguard Worker         const String8& resType)
907*d57664e9SAndroid Build Coastguard Worker {
908*d57664e9SAndroid Build Coastguard Worker     sp<AaptDir> dir = this;
909*d57664e9SAndroid Build Coastguard Worker     sp<AaptGroup> group;
910*d57664e9SAndroid Build Coastguard Worker     sp<AaptFile> file;
911*d57664e9SAndroid Build Coastguard Worker     String8 root, remain(filePath), partialPath;
912*d57664e9SAndroid Build Coastguard Worker     while (remain.length() > 0) {
913*d57664e9SAndroid Build Coastguard Worker         root = walkPath(remain, &remain);
914*d57664e9SAndroid Build Coastguard Worker         appendPath(partialPath, root);
915*d57664e9SAndroid Build Coastguard Worker 
916*d57664e9SAndroid Build Coastguard Worker         const String8 rootStr(root);
917*d57664e9SAndroid Build Coastguard Worker 
918*d57664e9SAndroid Build Coastguard Worker         if (remain.length() == 0) {
919*d57664e9SAndroid Build Coastguard Worker             ssize_t i = dir->getFiles().indexOfKey(rootStr);
920*d57664e9SAndroid Build Coastguard Worker             if (i >= 0) {
921*d57664e9SAndroid Build Coastguard Worker                 group = dir->getFiles().valueAt(i);
922*d57664e9SAndroid Build Coastguard Worker             } else {
923*d57664e9SAndroid Build Coastguard Worker                 group = new AaptGroup(rootStr, filePath);
924*d57664e9SAndroid Build Coastguard Worker                 status_t res = dir->addFile(rootStr, group);
925*d57664e9SAndroid Build Coastguard Worker                 if (res != NO_ERROR) {
926*d57664e9SAndroid Build Coastguard Worker                     return NULL;
927*d57664e9SAndroid Build Coastguard Worker                 }
928*d57664e9SAndroid Build Coastguard Worker             }
929*d57664e9SAndroid Build Coastguard Worker             file = new AaptFile(appendPathCopy(srcDir, filePath), entry, resType);
930*d57664e9SAndroid Build Coastguard Worker             status_t res = group->addFile(file);
931*d57664e9SAndroid Build Coastguard Worker             if (res != NO_ERROR) {
932*d57664e9SAndroid Build Coastguard Worker                 return NULL;
933*d57664e9SAndroid Build Coastguard Worker             }
934*d57664e9SAndroid Build Coastguard Worker             break;
935*d57664e9SAndroid Build Coastguard Worker 
936*d57664e9SAndroid Build Coastguard Worker         } else {
937*d57664e9SAndroid Build Coastguard Worker             ssize_t i = dir->getDirs().indexOfKey(rootStr);
938*d57664e9SAndroid Build Coastguard Worker             if (i >= 0) {
939*d57664e9SAndroid Build Coastguard Worker                 dir = dir->getDirs().valueAt(i);
940*d57664e9SAndroid Build Coastguard Worker             } else {
941*d57664e9SAndroid Build Coastguard Worker                 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
942*d57664e9SAndroid Build Coastguard Worker                 status_t res = dir->addDir(rootStr, subdir);
943*d57664e9SAndroid Build Coastguard Worker                 if (res != NO_ERROR) {
944*d57664e9SAndroid Build Coastguard Worker                     return NULL;
945*d57664e9SAndroid Build Coastguard Worker                 }
946*d57664e9SAndroid Build Coastguard Worker                 dir = subdir;
947*d57664e9SAndroid Build Coastguard Worker             }
948*d57664e9SAndroid Build Coastguard Worker         }
949*d57664e9SAndroid Build Coastguard Worker     }
950*d57664e9SAndroid Build Coastguard Worker 
951*d57664e9SAndroid Build Coastguard Worker     mGroupEntries.add(entry);
952*d57664e9SAndroid Build Coastguard Worker     if (outGroup) *outGroup = group;
953*d57664e9SAndroid Build Coastguard Worker     return file;
954*d57664e9SAndroid Build Coastguard Worker }
955*d57664e9SAndroid Build Coastguard Worker 
addResource(const String8 & leafName,const String8 & path,const sp<AaptFile> & file,const String8 & resType)956*d57664e9SAndroid Build Coastguard Worker void AaptAssets::addResource(const String8& leafName, const String8& path,
957*d57664e9SAndroid Build Coastguard Worker                 const sp<AaptFile>& file, const String8& resType)
958*d57664e9SAndroid Build Coastguard Worker {
959*d57664e9SAndroid Build Coastguard Worker     sp<AaptDir> res = AaptDir::makeDir(kResString);
960*d57664e9SAndroid Build Coastguard Worker     String8 dirname = file->getGroupEntry().toDirName(resType);
961*d57664e9SAndroid Build Coastguard Worker     sp<AaptDir> subdir = res->makeDir(dirname);
962*d57664e9SAndroid Build Coastguard Worker     sp<AaptGroup> grr = new AaptGroup(leafName, path);
963*d57664e9SAndroid Build Coastguard Worker     grr->addFile(file);
964*d57664e9SAndroid Build Coastguard Worker 
965*d57664e9SAndroid Build Coastguard Worker     subdir->addFile(leafName, grr);
966*d57664e9SAndroid Build Coastguard Worker }
967*d57664e9SAndroid Build Coastguard Worker 
968*d57664e9SAndroid Build Coastguard Worker 
slurpFromArgs(Bundle * bundle)969*d57664e9SAndroid Build Coastguard Worker ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
970*d57664e9SAndroid Build Coastguard Worker {
971*d57664e9SAndroid Build Coastguard Worker     int count;
972*d57664e9SAndroid Build Coastguard Worker     int totalCount = 0;
973*d57664e9SAndroid Build Coastguard Worker     FileType type;
974*d57664e9SAndroid Build Coastguard Worker     const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
975*d57664e9SAndroid Build Coastguard Worker     const size_t dirCount =resDirs.size();
976*d57664e9SAndroid Build Coastguard Worker     sp<AaptAssets> current = this;
977*d57664e9SAndroid Build Coastguard Worker 
978*d57664e9SAndroid Build Coastguard Worker     const int N = bundle->getFileSpecCount();
979*d57664e9SAndroid Build Coastguard Worker 
980*d57664e9SAndroid Build Coastguard Worker     /*
981*d57664e9SAndroid Build Coastguard Worker      * If a package manifest was specified, include that first.
982*d57664e9SAndroid Build Coastguard Worker      */
983*d57664e9SAndroid Build Coastguard Worker     if (bundle->getAndroidManifestFile() != NULL) {
984*d57664e9SAndroid Build Coastguard Worker         // place at root of zip.
985*d57664e9SAndroid Build Coastguard Worker         String8 srcFile(bundle->getAndroidManifestFile());
986*d57664e9SAndroid Build Coastguard Worker         addFile(getPathLeaf(srcFile), AaptGroupEntry(), getPathDir(srcFile),
987*d57664e9SAndroid Build Coastguard Worker                 NULL, String8());
988*d57664e9SAndroid Build Coastguard Worker         totalCount++;
989*d57664e9SAndroid Build Coastguard Worker     }
990*d57664e9SAndroid Build Coastguard Worker 
991*d57664e9SAndroid Build Coastguard Worker     /*
992*d57664e9SAndroid Build Coastguard Worker      * If a directory of custom assets was supplied, slurp 'em up.
993*d57664e9SAndroid Build Coastguard Worker      */
994*d57664e9SAndroid Build Coastguard Worker     const Vector<const char*>& assetDirs = bundle->getAssetSourceDirs();
995*d57664e9SAndroid Build Coastguard Worker     const int AN = assetDirs.size();
996*d57664e9SAndroid Build Coastguard Worker     for (int i = 0; i < AN; i++) {
997*d57664e9SAndroid Build Coastguard Worker         FileType type = getFileType(assetDirs[i]);
998*d57664e9SAndroid Build Coastguard Worker         if (type == kFileTypeNonexistent) {
999*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDirs[i]);
1000*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
1001*d57664e9SAndroid Build Coastguard Worker         }
1002*d57664e9SAndroid Build Coastguard Worker         if (type != kFileTypeDirectory) {
1003*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDirs[i]);
1004*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
1005*d57664e9SAndroid Build Coastguard Worker         }
1006*d57664e9SAndroid Build Coastguard Worker 
1007*d57664e9SAndroid Build Coastguard Worker         String8 assetRoot(assetDirs[i]);
1008*d57664e9SAndroid Build Coastguard Worker         sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
1009*d57664e9SAndroid Build Coastguard Worker         AaptGroupEntry group;
1010*d57664e9SAndroid Build Coastguard Worker         count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
1011*d57664e9SAndroid Build Coastguard Worker                                             String8(), mFullAssetPaths, true);
1012*d57664e9SAndroid Build Coastguard Worker         if (count < 0) {
1013*d57664e9SAndroid Build Coastguard Worker             totalCount = count;
1014*d57664e9SAndroid Build Coastguard Worker             goto bail;
1015*d57664e9SAndroid Build Coastguard Worker         }
1016*d57664e9SAndroid Build Coastguard Worker         if (count > 0) {
1017*d57664e9SAndroid Build Coastguard Worker             mGroupEntries.add(group);
1018*d57664e9SAndroid Build Coastguard Worker         }
1019*d57664e9SAndroid Build Coastguard Worker         totalCount += count;
1020*d57664e9SAndroid Build Coastguard Worker 
1021*d57664e9SAndroid Build Coastguard Worker         if (bundle->getVerbose()) {
1022*d57664e9SAndroid Build Coastguard Worker             printf("Found %d custom asset file%s in %s\n",
1023*d57664e9SAndroid Build Coastguard Worker                    count, (count==1) ? "" : "s", assetDirs[i]);
1024*d57664e9SAndroid Build Coastguard Worker         }
1025*d57664e9SAndroid Build Coastguard Worker     }
1026*d57664e9SAndroid Build Coastguard Worker 
1027*d57664e9SAndroid Build Coastguard Worker     /*
1028*d57664e9SAndroid Build Coastguard Worker      * If a directory of resource-specific assets was supplied, slurp 'em up.
1029*d57664e9SAndroid Build Coastguard Worker      */
1030*d57664e9SAndroid Build Coastguard Worker     for (size_t i=0; i<dirCount; i++) {
1031*d57664e9SAndroid Build Coastguard Worker         const char *res = resDirs[i];
1032*d57664e9SAndroid Build Coastguard Worker         if (res) {
1033*d57664e9SAndroid Build Coastguard Worker             type = getFileType(res);
1034*d57664e9SAndroid Build Coastguard Worker             if (type == kFileTypeNonexistent) {
1035*d57664e9SAndroid Build Coastguard Worker                 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
1036*d57664e9SAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
1037*d57664e9SAndroid Build Coastguard Worker             }
1038*d57664e9SAndroid Build Coastguard Worker             if (type == kFileTypeDirectory) {
1039*d57664e9SAndroid Build Coastguard Worker                 if (i>0) {
1040*d57664e9SAndroid Build Coastguard Worker                     sp<AaptAssets> nextOverlay = new AaptAssets();
1041*d57664e9SAndroid Build Coastguard Worker                     current->setOverlay(nextOverlay);
1042*d57664e9SAndroid Build Coastguard Worker                     current = nextOverlay;
1043*d57664e9SAndroid Build Coastguard Worker                     current->setFullResPaths(mFullResPaths);
1044*d57664e9SAndroid Build Coastguard Worker                 }
1045*d57664e9SAndroid Build Coastguard Worker                 count = current->slurpResourceTree(bundle, String8(res));
1046*d57664e9SAndroid Build Coastguard Worker                 if (i > 0 && count > 0) {
1047*d57664e9SAndroid Build Coastguard Worker                   count = current->filter(bundle);
1048*d57664e9SAndroid Build Coastguard Worker                 }
1049*d57664e9SAndroid Build Coastguard Worker 
1050*d57664e9SAndroid Build Coastguard Worker                 if (count < 0) {
1051*d57664e9SAndroid Build Coastguard Worker                     totalCount = count;
1052*d57664e9SAndroid Build Coastguard Worker                     goto bail;
1053*d57664e9SAndroid Build Coastguard Worker                 }
1054*d57664e9SAndroid Build Coastguard Worker                 totalCount += count;
1055*d57664e9SAndroid Build Coastguard Worker             }
1056*d57664e9SAndroid Build Coastguard Worker             else {
1057*d57664e9SAndroid Build Coastguard Worker                 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
1058*d57664e9SAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
1059*d57664e9SAndroid Build Coastguard Worker             }
1060*d57664e9SAndroid Build Coastguard Worker         }
1061*d57664e9SAndroid Build Coastguard Worker 
1062*d57664e9SAndroid Build Coastguard Worker     }
1063*d57664e9SAndroid Build Coastguard Worker     /*
1064*d57664e9SAndroid Build Coastguard Worker      * Now do any additional raw files.
1065*d57664e9SAndroid Build Coastguard Worker      */
1066*d57664e9SAndroid Build Coastguard Worker     for (int arg=0; arg<N; arg++) {
1067*d57664e9SAndroid Build Coastguard Worker         const char* assetDir = bundle->getFileSpecEntry(arg);
1068*d57664e9SAndroid Build Coastguard Worker 
1069*d57664e9SAndroid Build Coastguard Worker         FileType type = getFileType(assetDir);
1070*d57664e9SAndroid Build Coastguard Worker         if (type == kFileTypeNonexistent) {
1071*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
1072*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
1073*d57664e9SAndroid Build Coastguard Worker         }
1074*d57664e9SAndroid Build Coastguard Worker         if (type != kFileTypeDirectory) {
1075*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1076*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
1077*d57664e9SAndroid Build Coastguard Worker         }
1078*d57664e9SAndroid Build Coastguard Worker 
1079*d57664e9SAndroid Build Coastguard Worker         String8 assetRoot(assetDir);
1080*d57664e9SAndroid Build Coastguard Worker 
1081*d57664e9SAndroid Build Coastguard Worker         if (bundle->getVerbose())
1082*d57664e9SAndroid Build Coastguard Worker             printf("Processing raw dir '%s'\n", (const char*) assetDir);
1083*d57664e9SAndroid Build Coastguard Worker 
1084*d57664e9SAndroid Build Coastguard Worker         /*
1085*d57664e9SAndroid Build Coastguard Worker          * Do a recursive traversal of subdir tree.  We don't make any
1086*d57664e9SAndroid Build Coastguard Worker          * guarantees about ordering, so we're okay with an inorder search
1087*d57664e9SAndroid Build Coastguard Worker          * using whatever order the OS happens to hand back to us.
1088*d57664e9SAndroid Build Coastguard Worker          */
1089*d57664e9SAndroid Build Coastguard Worker         count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths);
1090*d57664e9SAndroid Build Coastguard Worker         if (count < 0) {
1091*d57664e9SAndroid Build Coastguard Worker             /* failure; report error and remove archive */
1092*d57664e9SAndroid Build Coastguard Worker             totalCount = count;
1093*d57664e9SAndroid Build Coastguard Worker             goto bail;
1094*d57664e9SAndroid Build Coastguard Worker         }
1095*d57664e9SAndroid Build Coastguard Worker         totalCount += count;
1096*d57664e9SAndroid Build Coastguard Worker 
1097*d57664e9SAndroid Build Coastguard Worker         if (bundle->getVerbose())
1098*d57664e9SAndroid Build Coastguard Worker             printf("Found %d asset file%s in %s\n",
1099*d57664e9SAndroid Build Coastguard Worker                    count, (count==1) ? "" : "s", assetDir);
1100*d57664e9SAndroid Build Coastguard Worker     }
1101*d57664e9SAndroid Build Coastguard Worker 
1102*d57664e9SAndroid Build Coastguard Worker     count = validate();
1103*d57664e9SAndroid Build Coastguard Worker     if (count != NO_ERROR) {
1104*d57664e9SAndroid Build Coastguard Worker         totalCount = count;
1105*d57664e9SAndroid Build Coastguard Worker         goto bail;
1106*d57664e9SAndroid Build Coastguard Worker     }
1107*d57664e9SAndroid Build Coastguard Worker 
1108*d57664e9SAndroid Build Coastguard Worker     count = filter(bundle);
1109*d57664e9SAndroid Build Coastguard Worker     if (count != NO_ERROR) {
1110*d57664e9SAndroid Build Coastguard Worker         totalCount = count;
1111*d57664e9SAndroid Build Coastguard Worker         goto bail;
1112*d57664e9SAndroid Build Coastguard Worker     }
1113*d57664e9SAndroid Build Coastguard Worker 
1114*d57664e9SAndroid Build Coastguard Worker bail:
1115*d57664e9SAndroid Build Coastguard Worker     return totalCount;
1116*d57664e9SAndroid Build Coastguard Worker }
1117*d57664e9SAndroid Build Coastguard Worker 
slurpFullTree(Bundle * bundle,const String8 & srcDir,const AaptGroupEntry & kind,const String8 & resType,sp<FilePathStore> & fullResPaths,const bool overwrite)1118*d57664e9SAndroid Build Coastguard Worker ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
1119*d57664e9SAndroid Build Coastguard Worker                                     const AaptGroupEntry& kind,
1120*d57664e9SAndroid Build Coastguard Worker                                     const String8& resType,
1121*d57664e9SAndroid Build Coastguard Worker                                     sp<FilePathStore>& fullResPaths,
1122*d57664e9SAndroid Build Coastguard Worker                                     const bool overwrite)
1123*d57664e9SAndroid Build Coastguard Worker {
1124*d57664e9SAndroid Build Coastguard Worker     ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths, overwrite);
1125*d57664e9SAndroid Build Coastguard Worker     if (res > 0) {
1126*d57664e9SAndroid Build Coastguard Worker         mGroupEntries.add(kind);
1127*d57664e9SAndroid Build Coastguard Worker     }
1128*d57664e9SAndroid Build Coastguard Worker 
1129*d57664e9SAndroid Build Coastguard Worker     return res;
1130*d57664e9SAndroid Build Coastguard Worker }
1131*d57664e9SAndroid Build Coastguard Worker 
slurpResourceTree(Bundle * bundle,const String8 & srcDir)1132*d57664e9SAndroid Build Coastguard Worker ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
1133*d57664e9SAndroid Build Coastguard Worker {
1134*d57664e9SAndroid Build Coastguard Worker     ssize_t err = 0;
1135*d57664e9SAndroid Build Coastguard Worker 
1136*d57664e9SAndroid Build Coastguard Worker     DIR* dir = opendir(srcDir.c_str());
1137*d57664e9SAndroid Build Coastguard Worker     if (dir == NULL) {
1138*d57664e9SAndroid Build Coastguard Worker         fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.c_str(), strerror(errno));
1139*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
1140*d57664e9SAndroid Build Coastguard Worker     }
1141*d57664e9SAndroid Build Coastguard Worker 
1142*d57664e9SAndroid Build Coastguard Worker     status_t count = 0;
1143*d57664e9SAndroid Build Coastguard Worker 
1144*d57664e9SAndroid Build Coastguard Worker     /*
1145*d57664e9SAndroid Build Coastguard Worker      * Run through the directory, looking for dirs that match the
1146*d57664e9SAndroid Build Coastguard Worker      * expected pattern.
1147*d57664e9SAndroid Build Coastguard Worker      */
1148*d57664e9SAndroid Build Coastguard Worker     while (1) {
1149*d57664e9SAndroid Build Coastguard Worker         struct dirent* entry = readdir(dir);
1150*d57664e9SAndroid Build Coastguard Worker         if (entry == NULL) {
1151*d57664e9SAndroid Build Coastguard Worker             break;
1152*d57664e9SAndroid Build Coastguard Worker         }
1153*d57664e9SAndroid Build Coastguard Worker 
1154*d57664e9SAndroid Build Coastguard Worker         if (isHidden(srcDir.c_str(), entry->d_name)) {
1155*d57664e9SAndroid Build Coastguard Worker             continue;
1156*d57664e9SAndroid Build Coastguard Worker         }
1157*d57664e9SAndroid Build Coastguard Worker 
1158*d57664e9SAndroid Build Coastguard Worker         String8 subdirName(srcDir);
1159*d57664e9SAndroid Build Coastguard Worker         appendPath(subdirName, entry->d_name);
1160*d57664e9SAndroid Build Coastguard Worker 
1161*d57664e9SAndroid Build Coastguard Worker         AaptGroupEntry group;
1162*d57664e9SAndroid Build Coastguard Worker         String8 resType;
1163*d57664e9SAndroid Build Coastguard Worker         bool b = group.initFromDirName(entry->d_name, &resType);
1164*d57664e9SAndroid Build Coastguard Worker         if (!b) {
1165*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "invalid resource directory name: %s %s\n", srcDir.c_str(),
1166*d57664e9SAndroid Build Coastguard Worker                     entry->d_name);
1167*d57664e9SAndroid Build Coastguard Worker             err = -1;
1168*d57664e9SAndroid Build Coastguard Worker             continue;
1169*d57664e9SAndroid Build Coastguard Worker         }
1170*d57664e9SAndroid Build Coastguard Worker 
1171*d57664e9SAndroid Build Coastguard Worker         if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
1172*d57664e9SAndroid Build Coastguard Worker             int maxResInt = atoi(bundle->getMaxResVersion());
1173*d57664e9SAndroid Build Coastguard Worker             const char *verString = group.getVersionString().c_str();
1174*d57664e9SAndroid Build Coastguard Worker             int dirVersionInt = atoi(verString + 1); // skip 'v' in version name
1175*d57664e9SAndroid Build Coastguard Worker             if (dirVersionInt > maxResInt) {
1176*d57664e9SAndroid Build Coastguard Worker               fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name);
1177*d57664e9SAndroid Build Coastguard Worker               continue;
1178*d57664e9SAndroid Build Coastguard Worker             }
1179*d57664e9SAndroid Build Coastguard Worker         }
1180*d57664e9SAndroid Build Coastguard Worker 
1181*d57664e9SAndroid Build Coastguard Worker         FileType type = getFileType(subdirName.c_str());
1182*d57664e9SAndroid Build Coastguard Worker 
1183*d57664e9SAndroid Build Coastguard Worker         if (type == kFileTypeDirectory) {
1184*d57664e9SAndroid Build Coastguard Worker             sp<AaptDir> dir = makeDir(resType);
1185*d57664e9SAndroid Build Coastguard Worker             ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
1186*d57664e9SAndroid Build Coastguard Worker                                                 resType, mFullResPaths);
1187*d57664e9SAndroid Build Coastguard Worker             if (res < 0) {
1188*d57664e9SAndroid Build Coastguard Worker                 count = res;
1189*d57664e9SAndroid Build Coastguard Worker                 goto bail;
1190*d57664e9SAndroid Build Coastguard Worker             }
1191*d57664e9SAndroid Build Coastguard Worker             if (res > 0) {
1192*d57664e9SAndroid Build Coastguard Worker                 mGroupEntries.add(group);
1193*d57664e9SAndroid Build Coastguard Worker                 count += res;
1194*d57664e9SAndroid Build Coastguard Worker             }
1195*d57664e9SAndroid Build Coastguard Worker 
1196*d57664e9SAndroid Build Coastguard Worker             // Only add this directory if we don't already have a resource dir
1197*d57664e9SAndroid Build Coastguard Worker             // for the current type.  This ensures that we only add the dir once
1198*d57664e9SAndroid Build Coastguard Worker             // for all configs.
1199*d57664e9SAndroid Build Coastguard Worker             sp<AaptDir> rdir = resDir(resType);
1200*d57664e9SAndroid Build Coastguard Worker             if (rdir == NULL) {
1201*d57664e9SAndroid Build Coastguard Worker                 mResDirs.add(dir);
1202*d57664e9SAndroid Build Coastguard Worker             }
1203*d57664e9SAndroid Build Coastguard Worker         } else {
1204*d57664e9SAndroid Build Coastguard Worker             if (bundle->getVerbose()) {
1205*d57664e9SAndroid Build Coastguard Worker                 fprintf(stderr, "   (ignoring file '%s')\n", subdirName.c_str());
1206*d57664e9SAndroid Build Coastguard Worker             }
1207*d57664e9SAndroid Build Coastguard Worker         }
1208*d57664e9SAndroid Build Coastguard Worker     }
1209*d57664e9SAndroid Build Coastguard Worker 
1210*d57664e9SAndroid Build Coastguard Worker bail:
1211*d57664e9SAndroid Build Coastguard Worker     closedir(dir);
1212*d57664e9SAndroid Build Coastguard Worker     dir = NULL;
1213*d57664e9SAndroid Build Coastguard Worker 
1214*d57664e9SAndroid Build Coastguard Worker     if (err != 0) {
1215*d57664e9SAndroid Build Coastguard Worker         return err;
1216*d57664e9SAndroid Build Coastguard Worker     }
1217*d57664e9SAndroid Build Coastguard Worker     return count;
1218*d57664e9SAndroid Build Coastguard Worker }
1219*d57664e9SAndroid Build Coastguard Worker 
1220*d57664e9SAndroid Build Coastguard Worker ssize_t
slurpResourceZip(Bundle *,const char * filename)1221*d57664e9SAndroid Build Coastguard Worker AaptAssets::slurpResourceZip(Bundle* /* bundle */, const char* filename)
1222*d57664e9SAndroid Build Coastguard Worker {
1223*d57664e9SAndroid Build Coastguard Worker     int count = 0;
1224*d57664e9SAndroid Build Coastguard Worker     SortedVector<AaptGroupEntry> entries;
1225*d57664e9SAndroid Build Coastguard Worker 
1226*d57664e9SAndroid Build Coastguard Worker     ZipFile* zip = new ZipFile;
1227*d57664e9SAndroid Build Coastguard Worker     status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
1228*d57664e9SAndroid Build Coastguard Worker     if (err != NO_ERROR) {
1229*d57664e9SAndroid Build Coastguard Worker         fprintf(stderr, "error opening zip file %s\n", filename);
1230*d57664e9SAndroid Build Coastguard Worker         count = err;
1231*d57664e9SAndroid Build Coastguard Worker         delete zip;
1232*d57664e9SAndroid Build Coastguard Worker         return -1;
1233*d57664e9SAndroid Build Coastguard Worker     }
1234*d57664e9SAndroid Build Coastguard Worker 
1235*d57664e9SAndroid Build Coastguard Worker     const int N = zip->getNumEntries();
1236*d57664e9SAndroid Build Coastguard Worker     for (int i=0; i<N; i++) {
1237*d57664e9SAndroid Build Coastguard Worker         ZipEntry* entry = zip->getEntryByIndex(i);
1238*d57664e9SAndroid Build Coastguard Worker         if (entry->getDeleted()) {
1239*d57664e9SAndroid Build Coastguard Worker             continue;
1240*d57664e9SAndroid Build Coastguard Worker         }
1241*d57664e9SAndroid Build Coastguard Worker 
1242*d57664e9SAndroid Build Coastguard Worker         String8 entryName(entry->getFileName());
1243*d57664e9SAndroid Build Coastguard Worker 
1244*d57664e9SAndroid Build Coastguard Worker         String8 dirName = getPathDir(entryName);
1245*d57664e9SAndroid Build Coastguard Worker         sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
1246*d57664e9SAndroid Build Coastguard Worker 
1247*d57664e9SAndroid Build Coastguard Worker         String8 resType;
1248*d57664e9SAndroid Build Coastguard Worker         AaptGroupEntry kind;
1249*d57664e9SAndroid Build Coastguard Worker 
1250*d57664e9SAndroid Build Coastguard Worker         String8 remain;
1251*d57664e9SAndroid Build Coastguard Worker         if (walkPath(entryName, &remain) == kResourceDir) {
1252*d57664e9SAndroid Build Coastguard Worker             // these are the resources, pull their type out of the directory name
1253*d57664e9SAndroid Build Coastguard Worker             kind.initFromDirName(walkPath(remain).c_str(), &resType);
1254*d57664e9SAndroid Build Coastguard Worker         } else {
1255*d57664e9SAndroid Build Coastguard Worker             // these are untyped and don't have an AaptGroupEntry
1256*d57664e9SAndroid Build Coastguard Worker         }
1257*d57664e9SAndroid Build Coastguard Worker         if (entries.indexOf(kind) < 0) {
1258*d57664e9SAndroid Build Coastguard Worker             entries.add(kind);
1259*d57664e9SAndroid Build Coastguard Worker             mGroupEntries.add(kind);
1260*d57664e9SAndroid Build Coastguard Worker         }
1261*d57664e9SAndroid Build Coastguard Worker 
1262*d57664e9SAndroid Build Coastguard Worker         // use the one from the zip file if they both exist.
1263*d57664e9SAndroid Build Coastguard Worker         dir->removeFile(getPathLeaf(entryName));
1264*d57664e9SAndroid Build Coastguard Worker 
1265*d57664e9SAndroid Build Coastguard Worker         sp<AaptFile> file = new AaptFile(entryName, kind, resType);
1266*d57664e9SAndroid Build Coastguard Worker         status_t err = dir->addLeafFile(getPathLeaf(entryName), file);
1267*d57664e9SAndroid Build Coastguard Worker         if (err != NO_ERROR) {
1268*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.c_str());
1269*d57664e9SAndroid Build Coastguard Worker             count = err;
1270*d57664e9SAndroid Build Coastguard Worker             goto bail;
1271*d57664e9SAndroid Build Coastguard Worker         }
1272*d57664e9SAndroid Build Coastguard Worker         file->setCompressionMethod(entry->getCompressionMethod());
1273*d57664e9SAndroid Build Coastguard Worker 
1274*d57664e9SAndroid Build Coastguard Worker #if 0
1275*d57664e9SAndroid Build Coastguard Worker         if (entryName == "AndroidManifest.xml") {
1276*d57664e9SAndroid Build Coastguard Worker             printf("AndroidManifest.xml\n");
1277*d57664e9SAndroid Build Coastguard Worker         }
1278*d57664e9SAndroid Build Coastguard Worker         printf("\n\nfile: %s\n", entryName.c_str());
1279*d57664e9SAndroid Build Coastguard Worker #endif
1280*d57664e9SAndroid Build Coastguard Worker 
1281*d57664e9SAndroid Build Coastguard Worker         size_t len = entry->getUncompressedLen();
1282*d57664e9SAndroid Build Coastguard Worker         void* data = zip->uncompress(entry);
1283*d57664e9SAndroid Build Coastguard Worker         void* buf = file->editData(len);
1284*d57664e9SAndroid Build Coastguard Worker         memcpy(buf, data, len);
1285*d57664e9SAndroid Build Coastguard Worker 
1286*d57664e9SAndroid Build Coastguard Worker #if 0
1287*d57664e9SAndroid Build Coastguard Worker         const int OFF = 0;
1288*d57664e9SAndroid Build Coastguard Worker         const unsigned char* p = (unsigned char*)data;
1289*d57664e9SAndroid Build Coastguard Worker         const unsigned char* end = p+len;
1290*d57664e9SAndroid Build Coastguard Worker         p += OFF;
1291*d57664e9SAndroid Build Coastguard Worker         for (int i=0; i<32 && p < end; i++) {
1292*d57664e9SAndroid Build Coastguard Worker             printf("0x%03x ", i*0x10 + OFF);
1293*d57664e9SAndroid Build Coastguard Worker             for (int j=0; j<0x10 && p < end; j++) {
1294*d57664e9SAndroid Build Coastguard Worker                 printf(" %02x", *p);
1295*d57664e9SAndroid Build Coastguard Worker                 p++;
1296*d57664e9SAndroid Build Coastguard Worker             }
1297*d57664e9SAndroid Build Coastguard Worker             printf("\n");
1298*d57664e9SAndroid Build Coastguard Worker         }
1299*d57664e9SAndroid Build Coastguard Worker #endif
1300*d57664e9SAndroid Build Coastguard Worker 
1301*d57664e9SAndroid Build Coastguard Worker         free(data);
1302*d57664e9SAndroid Build Coastguard Worker 
1303*d57664e9SAndroid Build Coastguard Worker         count++;
1304*d57664e9SAndroid Build Coastguard Worker     }
1305*d57664e9SAndroid Build Coastguard Worker 
1306*d57664e9SAndroid Build Coastguard Worker bail:
1307*d57664e9SAndroid Build Coastguard Worker     delete zip;
1308*d57664e9SAndroid Build Coastguard Worker     return count;
1309*d57664e9SAndroid Build Coastguard Worker }
1310*d57664e9SAndroid Build Coastguard Worker 
filter(Bundle * bundle)1311*d57664e9SAndroid Build Coastguard Worker status_t AaptAssets::filter(Bundle* bundle)
1312*d57664e9SAndroid Build Coastguard Worker {
1313*d57664e9SAndroid Build Coastguard Worker     sp<WeakResourceFilter> reqFilter(new WeakResourceFilter());
1314*d57664e9SAndroid Build Coastguard Worker     status_t err = reqFilter->parse(bundle->getConfigurations());
1315*d57664e9SAndroid Build Coastguard Worker     if (err != NO_ERROR) {
1316*d57664e9SAndroid Build Coastguard Worker         return err;
1317*d57664e9SAndroid Build Coastguard Worker     }
1318*d57664e9SAndroid Build Coastguard Worker 
1319*d57664e9SAndroid Build Coastguard Worker     uint32_t preferredDensity = 0;
1320*d57664e9SAndroid Build Coastguard Worker     if (bundle->getPreferredDensity().size() > 0) {
1321*d57664e9SAndroid Build Coastguard Worker         ResTable_config preferredConfig;
1322*d57664e9SAndroid Build Coastguard Worker         if (!AaptConfig::parseDensity(bundle->getPreferredDensity().c_str(), &preferredConfig)) {
1323*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "Error parsing preferred density: %s\n",
1324*d57664e9SAndroid Build Coastguard Worker                     bundle->getPreferredDensity().c_str());
1325*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
1326*d57664e9SAndroid Build Coastguard Worker         }
1327*d57664e9SAndroid Build Coastguard Worker         preferredDensity = preferredConfig.density;
1328*d57664e9SAndroid Build Coastguard Worker     }
1329*d57664e9SAndroid Build Coastguard Worker 
1330*d57664e9SAndroid Build Coastguard Worker     if (reqFilter->isEmpty() && preferredDensity == 0) {
1331*d57664e9SAndroid Build Coastguard Worker         return NO_ERROR;
1332*d57664e9SAndroid Build Coastguard Worker     }
1333*d57664e9SAndroid Build Coastguard Worker 
1334*d57664e9SAndroid Build Coastguard Worker     if (bundle->getVerbose()) {
1335*d57664e9SAndroid Build Coastguard Worker         if (!reqFilter->isEmpty()) {
1336*d57664e9SAndroid Build Coastguard Worker             printf("Applying required filter: %s\n",
1337*d57664e9SAndroid Build Coastguard Worker                     bundle->getConfigurations().c_str());
1338*d57664e9SAndroid Build Coastguard Worker         }
1339*d57664e9SAndroid Build Coastguard Worker         if (preferredDensity > 0) {
1340*d57664e9SAndroid Build Coastguard Worker             printf("Applying preferred density filter: %s\n",
1341*d57664e9SAndroid Build Coastguard Worker                     bundle->getPreferredDensity().c_str());
1342*d57664e9SAndroid Build Coastguard Worker         }
1343*d57664e9SAndroid Build Coastguard Worker     }
1344*d57664e9SAndroid Build Coastguard Worker 
1345*d57664e9SAndroid Build Coastguard Worker     const Vector<sp<AaptDir> >& resdirs = mResDirs;
1346*d57664e9SAndroid Build Coastguard Worker     const size_t ND = resdirs.size();
1347*d57664e9SAndroid Build Coastguard Worker     for (size_t i=0; i<ND; i++) {
1348*d57664e9SAndroid Build Coastguard Worker         const sp<AaptDir>& dir = resdirs.itemAt(i);
1349*d57664e9SAndroid Build Coastguard Worker         if (dir->getLeaf() == kValuesDir) {
1350*d57664e9SAndroid Build Coastguard Worker             // The "value" dir is special since a single file defines
1351*d57664e9SAndroid Build Coastguard Worker             // multiple resources, so we can not do filtering on the
1352*d57664e9SAndroid Build Coastguard Worker             // files themselves.
1353*d57664e9SAndroid Build Coastguard Worker             continue;
1354*d57664e9SAndroid Build Coastguard Worker         }
1355*d57664e9SAndroid Build Coastguard Worker         if (dir->getLeaf() == kMipmapDir) {
1356*d57664e9SAndroid Build Coastguard Worker             // We also skip the "mipmap" directory, since the point of this
1357*d57664e9SAndroid Build Coastguard Worker             // is to include all densities without stripping.  If you put
1358*d57664e9SAndroid Build Coastguard Worker             // other configurations in here as well they won't be stripped
1359*d57664e9SAndroid Build Coastguard Worker             // either...  So don't do that.  Seriously.  What is wrong with you?
1360*d57664e9SAndroid Build Coastguard Worker             continue;
1361*d57664e9SAndroid Build Coastguard Worker         }
1362*d57664e9SAndroid Build Coastguard Worker 
1363*d57664e9SAndroid Build Coastguard Worker         const size_t NG = dir->getFiles().size();
1364*d57664e9SAndroid Build Coastguard Worker         for (size_t j=0; j<NG; j++) {
1365*d57664e9SAndroid Build Coastguard Worker             sp<AaptGroup> grp = dir->getFiles().valueAt(j);
1366*d57664e9SAndroid Build Coastguard Worker 
1367*d57664e9SAndroid Build Coastguard Worker             // First remove any configurations we know we don't need.
1368*d57664e9SAndroid Build Coastguard Worker             for (size_t k=0; k<grp->getFiles().size(); k++) {
1369*d57664e9SAndroid Build Coastguard Worker                 sp<AaptFile> file = grp->getFiles().valueAt(k);
1370*d57664e9SAndroid Build Coastguard Worker                 if (k == 0 && grp->getFiles().size() == 1) {
1371*d57664e9SAndroid Build Coastguard Worker                     // If this is the only file left, we need to keep it.
1372*d57664e9SAndroid Build Coastguard Worker                     // Otherwise the resource IDs we are using will be inconsistent
1373*d57664e9SAndroid Build Coastguard Worker                     // with what we get when not stripping.  Sucky, but at least
1374*d57664e9SAndroid Build Coastguard Worker                     // for now we can rely on the back-end doing another filtering
1375*d57664e9SAndroid Build Coastguard Worker                     // pass to take this out and leave us with this resource name
1376*d57664e9SAndroid Build Coastguard Worker                     // containing no entries.
1377*d57664e9SAndroid Build Coastguard Worker                     continue;
1378*d57664e9SAndroid Build Coastguard Worker                 }
1379*d57664e9SAndroid Build Coastguard Worker                 if (getPathExtension(file->getPath()) == ".xml") {
1380*d57664e9SAndroid Build Coastguard Worker                     // We can't remove .xml files at this point, because when
1381*d57664e9SAndroid Build Coastguard Worker                     // we parse them they may add identifier resources, so
1382*d57664e9SAndroid Build Coastguard Worker                     // removing them can cause our resource identifiers to
1383*d57664e9SAndroid Build Coastguard Worker                     // become inconsistent.
1384*d57664e9SAndroid Build Coastguard Worker                     continue;
1385*d57664e9SAndroid Build Coastguard Worker                 }
1386*d57664e9SAndroid Build Coastguard Worker                 const ResTable_config& config(file->getGroupEntry().toParams());
1387*d57664e9SAndroid Build Coastguard Worker                 if (!reqFilter->match(config)) {
1388*d57664e9SAndroid Build Coastguard Worker                     if (bundle->getVerbose()) {
1389*d57664e9SAndroid Build Coastguard Worker                         printf("Pruning unneeded resource: %s\n",
1390*d57664e9SAndroid Build Coastguard Worker                                 file->getPrintableSource().c_str());
1391*d57664e9SAndroid Build Coastguard Worker                     }
1392*d57664e9SAndroid Build Coastguard Worker                     grp->removeFile(k);
1393*d57664e9SAndroid Build Coastguard Worker                     k--;
1394*d57664e9SAndroid Build Coastguard Worker                 }
1395*d57664e9SAndroid Build Coastguard Worker             }
1396*d57664e9SAndroid Build Coastguard Worker 
1397*d57664e9SAndroid Build Coastguard Worker             // Quick check: no preferred filters, nothing more to do.
1398*d57664e9SAndroid Build Coastguard Worker             if (preferredDensity == 0) {
1399*d57664e9SAndroid Build Coastguard Worker                 continue;
1400*d57664e9SAndroid Build Coastguard Worker             }
1401*d57664e9SAndroid Build Coastguard Worker 
1402*d57664e9SAndroid Build Coastguard Worker             // Get the preferred density if there is one. We do not match exactly for density.
1403*d57664e9SAndroid Build Coastguard Worker             // If our preferred density is hdpi but we only have mdpi and xhdpi resources, we
1404*d57664e9SAndroid Build Coastguard Worker             // pick xhdpi.
1405*d57664e9SAndroid Build Coastguard Worker             for (size_t k=0; k<grp->getFiles().size(); k++) {
1406*d57664e9SAndroid Build Coastguard Worker                 sp<AaptFile> file = grp->getFiles().valueAt(k);
1407*d57664e9SAndroid Build Coastguard Worker                 if (k == 0 && grp->getFiles().size() == 1) {
1408*d57664e9SAndroid Build Coastguard Worker                     // If this is the only file left, we need to keep it.
1409*d57664e9SAndroid Build Coastguard Worker                     // Otherwise the resource IDs we are using will be inconsistent
1410*d57664e9SAndroid Build Coastguard Worker                     // with what we get when not stripping.  Sucky, but at least
1411*d57664e9SAndroid Build Coastguard Worker                     // for now we can rely on the back-end doing another filtering
1412*d57664e9SAndroid Build Coastguard Worker                     // pass to take this out and leave us with this resource name
1413*d57664e9SAndroid Build Coastguard Worker                     // containing no entries.
1414*d57664e9SAndroid Build Coastguard Worker                     continue;
1415*d57664e9SAndroid Build Coastguard Worker                 }
1416*d57664e9SAndroid Build Coastguard Worker                 if (getPathExtension(file->getPath()) == ".xml") {
1417*d57664e9SAndroid Build Coastguard Worker                     // We can't remove .xml files at this point, because when
1418*d57664e9SAndroid Build Coastguard Worker                     // we parse them they may add identifier resources, so
1419*d57664e9SAndroid Build Coastguard Worker                     // removing them can cause our resource identifiers to
1420*d57664e9SAndroid Build Coastguard Worker                     // become inconsistent.
1421*d57664e9SAndroid Build Coastguard Worker                     continue;
1422*d57664e9SAndroid Build Coastguard Worker                 }
1423*d57664e9SAndroid Build Coastguard Worker                 const ResTable_config& config(file->getGroupEntry().toParams());
1424*d57664e9SAndroid Build Coastguard Worker                 if (config.density != 0 && config.density != preferredDensity) {
1425*d57664e9SAndroid Build Coastguard Worker                     // This is a resource we would prefer not to have.  Check
1426*d57664e9SAndroid Build Coastguard Worker                     // to see if have a similar variation that we would like
1427*d57664e9SAndroid Build Coastguard Worker                     // to have and, if so, we can drop it.
1428*d57664e9SAndroid Build Coastguard Worker                     uint32_t bestDensity = config.density;
1429*d57664e9SAndroid Build Coastguard Worker 
1430*d57664e9SAndroid Build Coastguard Worker                     for (size_t m=0; m<grp->getFiles().size(); m++) {
1431*d57664e9SAndroid Build Coastguard Worker                         if (m == k) {
1432*d57664e9SAndroid Build Coastguard Worker                             continue;
1433*d57664e9SAndroid Build Coastguard Worker                         }
1434*d57664e9SAndroid Build Coastguard Worker 
1435*d57664e9SAndroid Build Coastguard Worker                         sp<AaptFile> mfile = grp->getFiles().valueAt(m);
1436*d57664e9SAndroid Build Coastguard Worker                         const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
1437*d57664e9SAndroid Build Coastguard Worker                         if (AaptConfig::isSameExcept(config, mconfig, ResTable_config::CONFIG_DENSITY)) {
1438*d57664e9SAndroid Build Coastguard Worker                             // See if there is a better density resource
1439*d57664e9SAndroid Build Coastguard Worker                             if (mconfig.density < bestDensity &&
1440*d57664e9SAndroid Build Coastguard Worker                                     mconfig.density >= preferredDensity &&
1441*d57664e9SAndroid Build Coastguard Worker                                     bestDensity > preferredDensity) {
1442*d57664e9SAndroid Build Coastguard Worker                                 // This density is our preferred density, or between our best density and
1443*d57664e9SAndroid Build Coastguard Worker                                 // the preferred density, therefore it is better.
1444*d57664e9SAndroid Build Coastguard Worker                                 bestDensity = mconfig.density;
1445*d57664e9SAndroid Build Coastguard Worker                             } else if (mconfig.density > bestDensity &&
1446*d57664e9SAndroid Build Coastguard Worker                                     bestDensity < preferredDensity) {
1447*d57664e9SAndroid Build Coastguard Worker                                 // This density is better than our best density and
1448*d57664e9SAndroid Build Coastguard Worker                                 // our best density was smaller than our preferred
1449*d57664e9SAndroid Build Coastguard Worker                                 // density, so it is better.
1450*d57664e9SAndroid Build Coastguard Worker                                 bestDensity = mconfig.density;
1451*d57664e9SAndroid Build Coastguard Worker                             }
1452*d57664e9SAndroid Build Coastguard Worker                         }
1453*d57664e9SAndroid Build Coastguard Worker                     }
1454*d57664e9SAndroid Build Coastguard Worker 
1455*d57664e9SAndroid Build Coastguard Worker                     if (bestDensity != config.density) {
1456*d57664e9SAndroid Build Coastguard Worker                         if (bundle->getVerbose()) {
1457*d57664e9SAndroid Build Coastguard Worker                             printf("Pruning unneeded resource: %s\n",
1458*d57664e9SAndroid Build Coastguard Worker                                     file->getPrintableSource().c_str());
1459*d57664e9SAndroid Build Coastguard Worker                         }
1460*d57664e9SAndroid Build Coastguard Worker                         grp->removeFile(k);
1461*d57664e9SAndroid Build Coastguard Worker                         k--;
1462*d57664e9SAndroid Build Coastguard Worker                     }
1463*d57664e9SAndroid Build Coastguard Worker                 }
1464*d57664e9SAndroid Build Coastguard Worker             }
1465*d57664e9SAndroid Build Coastguard Worker         }
1466*d57664e9SAndroid Build Coastguard Worker     }
1467*d57664e9SAndroid Build Coastguard Worker 
1468*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
1469*d57664e9SAndroid Build Coastguard Worker }
1470*d57664e9SAndroid Build Coastguard Worker 
getSymbolsFor(const String8 & name)1471*d57664e9SAndroid Build Coastguard Worker sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
1472*d57664e9SAndroid Build Coastguard Worker {
1473*d57664e9SAndroid Build Coastguard Worker     sp<AaptSymbols> sym = mSymbols.valueFor(name);
1474*d57664e9SAndroid Build Coastguard Worker     if (sym == NULL) {
1475*d57664e9SAndroid Build Coastguard Worker         sym = new AaptSymbols();
1476*d57664e9SAndroid Build Coastguard Worker         mSymbols.add(name, sym);
1477*d57664e9SAndroid Build Coastguard Worker     }
1478*d57664e9SAndroid Build Coastguard Worker     return sym;
1479*d57664e9SAndroid Build Coastguard Worker }
1480*d57664e9SAndroid Build Coastguard Worker 
getJavaSymbolsFor(const String8 & name)1481*d57664e9SAndroid Build Coastguard Worker sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name)
1482*d57664e9SAndroid Build Coastguard Worker {
1483*d57664e9SAndroid Build Coastguard Worker     sp<AaptSymbols> sym = mJavaSymbols.valueFor(name);
1484*d57664e9SAndroid Build Coastguard Worker     if (sym == NULL) {
1485*d57664e9SAndroid Build Coastguard Worker         sym = new AaptSymbols();
1486*d57664e9SAndroid Build Coastguard Worker         mJavaSymbols.add(name, sym);
1487*d57664e9SAndroid Build Coastguard Worker     }
1488*d57664e9SAndroid Build Coastguard Worker     return sym;
1489*d57664e9SAndroid Build Coastguard Worker }
1490*d57664e9SAndroid Build Coastguard Worker 
applyJavaSymbols()1491*d57664e9SAndroid Build Coastguard Worker status_t AaptAssets::applyJavaSymbols()
1492*d57664e9SAndroid Build Coastguard Worker {
1493*d57664e9SAndroid Build Coastguard Worker     size_t N = mJavaSymbols.size();
1494*d57664e9SAndroid Build Coastguard Worker     for (size_t i=0; i<N; i++) {
1495*d57664e9SAndroid Build Coastguard Worker         const String8& name = mJavaSymbols.keyAt(i);
1496*d57664e9SAndroid Build Coastguard Worker         const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i);
1497*d57664e9SAndroid Build Coastguard Worker         ssize_t pos = mSymbols.indexOfKey(name);
1498*d57664e9SAndroid Build Coastguard Worker         if (pos < 0) {
1499*d57664e9SAndroid Build Coastguard Worker             SourcePos pos;
1500*d57664e9SAndroid Build Coastguard Worker             pos.error("Java symbol dir %s not defined\n", name.c_str());
1501*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
1502*d57664e9SAndroid Build Coastguard Worker         }
1503*d57664e9SAndroid Build Coastguard Worker         //printf("**** applying java symbols in dir %s\n", name.c_str());
1504*d57664e9SAndroid Build Coastguard Worker         status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
1505*d57664e9SAndroid Build Coastguard Worker         if (err != NO_ERROR) {
1506*d57664e9SAndroid Build Coastguard Worker             return err;
1507*d57664e9SAndroid Build Coastguard Worker         }
1508*d57664e9SAndroid Build Coastguard Worker     }
1509*d57664e9SAndroid Build Coastguard Worker 
1510*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
1511*d57664e9SAndroid Build Coastguard Worker }
1512*d57664e9SAndroid Build Coastguard Worker 
isJavaSymbol(const AaptSymbolEntry & sym,bool includePrivate) const1513*d57664e9SAndroid Build Coastguard Worker bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
1514*d57664e9SAndroid Build Coastguard Worker     //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
1515*d57664e9SAndroid Build Coastguard Worker     //        sym.name.c_str(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
1516*d57664e9SAndroid Build Coastguard Worker     //        sym.isJavaSymbol ? 1 : 0);
1517*d57664e9SAndroid Build Coastguard Worker     if (!mHavePrivateSymbols) return true;
1518*d57664e9SAndroid Build Coastguard Worker     if (sym.isPublic) return true;
1519*d57664e9SAndroid Build Coastguard Worker     if (includePrivate && sym.isJavaSymbol) return true;
1520*d57664e9SAndroid Build Coastguard Worker     return false;
1521*d57664e9SAndroid Build Coastguard Worker }
1522*d57664e9SAndroid Build Coastguard Worker 
buildIncludedResources(Bundle * bundle)1523*d57664e9SAndroid Build Coastguard Worker status_t AaptAssets::buildIncludedResources(Bundle* bundle)
1524*d57664e9SAndroid Build Coastguard Worker {
1525*d57664e9SAndroid Build Coastguard Worker     if (mHaveIncludedAssets) {
1526*d57664e9SAndroid Build Coastguard Worker         return NO_ERROR;
1527*d57664e9SAndroid Build Coastguard Worker     }
1528*d57664e9SAndroid Build Coastguard Worker 
1529*d57664e9SAndroid Build Coastguard Worker     // Add in all includes.
1530*d57664e9SAndroid Build Coastguard Worker     const Vector<String8>& includes = bundle->getPackageIncludes();
1531*d57664e9SAndroid Build Coastguard Worker     const size_t packageIncludeCount = includes.size();
1532*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 0; i < packageIncludeCount; i++) {
1533*d57664e9SAndroid Build Coastguard Worker         if (bundle->getVerbose()) {
1534*d57664e9SAndroid Build Coastguard Worker             printf("Including resources from package: %s\n", includes[i].c_str());
1535*d57664e9SAndroid Build Coastguard Worker         }
1536*d57664e9SAndroid Build Coastguard Worker 
1537*d57664e9SAndroid Build Coastguard Worker         if (!mIncludedAssets.addAssetPath(includes[i], NULL)) {
1538*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
1539*d57664e9SAndroid Build Coastguard Worker                     includes[i].c_str());
1540*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
1541*d57664e9SAndroid Build Coastguard Worker         }
1542*d57664e9SAndroid Build Coastguard Worker     }
1543*d57664e9SAndroid Build Coastguard Worker 
1544*d57664e9SAndroid Build Coastguard Worker     const String8& featureOfBase = bundle->getFeatureOfPackage();
1545*d57664e9SAndroid Build Coastguard Worker     if (!featureOfBase.empty()) {
1546*d57664e9SAndroid Build Coastguard Worker         if (bundle->getVerbose()) {
1547*d57664e9SAndroid Build Coastguard Worker             printf("Including base feature resources from package: %s\n",
1548*d57664e9SAndroid Build Coastguard Worker                     featureOfBase.c_str());
1549*d57664e9SAndroid Build Coastguard Worker         }
1550*d57664e9SAndroid Build Coastguard Worker 
1551*d57664e9SAndroid Build Coastguard Worker         if (!mIncludedAssets.addAssetPath(featureOfBase, NULL)) {
1552*d57664e9SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: base feature package '%s' not found.\n",
1553*d57664e9SAndroid Build Coastguard Worker                     featureOfBase.c_str());
1554*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
1555*d57664e9SAndroid Build Coastguard Worker         }
1556*d57664e9SAndroid Build Coastguard Worker     }
1557*d57664e9SAndroid Build Coastguard Worker 
1558*d57664e9SAndroid Build Coastguard Worker     mHaveIncludedAssets = true;
1559*d57664e9SAndroid Build Coastguard Worker 
1560*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
1561*d57664e9SAndroid Build Coastguard Worker }
1562*d57664e9SAndroid Build Coastguard Worker 
addIncludedResources(const sp<AaptFile> & file)1563*d57664e9SAndroid Build Coastguard Worker status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
1564*d57664e9SAndroid Build Coastguard Worker {
1565*d57664e9SAndroid Build Coastguard Worker     const ResTable& res = getIncludedResources();
1566*d57664e9SAndroid Build Coastguard Worker     // XXX dirty!
1567*d57664e9SAndroid Build Coastguard Worker     return const_cast<ResTable&>(res).add(file->getData(), file->getSize());
1568*d57664e9SAndroid Build Coastguard Worker }
1569*d57664e9SAndroid Build Coastguard Worker 
getIncludedResources() const1570*d57664e9SAndroid Build Coastguard Worker const ResTable& AaptAssets::getIncludedResources() const
1571*d57664e9SAndroid Build Coastguard Worker {
1572*d57664e9SAndroid Build Coastguard Worker     return mIncludedAssets.getResources(false);
1573*d57664e9SAndroid Build Coastguard Worker }
1574*d57664e9SAndroid Build Coastguard Worker 
getAssetManager()1575*d57664e9SAndroid Build Coastguard Worker AssetManager& AaptAssets::getAssetManager()
1576*d57664e9SAndroid Build Coastguard Worker {
1577*d57664e9SAndroid Build Coastguard Worker     return mIncludedAssets;
1578*d57664e9SAndroid Build Coastguard Worker }
1579*d57664e9SAndroid Build Coastguard Worker 
print(const String8 & prefix) const1580*d57664e9SAndroid Build Coastguard Worker void AaptAssets::print(const String8& prefix) const
1581*d57664e9SAndroid Build Coastguard Worker {
1582*d57664e9SAndroid Build Coastguard Worker     String8 innerPrefix(prefix);
1583*d57664e9SAndroid Build Coastguard Worker     innerPrefix.append("  ");
1584*d57664e9SAndroid Build Coastguard Worker     String8 innerInnerPrefix(innerPrefix);
1585*d57664e9SAndroid Build Coastguard Worker     innerInnerPrefix.append("  ");
1586*d57664e9SAndroid Build Coastguard Worker     printf("%sConfigurations:\n", prefix.c_str());
1587*d57664e9SAndroid Build Coastguard Worker     const size_t N=mGroupEntries.size();
1588*d57664e9SAndroid Build Coastguard Worker     for (size_t i=0; i<N; i++) {
1589*d57664e9SAndroid Build Coastguard Worker         String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
1590*d57664e9SAndroid Build Coastguard Worker         printf("%s %s\n", prefix.c_str(),
1591*d57664e9SAndroid Build Coastguard Worker                 cname != "" ? cname.c_str() : "(default)");
1592*d57664e9SAndroid Build Coastguard Worker     }
1593*d57664e9SAndroid Build Coastguard Worker 
1594*d57664e9SAndroid Build Coastguard Worker     printf("\n%sFiles:\n", prefix.c_str());
1595*d57664e9SAndroid Build Coastguard Worker     AaptDir::print(innerPrefix);
1596*d57664e9SAndroid Build Coastguard Worker 
1597*d57664e9SAndroid Build Coastguard Worker     printf("\n%sResource Dirs:\n", prefix.c_str());
1598*d57664e9SAndroid Build Coastguard Worker     const Vector<sp<AaptDir> >& resdirs = mResDirs;
1599*d57664e9SAndroid Build Coastguard Worker     const size_t NR = resdirs.size();
1600*d57664e9SAndroid Build Coastguard Worker     for (size_t i=0; i<NR; i++) {
1601*d57664e9SAndroid Build Coastguard Worker         const sp<AaptDir>& d = resdirs.itemAt(i);
1602*d57664e9SAndroid Build Coastguard Worker         printf("%s  Type %s\n", prefix.c_str(), d->getLeaf().c_str());
1603*d57664e9SAndroid Build Coastguard Worker         d->print(innerInnerPrefix);
1604*d57664e9SAndroid Build Coastguard Worker     }
1605*d57664e9SAndroid Build Coastguard Worker }
1606*d57664e9SAndroid Build Coastguard Worker 
resDir(const String8 & name) const1607*d57664e9SAndroid Build Coastguard Worker sp<AaptDir> AaptAssets::resDir(const String8& name) const
1608*d57664e9SAndroid Build Coastguard Worker {
1609*d57664e9SAndroid Build Coastguard Worker     const Vector<sp<AaptDir> >& resdirs = mResDirs;
1610*d57664e9SAndroid Build Coastguard Worker     const size_t N = resdirs.size();
1611*d57664e9SAndroid Build Coastguard Worker     for (size_t i=0; i<N; i++) {
1612*d57664e9SAndroid Build Coastguard Worker         const sp<AaptDir>& d = resdirs.itemAt(i);
1613*d57664e9SAndroid Build Coastguard Worker         if (d->getLeaf() == name) {
1614*d57664e9SAndroid Build Coastguard Worker             return d;
1615*d57664e9SAndroid Build Coastguard Worker         }
1616*d57664e9SAndroid Build Coastguard Worker     }
1617*d57664e9SAndroid Build Coastguard Worker     return NULL;
1618*d57664e9SAndroid Build Coastguard Worker }
1619*d57664e9SAndroid Build Coastguard Worker 
1620*d57664e9SAndroid Build Coastguard Worker bool
valid_symbol_name(const String8 & symbol)1621*d57664e9SAndroid Build Coastguard Worker valid_symbol_name(const String8& symbol)
1622*d57664e9SAndroid Build Coastguard Worker {
1623*d57664e9SAndroid Build Coastguard Worker     static char const * const KEYWORDS[] = {
1624*d57664e9SAndroid Build Coastguard Worker         "abstract", "assert", "boolean", "break",
1625*d57664e9SAndroid Build Coastguard Worker         "byte", "case", "catch", "char", "class", "const", "continue",
1626*d57664e9SAndroid Build Coastguard Worker         "default", "do", "double", "else", "enum", "extends", "final",
1627*d57664e9SAndroid Build Coastguard Worker         "finally", "float", "for", "goto", "if", "implements", "import",
1628*d57664e9SAndroid Build Coastguard Worker         "instanceof", "int", "interface", "long", "native", "new", "package",
1629*d57664e9SAndroid Build Coastguard Worker         "private", "protected", "public", "return", "short", "static",
1630*d57664e9SAndroid Build Coastguard Worker         "strictfp", "super", "switch", "synchronized", "this", "throw",
1631*d57664e9SAndroid Build Coastguard Worker         "throws", "transient", "try", "void", "volatile", "while",
1632*d57664e9SAndroid Build Coastguard Worker         "true", "false", "null",
1633*d57664e9SAndroid Build Coastguard Worker         NULL
1634*d57664e9SAndroid Build Coastguard Worker     };
1635*d57664e9SAndroid Build Coastguard Worker     const char*const* k = KEYWORDS;
1636*d57664e9SAndroid Build Coastguard Worker     const char*const s = symbol.c_str();
1637*d57664e9SAndroid Build Coastguard Worker     while (*k) {
1638*d57664e9SAndroid Build Coastguard Worker         if (0 == strcmp(s, *k)) {
1639*d57664e9SAndroid Build Coastguard Worker             return false;
1640*d57664e9SAndroid Build Coastguard Worker         }
1641*d57664e9SAndroid Build Coastguard Worker         k++;
1642*d57664e9SAndroid Build Coastguard Worker     }
1643*d57664e9SAndroid Build Coastguard Worker     return true;
1644*d57664e9SAndroid Build Coastguard Worker }
1645