AaptAssets.cpp revision a53b828635fce8b6b2d3e3377d74d72070056623
1//
2// Copyright 2006 The Android Open Source Project
3//
4
5#include "AaptAssets.h"
6#include "Main.h"
7
8#include <utils/misc.h>
9#include <utils/SortedVector.h>
10
11#include <ctype.h>
12#include <dirent.h>
13#include <errno.h>
14
15static const char* kDefaultLocale = "default";
16static const char* kWildcardName = "any";
17static const char* kAssetDir = "assets";
18static const char* kResourceDir = "res";
19static const char* kInvalidChars = "/\\:";
20static const size_t kMaxAssetFileName = 100;
21
22static const String8 kResString(kResourceDir);
23
24/*
25 * Names of asset files must meet the following criteria:
26 *
27 *  - the filename length must be less than kMaxAssetFileName bytes long
28 *    (and can't be empty)
29 *  - all characters must be 7-bit printable ASCII
30 *  - none of { '/' '\\' ':' }
31 *
32 * Pass in just the filename, not the full path.
33 */
34static bool validateFileName(const char* fileName)
35{
36    const char* cp = fileName;
37    size_t len = 0;
38
39    while (*cp != '\0') {
40        if ((*cp & 0x80) != 0)
41            return false;           // reject high ASCII
42        if (*cp < 0x20 || *cp >= 0x7f)
43            return false;           // reject control chars and 0x7f
44        if (strchr(kInvalidChars, *cp) != NULL)
45            return false;           // reject path sep chars
46        cp++;
47        len++;
48    }
49
50    if (len < 1 || len > kMaxAssetFileName)
51        return false;               // reject empty or too long
52
53    return true;
54}
55
56static bool isHidden(const char *root, const char *path)
57{
58    const char *type = NULL;
59
60    // Skip all hidden files.
61    if (path[0] == '.') {
62        // Skip ., .. and  .svn but don't chatter about it.
63        if (strcmp(path, ".") == 0
64            || strcmp(path, "..") == 0
65            || strcmp(path, ".svn") == 0) {
66            return true;
67        }
68        type = "hidden";
69    } else if (path[0] == '_') {
70        // skip directories starting with _ (don't chatter about it)
71        String8 subdirName(root);
72        subdirName.appendPath(path);
73        if (getFileType(subdirName.string()) == kFileTypeDirectory) {
74            return true;
75        }
76    } else if (strcmp(path, "CVS") == 0) {
77        // Skip CVS but don't chatter about it.
78        return true;
79    } else if (strcasecmp(path, "thumbs.db") == 0
80               || strcasecmp(path, "picasa.ini") == 0) {
81        // Skip suspected image indexes files.
82        type = "index";
83    } else if (path[strlen(path)-1] == '~') {
84        // Skip suspected emacs backup files.
85        type = "backup";
86    } else {
87        // Let everything else through.
88        return false;
89    }
90
91    /* If we get this far, "type" should be set and the file
92     * should be skipped.
93     */
94    String8 subdirName(root);
95    subdirName.appendPath(path);
96    fprintf(stderr, "    (skipping %s %s '%s')\n", type,
97            getFileType(subdirName.string())==kFileTypeDirectory ? "dir":"file",
98            subdirName.string());
99
100    return true;
101}
102
103// =========================================================================
104// =========================================================================
105// =========================================================================
106
107status_t
108AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
109{
110    ResTable_config config;
111
112    // IMSI - MCC
113    if (getMccName(part.string(), &config)) {
114        *axis = AXIS_MCC;
115        *value = config.mcc;
116        return 0;
117    }
118
119    // IMSI - MNC
120    if (getMncName(part.string(), &config)) {
121        *axis = AXIS_MNC;
122        *value = config.mnc;
123        return 0;
124    }
125
126    // locale - language
127    if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
128        *axis = AXIS_LANGUAGE;
129        *value = part[1] << 8 | part[0];
130        return 0;
131    }
132
133    // locale - language_REGION
134    if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1])
135            && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) {
136        *axis = AXIS_LANGUAGE;
137        *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]);
138        return 0;
139    }
140
141    // orientation
142    if (getOrientationName(part.string(), &config)) {
143        *axis = AXIS_ORIENTATION;
144        *value = config.orientation;
145        return 0;
146    }
147
148    // density
149    if (getDensityName(part.string(), &config)) {
150        *axis = AXIS_DENSITY;
151        *value = config.density;
152        return 0;
153    }
154
155    // touchscreen
156    if (getTouchscreenName(part.string(), &config)) {
157        *axis = AXIS_TOUCHSCREEN;
158        *value = config.touchscreen;
159        return 0;
160    }
161
162    // keyboard hidden
163    if (getKeysHiddenName(part.string(), &config)) {
164        *axis = AXIS_KEYSHIDDEN;
165        *value = config.inputFlags;
166        return 0;
167    }
168
169    // keyboard
170    if (getKeyboardName(part.string(), &config)) {
171        *axis = AXIS_KEYBOARD;
172        *value = config.keyboard;
173        return 0;
174    }
175
176    // navigation
177    if (getNavigationName(part.string(), &config)) {
178        *axis = AXIS_NAVIGATION;
179        *value = config.navigation;
180        return 0;
181    }
182
183    // screen size
184    if (getScreenSizeName(part.string(), &config)) {
185        *axis = AXIS_SCREENSIZE;
186        *value = config.screenSize;
187        return 0;
188    }
189
190    // screen layout
191    if (getScreenLayoutName(part.string(), &config)) {
192        *axis = AXIS_SCREENLAYOUT;
193        *value = config.screenLayout;
194        return 0;
195    }
196
197    // version
198    if (getVersionName(part.string(), &config)) {
199        *axis = AXIS_VERSION;
200        *value = config.version;
201        return 0;
202    }
203
204    return 1;
205}
206
207bool
208AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
209{
210    Vector<String8> parts;
211
212    String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, layout, vers;
213
214    const char *p = dir;
215    const char *q;
216    while (NULL != (q = strchr(p, '-'))) {
217        String8 val(p, q-p);
218        val.toLower();
219        parts.add(val);
220        //printf("part: %s\n", parts[parts.size()-1].string());
221        p = q+1;
222    }
223    String8 val(p);
224    val.toLower();
225    parts.add(val);
226    //printf("part: %s\n", parts[parts.size()-1].string());
227
228    const int N = parts.size();
229    int index = 0;
230    String8 part = parts[index];
231
232    // resource type
233    if (!isValidResourceType(part)) {
234        return false;
235    }
236    *resType = part;
237
238    index++;
239    if (index == N) {
240        goto success;
241    }
242    part = parts[index];
243
244    // imsi - mcc
245    if (getMccName(part.string())) {
246        mcc = part;
247
248        index++;
249        if (index == N) {
250            goto success;
251        }
252        part = parts[index];
253    } else {
254        //printf("not mcc: %s\n", part.string());
255    }
256
257    // imsi - mnc
258    if (getMncName(part.string())) {
259        mnc = part;
260
261        index++;
262        if (index == N) {
263            goto success;
264        }
265        part = parts[index];
266    } else {
267        //printf("not mcc: %s\n", part.string());
268    }
269
270    // locale - language
271    if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
272        loc = part;
273
274        index++;
275        if (index == N) {
276            goto success;
277        }
278        part = parts[index];
279    } else {
280        //printf("not language: %s\n", part.string());
281    }
282
283    // locale - region
284    if (loc.length() > 0
285            && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) {
286        loc += "-";
287        part.toUpper();
288        loc += part.string() + 1;
289
290        index++;
291        if (index == N) {
292            goto success;
293        }
294        part = parts[index];
295    } else {
296        //printf("not region: %s\n", part.string());
297    }
298
299    // orientation
300    if (getOrientationName(part.string())) {
301        orient = part;
302
303        index++;
304        if (index == N) {
305            goto success;
306        }
307        part = parts[index];
308    } else {
309        //printf("not orientation: %s\n", part.string());
310    }
311
312    // density
313    if (getDensityName(part.string())) {
314        den = part;
315
316        index++;
317        if (index == N) {
318            goto success;
319        }
320        part = parts[index];
321    } else {
322        //printf("not density: %s\n", part.string());
323    }
324
325    // touchscreen
326    if (getTouchscreenName(part.string())) {
327        touch = part;
328
329        index++;
330        if (index == N) {
331            goto success;
332        }
333        part = parts[index];
334    } else {
335        //printf("not touchscreen: %s\n", part.string());
336    }
337
338    // keyboard hidden
339    if (getKeysHiddenName(part.string())) {
340        keysHidden = part;
341
342        index++;
343        if (index == N) {
344            goto success;
345        }
346        part = parts[index];
347    } else {
348        //printf("not keysHidden: %s\n", part.string());
349    }
350
351    // keyboard
352    if (getKeyboardName(part.string())) {
353        key = part;
354
355        index++;
356        if (index == N) {
357            goto success;
358        }
359        part = parts[index];
360    } else {
361        //printf("not keyboard: %s\n", part.string());
362    }
363
364    if (getNavigationName(part.string())) {
365        nav = part;
366
367        index++;
368        if (index == N) {
369            goto success;
370        }
371        part = parts[index];
372    } else {
373        //printf("not navigation: %s\n", part.string());
374    }
375
376    if (getScreenSizeName(part.string())) {
377        size = part;
378
379        index++;
380        if (index == N) {
381            goto success;
382        }
383        part = parts[index];
384    } else {
385        //printf("not screen size: %s\n", part.string());
386    }
387
388    if (getScreenLayoutName(part.string())) {
389        layout = part;
390
391        index++;
392        if (index == N) {
393            goto success;
394        }
395        part = parts[index];
396    } else {
397        //printf("not screen layout: %s\n", part.string());
398    }
399
400    if (getVersionName(part.string())) {
401        vers = part;
402
403        index++;
404        if (index == N) {
405            goto success;
406        }
407        part = parts[index];
408    } else {
409        //printf("not version: %s\n", part.string());
410    }
411
412    // if there are extra parts, it doesn't match
413    return false;
414
415success:
416    this->mcc = mcc;
417    this->mnc = mnc;
418    this->locale = loc;
419    this->orientation = orient;
420    this->density = den;
421    this->touchscreen = touch;
422    this->keysHidden = keysHidden;
423    this->keyboard = key;
424    this->navigation = nav;
425    this->screenSize = size;
426    this->screenLayout = layout;
427    this->version = vers;
428
429    // what is this anyway?
430    this->vendor = "";
431
432    return true;
433}
434
435String8
436AaptGroupEntry::toString() const
437{
438    String8 s = this->mcc;
439    s += ",";
440    s += this->mnc;
441    s += ",";
442    s += this->locale;
443    s += ",";
444    s += this->orientation;
445    s += ",";
446    s += density;
447    s += ",";
448    s += touchscreen;
449    s += ",";
450    s += keysHidden;
451    s += ",";
452    s += keyboard;
453    s += ",";
454    s += navigation;
455    s += ",";
456    s += screenSize;
457    s += ",";
458    s += screenLayout;
459    s += ",";
460    s += version;
461    return s;
462}
463
464String8
465AaptGroupEntry::toDirName(const String8& resType) const
466{
467    String8 s = resType;
468    if (this->mcc != "") {
469        s += "-";
470        s += mcc;
471    }
472    if (this->mnc != "") {
473        s += "-";
474        s += mnc;
475    }
476    if (this->locale != "") {
477        s += "-";
478        s += locale;
479    }
480    if (this->orientation != "") {
481        s += "-";
482        s += orientation;
483    }
484    if (this->density != "") {
485        s += "-";
486        s += density;
487    }
488    if (this->touchscreen != "") {
489        s += "-";
490        s += touchscreen;
491    }
492    if (this->keysHidden != "") {
493        s += "-";
494        s += keysHidden;
495    }
496    if (this->keyboard != "") {
497        s += "-";
498        s += keyboard;
499    }
500    if (this->navigation != "") {
501        s += "-";
502        s += navigation;
503    }
504    if (this->screenSize != "") {
505        s += "-";
506        s += screenSize;
507    }
508    if (this->screenLayout != "") {
509        s += "-";
510        s += screenLayout;
511    }
512    if (this->version != "") {
513        s += "-";
514        s += version;
515    }
516
517    return s;
518}
519
520bool AaptGroupEntry::getMccName(const char* name,
521                                    ResTable_config* out)
522{
523    if (strcmp(name, kWildcardName) == 0) {
524        if (out) out->mcc = 0;
525        return true;
526    }
527    const char* c = name;
528    if (tolower(*c) != 'm') return false;
529    c++;
530    if (tolower(*c) != 'c') return false;
531    c++;
532    if (tolower(*c) != 'c') return false;
533    c++;
534
535    const char* val = c;
536
537    while (*c >= '0' && *c <= '9') {
538        c++;
539    }
540    if (*c != 0) return false;
541    if (c-val != 3) return false;
542
543    int d = atoi(val);
544    if (d != 0) {
545        if (out) out->mcc = d;
546        return true;
547    }
548
549    return false;
550}
551
552bool AaptGroupEntry::getMncName(const char* name,
553                                    ResTable_config* out)
554{
555    if (strcmp(name, kWildcardName) == 0) {
556        if (out) out->mcc = 0;
557        return true;
558    }
559    const char* c = name;
560    if (tolower(*c) != 'm') return false;
561    c++;
562    if (tolower(*c) != 'n') return false;
563    c++;
564    if (tolower(*c) != 'c') return false;
565    c++;
566
567    const char* val = c;
568
569    while (*c >= '0' && *c <= '9') {
570        c++;
571    }
572    if (*c != 0) return false;
573    if (c-val == 0 || c-val > 3) return false;
574
575    int d = atoi(val);
576    if (d != 0) {
577        if (out) out->mnc = d;
578        return true;
579    }
580
581    return false;
582}
583
584/*
585 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
586 * "default")?
587 *
588 * TODO: Should insist that the first two letters are lower case, and the
589 * second two are upper.
590 */
591bool AaptGroupEntry::getLocaleName(const char* fileName,
592                                   ResTable_config* out)
593{
594    if (strcmp(fileName, kWildcardName) == 0
595            || strcmp(fileName, kDefaultLocale) == 0) {
596        if (out) {
597            out->language[0] = 0;
598            out->language[1] = 0;
599            out->country[0] = 0;
600            out->country[1] = 0;
601        }
602        return true;
603    }
604
605    if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) {
606        if (out) {
607            out->language[0] = fileName[0];
608            out->language[1] = fileName[1];
609            out->country[0] = 0;
610            out->country[1] = 0;
611        }
612        return true;
613    }
614
615    if (strlen(fileName) == 5 &&
616        isalpha(fileName[0]) &&
617        isalpha(fileName[1]) &&
618        fileName[2] == '-' &&
619        isalpha(fileName[3]) &&
620        isalpha(fileName[4])) {
621        if (out) {
622            out->language[0] = fileName[0];
623            out->language[1] = fileName[1];
624            out->country[0] = fileName[3];
625            out->country[1] = fileName[4];
626        }
627        return true;
628    }
629
630    return false;
631}
632
633bool AaptGroupEntry::getOrientationName(const char* name,
634                                        ResTable_config* out)
635{
636    if (strcmp(name, kWildcardName) == 0) {
637        if (out) out->orientation = out->ORIENTATION_ANY;
638        return true;
639    } else if (strcmp(name, "port") == 0) {
640        if (out) out->orientation = out->ORIENTATION_PORT;
641        return true;
642    } else if (strcmp(name, "land") == 0) {
643        if (out) out->orientation = out->ORIENTATION_LAND;
644        return true;
645    } else if (strcmp(name, "square") == 0) {
646        if (out) out->orientation = out->ORIENTATION_SQUARE;
647        return true;
648    }
649
650    return false;
651}
652
653bool AaptGroupEntry::getDensityName(const char* name,
654                                    ResTable_config* out)
655{
656    if (strcmp(name, kWildcardName) == 0) {
657        if (out) out->density = ResTable_config::DENSITY_DEFAULT;
658        return true;
659    }
660
661    if (strcmp(name, "nodpi") == 0) {
662        if (out) out->density = ResTable_config::DENSITY_NONE;
663        return true;
664    }
665
666    char* c = (char*)name;
667    while (*c >= '0' && *c <= '9') {
668        c++;
669    }
670
671    // check that we have 'dpi' after the last digit.
672    if (toupper(c[0]) != 'D' ||
673            toupper(c[1]) != 'P' ||
674            toupper(c[2]) != 'I' ||
675            c[3] != 0) {
676        return false;
677    }
678
679    // temporarily replace the first letter with \0 to
680    // use atoi.
681    char tmp = c[0];
682    c[0] = '\0';
683
684    int d = atoi(name);
685    c[0] = tmp;
686
687    if (d != 0) {
688        if (out) out->density = d;
689        return true;
690    }
691
692    return false;
693}
694
695bool AaptGroupEntry::getTouchscreenName(const char* name,
696                                        ResTable_config* out)
697{
698    if (strcmp(name, kWildcardName) == 0) {
699        if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
700        return true;
701    } else if (strcmp(name, "notouch") == 0) {
702        if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
703        return true;
704    } else if (strcmp(name, "stylus") == 0) {
705        if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
706        return true;
707    } else if (strcmp(name, "finger") == 0) {
708        if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
709        return true;
710    }
711
712    return false;
713}
714
715bool AaptGroupEntry::getKeysHiddenName(const char* name,
716                                       ResTable_config* out)
717{
718    uint8_t mask = 0;
719    uint8_t value = 0;
720    if (strcmp(name, kWildcardName) == 0) {
721        mask = out->MASK_KEYSHIDDEN;
722        value = out->KEYSHIDDEN_ANY;
723    } else if (strcmp(name, "keysexposed") == 0) {
724        mask = out->MASK_KEYSHIDDEN;
725        value = out->KEYSHIDDEN_NO;
726    } else if (strcmp(name, "keyshidden") == 0) {
727        mask = out->MASK_KEYSHIDDEN;
728        value = out->KEYSHIDDEN_YES;
729    } else if (strcmp(name, "keyssoft") == 0) {
730        mask = out->MASK_KEYSHIDDEN;
731        value = out->KEYSHIDDEN_SOFT;
732    }
733
734    if (mask != 0) {
735        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
736        return true;
737    }
738
739    return false;
740}
741
742bool AaptGroupEntry::getKeyboardName(const char* name,
743                                        ResTable_config* out)
744{
745    if (strcmp(name, kWildcardName) == 0) {
746        if (out) out->keyboard = out->KEYBOARD_ANY;
747        return true;
748    } else if (strcmp(name, "nokeys") == 0) {
749        if (out) out->keyboard = out->KEYBOARD_NOKEYS;
750        return true;
751    } else if (strcmp(name, "qwerty") == 0) {
752        if (out) out->keyboard = out->KEYBOARD_QWERTY;
753        return true;
754    } else if (strcmp(name, "12key") == 0) {
755        if (out) out->keyboard = out->KEYBOARD_12KEY;
756        return true;
757    }
758
759    return false;
760}
761
762bool AaptGroupEntry::getNavigationName(const char* name,
763                                     ResTable_config* out)
764{
765    if (strcmp(name, kWildcardName) == 0) {
766        if (out) out->navigation = out->NAVIGATION_ANY;
767        return true;
768    } else if (strcmp(name, "nonav") == 0) {
769        if (out) out->navigation = out->NAVIGATION_NONAV;
770        return true;
771    } else if (strcmp(name, "dpad") == 0) {
772        if (out) out->navigation = out->NAVIGATION_DPAD;
773        return true;
774    } else if (strcmp(name, "trackball") == 0) {
775        if (out) out->navigation = out->NAVIGATION_TRACKBALL;
776        return true;
777    } else if (strcmp(name, "wheel") == 0) {
778        if (out) out->navigation = out->NAVIGATION_WHEEL;
779        return true;
780    }
781
782    return false;
783}
784
785bool AaptGroupEntry::getScreenSizeName(const char* name,
786                                       ResTable_config* out)
787{
788    if (strcmp(name, kWildcardName) == 0) {
789        if (out) {
790            out->screenWidth = out->SCREENWIDTH_ANY;
791            out->screenHeight = out->SCREENHEIGHT_ANY;
792        }
793        return true;
794    }
795
796    const char* x = name;
797    while (*x >= '0' && *x <= '9') x++;
798    if (x == name || *x != 'x') return false;
799    String8 xName(name, x-name);
800    x++;
801
802    const char* y = x;
803    while (*y >= '0' && *y <= '9') y++;
804    if (y == name || *y != 0) return false;
805    String8 yName(x, y-x);
806
807    uint16_t w = (uint16_t)atoi(xName.string());
808    uint16_t h = (uint16_t)atoi(yName.string());
809    if (w < h) {
810        return false;
811    }
812
813    if (out) {
814        out->screenWidth = w;
815        out->screenHeight = h;
816    }
817
818    return true;
819}
820
821bool AaptGroupEntry::getScreenLayoutName(const char* name,
822                                     ResTable_config* out)
823{
824    if (strcmp(name, kWildcardName) == 0) {
825        if (out) out->screenLayout = out->SCREENLAYOUT_ANY;
826        return true;
827    } else if (strcmp(name, "smallscreen") == 0) {
828        if (out) out->screenLayout = out->SCREENLAYOUT_SMALL;
829        return true;
830    } else if (strcmp(name, "normalscreen") == 0) {
831        if (out) out->screenLayout = out->SCREENLAYOUT_NORMAL;
832        return true;
833    } else if (strcmp(name, "largescreen") == 0) {
834        if (out) out->screenLayout = out->SCREENLAYOUT_LARGE;
835        return true;
836    }
837
838    return false;
839}
840
841bool AaptGroupEntry::getVersionName(const char* name,
842                                    ResTable_config* out)
843{
844    if (strcmp(name, kWildcardName) == 0) {
845        if (out) {
846            out->sdkVersion = out->SDKVERSION_ANY;
847            out->minorVersion = out->MINORVERSION_ANY;
848        }
849        return true;
850    }
851
852    if (*name != 'v') {
853        return false;
854    }
855
856    name++;
857    const char* s = name;
858    while (*s >= '0' && *s <= '9') s++;
859    if (s == name || *s != 0) return false;
860    String8 sdkName(name, s-name);
861
862    if (out) {
863        out->sdkVersion = (uint16_t)atoi(sdkName.string());
864        out->minorVersion = 0;
865    }
866
867    return true;
868}
869
870int AaptGroupEntry::compare(const AaptGroupEntry& o) const
871{
872    int v = mcc.compare(o.mcc);
873    if (v == 0) v = mnc.compare(o.mnc);
874    if (v == 0) v = locale.compare(o.locale);
875    if (v == 0) v = vendor.compare(o.vendor);
876    if (v == 0) v = orientation.compare(o.orientation);
877    if (v == 0) v = density.compare(o.density);
878    if (v == 0) v = touchscreen.compare(o.touchscreen);
879    if (v == 0) v = keysHidden.compare(o.keysHidden);
880    if (v == 0) v = keyboard.compare(o.keyboard);
881    if (v == 0) v = navigation.compare(o.navigation);
882    if (v == 0) v = screenSize.compare(o.screenSize);
883    if (v == 0) v = screenLayout.compare(o.screenLayout);
884    if (v == 0) v = version.compare(o.version);
885    return v;
886}
887
888ResTable_config AaptGroupEntry::toParams() const
889{
890    ResTable_config params;
891    memset(&params, 0, sizeof(params));
892    getMccName(mcc.string(), &params);
893    getMncName(mnc.string(), &params);
894    getLocaleName(locale.string(), &params);
895    getOrientationName(orientation.string(), &params);
896    getDensityName(density.string(), &params);
897    getTouchscreenName(touchscreen.string(), &params);
898    getKeysHiddenName(keysHidden.string(), &params);
899    getKeyboardName(keyboard.string(), &params);
900    getNavigationName(navigation.string(), &params);
901    getScreenSizeName(screenSize.string(), &params);
902    getScreenLayoutName(screenLayout.string(), &params);
903    getVersionName(version.string(), &params);
904    return params;
905}
906
907// =========================================================================
908// =========================================================================
909// =========================================================================
910
911void* AaptFile::editData(size_t size)
912{
913    if (size <= mBufferSize) {
914        mDataSize = size;
915        return mData;
916    }
917    size_t allocSize = (size*3)/2;
918    void* buf = realloc(mData, allocSize);
919    if (buf == NULL) {
920        return NULL;
921    }
922    mData = buf;
923    mDataSize = size;
924    mBufferSize = allocSize;
925    return buf;
926}
927
928void* AaptFile::editData(size_t* outSize)
929{
930    if (outSize) {
931        *outSize = mDataSize;
932    }
933    return mData;
934}
935
936void* AaptFile::padData(size_t wordSize)
937{
938    const size_t extra = mDataSize%wordSize;
939    if (extra == 0) {
940        return mData;
941    }
942
943    size_t initial = mDataSize;
944    void* data = editData(initial+(wordSize-extra));
945    if (data != NULL) {
946        memset(((uint8_t*)data) + initial, 0, wordSize-extra);
947    }
948    return data;
949}
950
951status_t AaptFile::writeData(const void* data, size_t size)
952{
953    size_t end = mDataSize;
954    size_t total = size + end;
955    void* buf = editData(total);
956    if (buf == NULL) {
957        return UNKNOWN_ERROR;
958    }
959    memcpy(((char*)buf)+end, data, size);
960    return NO_ERROR;
961}
962
963void AaptFile::clearData()
964{
965    if (mData != NULL) free(mData);
966    mData = NULL;
967    mDataSize = 0;
968    mBufferSize = 0;
969}
970
971String8 AaptFile::getPrintableSource() const
972{
973    if (hasData()) {
974        String8 name(mGroupEntry.locale.string());
975        name.appendPath(mGroupEntry.vendor.string());
976        name.appendPath(mPath);
977        name.append(" #generated");
978        return name;
979    }
980    return mSourceFile;
981}
982
983// =========================================================================
984// =========================================================================
985// =========================================================================
986
987status_t AaptGroup::addFile(const sp<AaptFile>& file)
988{
989    if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
990        file->mPath = mPath;
991        mFiles.add(file->getGroupEntry(), file);
992        return NO_ERROR;
993    }
994
995    SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
996                                               getPrintableSource().string());
997    return UNKNOWN_ERROR;
998}
999
1000void AaptGroup::removeFile(size_t index)
1001{
1002	mFiles.removeItemsAt(index);
1003}
1004
1005void AaptGroup::print() const
1006{
1007    printf("  %s\n", getPath().string());
1008    const size_t N=mFiles.size();
1009    size_t i;
1010    for (i=0; i<N; i++) {
1011        sp<AaptFile> file = mFiles.valueAt(i);
1012        const AaptGroupEntry& e = file->getGroupEntry();
1013        if (file->hasData()) {
1014            printf("      Gen: (%s) %d bytes\n", e.toString().string(),
1015                    (int)file->getSize());
1016        } else {
1017            printf("      Src: %s\n", file->getPrintableSource().string());
1018        }
1019    }
1020}
1021
1022String8 AaptGroup::getPrintableSource() const
1023{
1024    if (mFiles.size() > 0) {
1025        // Arbitrarily pull the first source file out of the list.
1026        return mFiles.valueAt(0)->getPrintableSource();
1027    }
1028
1029    // Should never hit this case, but to be safe...
1030    return getPath();
1031
1032}
1033
1034// =========================================================================
1035// =========================================================================
1036// =========================================================================
1037
1038status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1039{
1040    if (mFiles.indexOfKey(name) >= 0) {
1041        return ALREADY_EXISTS;
1042    }
1043    mFiles.add(name, file);
1044    return NO_ERROR;
1045}
1046
1047status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1048{
1049    if (mDirs.indexOfKey(name) >= 0) {
1050        return ALREADY_EXISTS;
1051    }
1052    mDirs.add(name, dir);
1053    return NO_ERROR;
1054}
1055
1056sp<AaptDir> AaptDir::makeDir(const String8& path)
1057{
1058    String8 name;
1059    String8 remain = path;
1060
1061    sp<AaptDir> subdir = this;
1062    while (name = remain.walkPath(&remain), remain != "") {
1063        subdir = subdir->makeDir(name);
1064    }
1065
1066    ssize_t i = subdir->mDirs.indexOfKey(name);
1067    if (i >= 0) {
1068        return subdir->mDirs.valueAt(i);
1069    }
1070    sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1071    subdir->mDirs.add(name, dir);
1072    return dir;
1073}
1074
1075void AaptDir::removeFile(const String8& name)
1076{
1077    mFiles.removeItem(name);
1078}
1079
1080void AaptDir::removeDir(const String8& name)
1081{
1082    mDirs.removeItem(name);
1083}
1084
1085status_t AaptDir::renameFile(const sp<AaptFile>& file, const String8& newName)
1086{
1087	sp<AaptGroup> origGroup;
1088
1089	// Find and remove the given file with shear, brute force!
1090	const size_t NG = mFiles.size();
1091	size_t i;
1092	for (i=0; origGroup == NULL && i<NG; i++) {
1093		sp<AaptGroup> g = mFiles.valueAt(i);
1094		const size_t NF = g->getFiles().size();
1095		for (size_t j=0; j<NF; j++) {
1096			if (g->getFiles().valueAt(j) == file) {
1097				origGroup = g;
1098				g->removeFile(j);
1099				if (NF == 1) {
1100					mFiles.removeItemsAt(i);
1101				}
1102				break;
1103			}
1104		}
1105	}
1106
1107	//printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1108
1109	// Place the file under its new name.
1110	if (origGroup != NULL) {
1111		return addLeafFile(newName, file);
1112	}
1113
1114	return NO_ERROR;
1115}
1116
1117status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
1118{
1119    sp<AaptGroup> group;
1120    if (mFiles.indexOfKey(leafName) >= 0) {
1121        group = mFiles.valueFor(leafName);
1122    } else {
1123        group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1124        mFiles.add(leafName, group);
1125    }
1126
1127    return group->addFile(file);
1128}
1129
1130ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
1131                            const AaptGroupEntry& kind, const String8& resType)
1132{
1133    Vector<String8> fileNames;
1134
1135    {
1136        DIR* dir = NULL;
1137
1138        dir = opendir(srcDir.string());
1139        if (dir == NULL) {
1140            fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1141            return UNKNOWN_ERROR;
1142        }
1143
1144        /*
1145         * Slurp the filenames out of the directory.
1146         */
1147        while (1) {
1148            struct dirent* entry;
1149
1150            entry = readdir(dir);
1151            if (entry == NULL)
1152                break;
1153
1154            if (isHidden(srcDir.string(), entry->d_name))
1155                continue;
1156
1157            fileNames.add(String8(entry->d_name));
1158        }
1159
1160        closedir(dir);
1161    }
1162
1163    ssize_t count = 0;
1164
1165    /*
1166     * Stash away the files and recursively descend into subdirectories.
1167     */
1168    const size_t N = fileNames.size();
1169    size_t i;
1170    for (i = 0; i < N; i++) {
1171        String8 pathName(srcDir);
1172        FileType type;
1173
1174        pathName.appendPath(fileNames[i].string());
1175        type = getFileType(pathName.string());
1176        if (type == kFileTypeDirectory) {
1177            sp<AaptDir> subdir;
1178            bool notAdded = false;
1179            if (mDirs.indexOfKey(fileNames[i]) >= 0) {
1180                subdir = mDirs.valueFor(fileNames[i]);
1181            } else {
1182                subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
1183                notAdded = true;
1184            }
1185            ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
1186                                                resType);
1187            if (res < NO_ERROR) {
1188                return res;
1189            }
1190            if (res > 0 && notAdded) {
1191                mDirs.add(fileNames[i], subdir);
1192            }
1193            count += res;
1194        } else if (type == kFileTypeRegular) {
1195            sp<AaptFile> file = new AaptFile(pathName, kind, resType);
1196            status_t err = addLeafFile(fileNames[i], file);
1197            if (err != NO_ERROR) {
1198                return err;
1199            }
1200
1201            count++;
1202
1203        } else {
1204            if (bundle->getVerbose())
1205                printf("   (ignoring non-file/dir '%s')\n", pathName.string());
1206        }
1207    }
1208
1209    return count;
1210}
1211
1212status_t AaptDir::validate() const
1213{
1214    const size_t NF = mFiles.size();
1215    const size_t ND = mDirs.size();
1216    size_t i;
1217    for (i = 0; i < NF; i++) {
1218        if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
1219            SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1220                    "Invalid filename.  Unable to add.");
1221            return UNKNOWN_ERROR;
1222        }
1223
1224        size_t j;
1225        for (j = i+1; j < NF; j++) {
1226            if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1227                           mFiles.valueAt(j)->getLeaf().string()) == 0) {
1228                SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1229                        "File is case-insensitive equivalent to: %s",
1230                        mFiles.valueAt(j)->getPrintableSource().string());
1231                return UNKNOWN_ERROR;
1232            }
1233
1234            // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1235            // (this is mostly caught by the "marked" stuff, below)
1236        }
1237
1238        for (j = 0; j < ND; j++) {
1239            if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1240                           mDirs.valueAt(j)->getLeaf().string()) == 0) {
1241                SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1242                        "File conflicts with dir from: %s",
1243                        mDirs.valueAt(j)->getPrintableSource().string());
1244                return UNKNOWN_ERROR;
1245            }
1246        }
1247    }
1248
1249    for (i = 0; i < ND; i++) {
1250        if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
1251            SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1252                    "Invalid directory name, unable to add.");
1253            return UNKNOWN_ERROR;
1254        }
1255
1256        size_t j;
1257        for (j = i+1; j < ND; j++) {
1258            if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
1259                           mDirs.valueAt(j)->getLeaf().string()) == 0) {
1260                SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1261                        "Directory is case-insensitive equivalent to: %s",
1262                        mDirs.valueAt(j)->getPrintableSource().string());
1263                return UNKNOWN_ERROR;
1264            }
1265        }
1266
1267        status_t err = mDirs.valueAt(i)->validate();
1268        if (err != NO_ERROR) {
1269            return err;
1270        }
1271    }
1272
1273    return NO_ERROR;
1274}
1275
1276void AaptDir::print() const
1277{
1278    const size_t ND=getDirs().size();
1279    size_t i;
1280    for (i=0; i<ND; i++) {
1281        getDirs().valueAt(i)->print();
1282    }
1283
1284    const size_t NF=getFiles().size();
1285    for (i=0; i<NF; i++) {
1286        getFiles().valueAt(i)->print();
1287    }
1288}
1289
1290String8 AaptDir::getPrintableSource() const
1291{
1292    if (mFiles.size() > 0) {
1293        // Arbitrarily pull the first file out of the list as the source dir.
1294        return mFiles.valueAt(0)->getPrintableSource().getPathDir();
1295    }
1296    if (mDirs.size() > 0) {
1297        // Or arbitrarily pull the first dir out of the list as the source dir.
1298        return mDirs.valueAt(0)->getPrintableSource().getPathDir();
1299    }
1300
1301    // Should never hit this case, but to be safe...
1302    return mPath;
1303
1304}
1305
1306// =========================================================================
1307// =========================================================================
1308// =========================================================================
1309
1310sp<AaptFile> AaptAssets::addFile(
1311        const String8& filePath, const AaptGroupEntry& entry,
1312        const String8& srcDir, sp<AaptGroup>* outGroup,
1313        const String8& resType)
1314{
1315    sp<AaptDir> dir = this;
1316    sp<AaptGroup> group;
1317    sp<AaptFile> file;
1318    String8 root, remain(filePath), partialPath;
1319    while (remain.length() > 0) {
1320        root = remain.walkPath(&remain);
1321        partialPath.appendPath(root);
1322
1323        const String8 rootStr(root);
1324
1325        if (remain.length() == 0) {
1326            ssize_t i = dir->getFiles().indexOfKey(rootStr);
1327            if (i >= 0) {
1328                group = dir->getFiles().valueAt(i);
1329            } else {
1330                group = new AaptGroup(rootStr, filePath);
1331                status_t res = dir->addFile(rootStr, group);
1332                if (res != NO_ERROR) {
1333                    return NULL;
1334                }
1335            }
1336            file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
1337            status_t res = group->addFile(file);
1338            if (res != NO_ERROR) {
1339                return NULL;
1340            }
1341            break;
1342
1343        } else {
1344            ssize_t i = dir->getDirs().indexOfKey(rootStr);
1345            if (i >= 0) {
1346                dir = dir->getDirs().valueAt(i);
1347            } else {
1348                sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
1349                status_t res = dir->addDir(rootStr, subdir);
1350                if (res != NO_ERROR) {
1351                    return NULL;
1352                }
1353                dir = subdir;
1354            }
1355        }
1356    }
1357
1358    mGroupEntries.add(entry);
1359    if (outGroup) *outGroup = group;
1360    return file;
1361}
1362
1363void AaptAssets::addResource(const String8& leafName, const String8& path,
1364                const sp<AaptFile>& file, const String8& resType)
1365{
1366    sp<AaptDir> res = AaptDir::makeDir(kResString);
1367    String8 dirname = file->getGroupEntry().toDirName(resType);
1368    sp<AaptDir> subdir = res->makeDir(dirname);
1369    sp<AaptGroup> grr = new AaptGroup(leafName, path);
1370    grr->addFile(file);
1371
1372    subdir->addFile(leafName, grr);
1373}
1374
1375
1376ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
1377{
1378    int count;
1379    int totalCount = 0;
1380    FileType type;
1381    const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
1382    const size_t dirCount =resDirs.size();
1383    sp<AaptAssets> current = this;
1384
1385    const int N = bundle->getFileSpecCount();
1386
1387    /*
1388     * If a package manifest was specified, include that first.
1389     */
1390    if (bundle->getAndroidManifestFile() != NULL) {
1391        // place at root of zip.
1392        String8 srcFile(bundle->getAndroidManifestFile());
1393        addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
1394                NULL, String8());
1395        totalCount++;
1396    }
1397
1398    /*
1399     * If a directory of custom assets was supplied, slurp 'em up.
1400     */
1401    if (bundle->getAssetSourceDir()) {
1402        const char* assetDir = bundle->getAssetSourceDir();
1403
1404        FileType type = getFileType(assetDir);
1405        if (type == kFileTypeNonexistent) {
1406            fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
1407            return UNKNOWN_ERROR;
1408        }
1409        if (type != kFileTypeDirectory) {
1410            fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1411            return UNKNOWN_ERROR;
1412        }
1413
1414        String8 assetRoot(assetDir);
1415        sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
1416        AaptGroupEntry group;
1417        count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
1418                                            String8());
1419        if (count < 0) {
1420            totalCount = count;
1421            goto bail;
1422        }
1423        if (count > 0) {
1424            mGroupEntries.add(group);
1425        }
1426        totalCount += count;
1427
1428        if (bundle->getVerbose())
1429            printf("Found %d custom asset file%s in %s\n",
1430                   count, (count==1) ? "" : "s", assetDir);
1431    }
1432
1433    /*
1434     * If a directory of resource-specific assets was supplied, slurp 'em up.
1435     */
1436    for (size_t i=0; i<dirCount; i++) {
1437        const char *res = resDirs[i];
1438        if (res) {
1439            type = getFileType(res);
1440            if (type == kFileTypeNonexistent) {
1441                fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
1442                return UNKNOWN_ERROR;
1443            }
1444            if (type == kFileTypeDirectory) {
1445                if (i>0) {
1446                    sp<AaptAssets> nextOverlay = new AaptAssets();
1447                    current->setOverlay(nextOverlay);
1448                    current = nextOverlay;
1449                }
1450                count = current->slurpResourceTree(bundle, String8(res));
1451
1452                if (count < 0) {
1453                    totalCount = count;
1454                    goto bail;
1455                }
1456                totalCount += count;
1457            }
1458            else {
1459                fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
1460                return UNKNOWN_ERROR;
1461            }
1462        }
1463
1464    }
1465    /*
1466     * Now do any additional raw files.
1467     */
1468    for (int arg=0; arg<N; arg++) {
1469        const char* assetDir = bundle->getFileSpecEntry(arg);
1470
1471        FileType type = getFileType(assetDir);
1472        if (type == kFileTypeNonexistent) {
1473            fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
1474            return UNKNOWN_ERROR;
1475        }
1476        if (type != kFileTypeDirectory) {
1477            fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1478            return UNKNOWN_ERROR;
1479        }
1480
1481        String8 assetRoot(assetDir);
1482
1483        if (bundle->getVerbose())
1484            printf("Processing raw dir '%s'\n", (const char*) assetDir);
1485
1486        /*
1487         * Do a recursive traversal of subdir tree.  We don't make any
1488         * guarantees about ordering, so we're okay with an inorder search
1489         * using whatever order the OS happens to hand back to us.
1490         */
1491        count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8());
1492        if (count < 0) {
1493            /* failure; report error and remove archive */
1494            totalCount = count;
1495            goto bail;
1496        }
1497        totalCount += count;
1498
1499        if (bundle->getVerbose())
1500            printf("Found %d asset file%s in %s\n",
1501                   count, (count==1) ? "" : "s", assetDir);
1502    }
1503
1504    count = validate();
1505    if (count != NO_ERROR) {
1506        totalCount = count;
1507        goto bail;
1508    }
1509
1510
1511bail:
1512    return totalCount;
1513}
1514
1515ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
1516                                    const AaptGroupEntry& kind,
1517                                    const String8& resType)
1518{
1519    ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType);
1520    if (res > 0) {
1521        mGroupEntries.add(kind);
1522    }
1523
1524    return res;
1525}
1526
1527ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
1528{
1529    ssize_t err = 0;
1530
1531    DIR* dir = opendir(srcDir.string());
1532    if (dir == NULL) {
1533        fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1534        return UNKNOWN_ERROR;
1535    }
1536
1537    status_t count = 0;
1538
1539    /*
1540     * Run through the directory, looking for dirs that match the
1541     * expected pattern.
1542     */
1543    while (1) {
1544        struct dirent* entry = readdir(dir);
1545        if (entry == NULL) {
1546            break;
1547        }
1548
1549        if (isHidden(srcDir.string(), entry->d_name)) {
1550            continue;
1551        }
1552
1553        String8 subdirName(srcDir);
1554        subdirName.appendPath(entry->d_name);
1555
1556        AaptGroupEntry group;
1557        String8 resType;
1558        bool b = group.initFromDirName(entry->d_name, &resType);
1559        if (!b) {
1560            fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
1561                    entry->d_name);
1562            err = -1;
1563            continue;
1564        }
1565
1566        FileType type = getFileType(subdirName.string());
1567
1568        if (type == kFileTypeDirectory) {
1569            sp<AaptDir> dir = makeDir(String8(entry->d_name));
1570            ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
1571                                                resType);
1572            if (res < 0) {
1573                count = res;
1574                goto bail;
1575            }
1576            if (res > 0) {
1577                mGroupEntries.add(group);
1578                count += res;
1579            }
1580
1581            mDirs.add(dir);
1582        } else {
1583            if (bundle->getVerbose()) {
1584                fprintf(stderr, "   (ignoring file '%s')\n", subdirName.string());
1585            }
1586        }
1587    }
1588
1589bail:
1590    closedir(dir);
1591    dir = NULL;
1592
1593    if (err != 0) {
1594        return err;
1595    }
1596    return count;
1597}
1598
1599ssize_t
1600AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
1601{
1602    int count = 0;
1603    SortedVector<AaptGroupEntry> entries;
1604
1605    ZipFile* zip = new ZipFile;
1606    status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
1607    if (err != NO_ERROR) {
1608        fprintf(stderr, "error opening zip file %s\n", filename);
1609        count = err;
1610        delete zip;
1611        return -1;
1612    }
1613
1614    const int N = zip->getNumEntries();
1615    for (int i=0; i<N; i++) {
1616        ZipEntry* entry = zip->getEntryByIndex(i);
1617        if (entry->getDeleted()) {
1618            continue;
1619        }
1620
1621        String8 entryName(entry->getFileName());
1622
1623        String8 dirName = entryName.getPathDir();
1624        sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
1625
1626        String8 resType;
1627        AaptGroupEntry kind;
1628
1629        String8 remain;
1630        if (entryName.walkPath(&remain) == kResourceDir) {
1631            // these are the resources, pull their type out of the directory name
1632            kind.initFromDirName(remain.walkPath().string(), &resType);
1633        } else {
1634            // these are untyped and don't have an AaptGroupEntry
1635        }
1636        if (entries.indexOf(kind) < 0) {
1637            entries.add(kind);
1638            mGroupEntries.add(kind);
1639        }
1640
1641        // use the one from the zip file if they both exist.
1642        dir->removeFile(entryName.getPathLeaf());
1643
1644        sp<AaptFile> file = new AaptFile(entryName, kind, resType);
1645        status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
1646        if (err != NO_ERROR) {
1647            fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
1648            count = err;
1649            goto bail;
1650        }
1651        file->setCompressionMethod(entry->getCompressionMethod());
1652
1653#if 0
1654        if (entryName == "AndroidManifest.xml") {
1655            printf("AndroidManifest.xml\n");
1656        }
1657        printf("\n\nfile: %s\n", entryName.string());
1658#endif
1659
1660        size_t len = entry->getUncompressedLen();
1661        void* data = zip->uncompress(entry);
1662        void* buf = file->editData(len);
1663        memcpy(buf, data, len);
1664
1665#if 0
1666        const int OFF = 0;
1667        const unsigned char* p = (unsigned char*)data;
1668        const unsigned char* end = p+len;
1669        p += OFF;
1670        for (int i=0; i<32 && p < end; i++) {
1671            printf("0x%03x ", i*0x10 + OFF);
1672            for (int j=0; j<0x10 && p < end; j++) {
1673                printf(" %02x", *p);
1674                p++;
1675            }
1676            printf("\n");
1677        }
1678#endif
1679
1680        free(data);
1681
1682        count++;
1683    }
1684
1685bail:
1686    delete zip;
1687    return count;
1688}
1689
1690sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
1691{
1692    sp<AaptSymbols> sym = mSymbols.valueFor(name);
1693    if (sym == NULL) {
1694        sym = new AaptSymbols();
1695        mSymbols.add(name, sym);
1696    }
1697    return sym;
1698}
1699
1700status_t AaptAssets::buildIncludedResources(Bundle* bundle)
1701{
1702    if (!mHaveIncludedAssets) {
1703        // Add in all includes.
1704        const Vector<const char*>& incl = bundle->getPackageIncludes();
1705        const size_t N=incl.size();
1706        for (size_t i=0; i<N; i++) {
1707            if (bundle->getVerbose())
1708                printf("Including resources from package: %s\n", incl[i]);
1709            if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
1710                fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
1711                        incl[i]);
1712                return UNKNOWN_ERROR;
1713            }
1714        }
1715        mHaveIncludedAssets = true;
1716    }
1717
1718    return NO_ERROR;
1719}
1720
1721status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
1722{
1723    const ResTable& res = getIncludedResources();
1724    // XXX dirty!
1725    return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL);
1726}
1727
1728const ResTable& AaptAssets::getIncludedResources() const
1729{
1730    return mIncludedAssets.getResources(false);
1731}
1732
1733void AaptAssets::print() const
1734{
1735    printf("Locale/Vendor pairs:\n");
1736    const size_t N=mGroupEntries.size();
1737    for (size_t i=0; i<N; i++) {
1738        printf("   %s/%s\n",
1739               mGroupEntries.itemAt(i).locale.string(),
1740               mGroupEntries.itemAt(i).vendor.string());
1741    }
1742
1743    printf("\nFiles:\n");
1744    AaptDir::print();
1745}
1746
1747bool
1748valid_symbol_name(const String8& symbol)
1749{
1750    static char const * const KEYWORDS[] = {
1751        "abstract", "assert", "boolean", "break",
1752        "byte", "case", "catch", "char", "class", "const", "continue",
1753        "default", "do", "double", "else", "enum", "extends", "final",
1754        "finally", "float", "for", "goto", "if", "implements", "import",
1755        "instanceof", "int", "interface", "long", "native", "new", "package",
1756        "private", "protected", "public", "return", "short", "static",
1757        "strictfp", "super", "switch", "synchronized", "this", "throw",
1758        "throws", "transient", "try", "void", "volatile", "while",
1759        "true", "false", "null",
1760        NULL
1761    };
1762    const char*const* k = KEYWORDS;
1763    const char*const s = symbol.string();
1764    while (*k) {
1765        if (0 == strcmp(s, *k)) {
1766            return false;
1767        }
1768        k++;
1769    }
1770    return true;
1771}
1772