AaptAssets.cpp revision cf4550c3198d6b3d92cdc52707fe70d7cc0caa9f
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 = 0;
658        return true;
659    }
660    char* c = (char*)name;
661    while (*c >= '0' && *c <= '9') {
662        c++;
663    }
664
665    // check that we have 'dpi' after the last digit.
666    if (toupper(c[0]) != 'D' ||
667            toupper(c[1]) != 'P' ||
668            toupper(c[2]) != 'I' ||
669            c[3] != 0) {
670        return false;
671    }
672
673    // temporarily replace the first letter with \0 to
674    // use atoi.
675    char tmp = c[0];
676    c[0] = '\0';
677
678    int d = atoi(name);
679    c[0] = tmp;
680
681    if (d != 0) {
682        if (out) out->density = d;
683        return true;
684    }
685
686    return false;
687}
688
689bool AaptGroupEntry::getTouchscreenName(const char* name,
690                                        ResTable_config* out)
691{
692    if (strcmp(name, kWildcardName) == 0) {
693        if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
694        return true;
695    } else if (strcmp(name, "notouch") == 0) {
696        if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
697        return true;
698    } else if (strcmp(name, "stylus") == 0) {
699        if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
700        return true;
701    } else if (strcmp(name, "finger") == 0) {
702        if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
703        return true;
704    }
705
706    return false;
707}
708
709bool AaptGroupEntry::getKeysHiddenName(const char* name,
710                                       ResTable_config* out)
711{
712    uint8_t mask = 0;
713    uint8_t value = 0;
714    if (strcmp(name, kWildcardName) == 0) {
715        mask = out->MASK_KEYSHIDDEN;
716        value = out->KEYSHIDDEN_ANY;
717    } else if (strcmp(name, "keysexposed") == 0) {
718        mask = out->MASK_KEYSHIDDEN;
719        value = out->KEYSHIDDEN_NO;
720    } else if (strcmp(name, "keyshidden") == 0) {
721        mask = out->MASK_KEYSHIDDEN;
722        value = out->KEYSHIDDEN_YES;
723    } else if (strcmp(name, "keyssoft") == 0) {
724        mask = out->MASK_KEYSHIDDEN;
725        value = out->KEYSHIDDEN_SOFT;
726    }
727
728    if (mask != 0) {
729        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
730        return true;
731    }
732
733    return false;
734}
735
736bool AaptGroupEntry::getKeyboardName(const char* name,
737                                        ResTable_config* out)
738{
739    if (strcmp(name, kWildcardName) == 0) {
740        if (out) out->keyboard = out->KEYBOARD_ANY;
741        return true;
742    } else if (strcmp(name, "nokeys") == 0) {
743        if (out) out->keyboard = out->KEYBOARD_NOKEYS;
744        return true;
745    } else if (strcmp(name, "qwerty") == 0) {
746        if (out) out->keyboard = out->KEYBOARD_QWERTY;
747        return true;
748    } else if (strcmp(name, "12key") == 0) {
749        if (out) out->keyboard = out->KEYBOARD_12KEY;
750        return true;
751    }
752
753    return false;
754}
755
756bool AaptGroupEntry::getNavigationName(const char* name,
757                                     ResTable_config* out)
758{
759    if (strcmp(name, kWildcardName) == 0) {
760        if (out) out->navigation = out->NAVIGATION_ANY;
761        return true;
762    } else if (strcmp(name, "nonav") == 0) {
763        if (out) out->navigation = out->NAVIGATION_NONAV;
764        return true;
765    } else if (strcmp(name, "dpad") == 0) {
766        if (out) out->navigation = out->NAVIGATION_DPAD;
767        return true;
768    } else if (strcmp(name, "trackball") == 0) {
769        if (out) out->navigation = out->NAVIGATION_TRACKBALL;
770        return true;
771    } else if (strcmp(name, "wheel") == 0) {
772        if (out) out->navigation = out->NAVIGATION_WHEEL;
773        return true;
774    }
775
776    return false;
777}
778
779bool AaptGroupEntry::getScreenSizeName(const char* name,
780                                       ResTable_config* out)
781{
782    if (strcmp(name, kWildcardName) == 0) {
783        if (out) {
784            out->screenWidth = out->SCREENWIDTH_ANY;
785            out->screenHeight = out->SCREENHEIGHT_ANY;
786        }
787        return true;
788    }
789
790    const char* x = name;
791    while (*x >= '0' && *x <= '9') x++;
792    if (x == name || *x != 'x') return false;
793    String8 xName(name, x-name);
794    x++;
795
796    const char* y = x;
797    while (*y >= '0' && *y <= '9') y++;
798    if (y == name || *y != 0) return false;
799    String8 yName(x, y-x);
800
801    uint16_t w = (uint16_t)atoi(xName.string());
802    uint16_t h = (uint16_t)atoi(yName.string());
803    if (w < h) {
804        return false;
805    }
806
807    if (out) {
808        out->screenWidth = w;
809        out->screenHeight = h;
810    }
811
812    return true;
813}
814
815bool AaptGroupEntry::getScreenLayoutName(const char* name,
816                                     ResTable_config* out)
817{
818    if (strcmp(name, kWildcardName) == 0) {
819        if (out) out->screenLayout = out->SCREENLAYOUT_ANY;
820        return true;
821    } else if (strcmp(name, "smallscreen") == 0) {
822        if (out) out->screenLayout = out->SCREENLAYOUT_SMALL;
823        return true;
824    } else if (strcmp(name, "normalscreen") == 0) {
825        if (out) out->screenLayout = out->SCREENLAYOUT_NORMAL;
826        return true;
827    } else if (strcmp(name, "largescreen") == 0) {
828        if (out) out->screenLayout = out->SCREENLAYOUT_LARGE;
829        return true;
830    }
831
832    return false;
833}
834
835bool AaptGroupEntry::getVersionName(const char* name,
836                                    ResTable_config* out)
837{
838    if (strcmp(name, kWildcardName) == 0) {
839        if (out) {
840            out->sdkVersion = out->SDKVERSION_ANY;
841            out->minorVersion = out->MINORVERSION_ANY;
842        }
843        return true;
844    }
845
846    if (*name != 'v') {
847        return false;
848    }
849
850    name++;
851    const char* s = name;
852    while (*s >= '0' && *s <= '9') s++;
853    if (s == name || *s != 0) return false;
854    String8 sdkName(name, s-name);
855
856    if (out) {
857        out->sdkVersion = (uint16_t)atoi(sdkName.string());
858        out->minorVersion = 0;
859    }
860
861    return true;
862}
863
864int AaptGroupEntry::compare(const AaptGroupEntry& o) const
865{
866    int v = mcc.compare(o.mcc);
867    if (v == 0) v = mnc.compare(o.mnc);
868    if (v == 0) v = locale.compare(o.locale);
869    if (v == 0) v = vendor.compare(o.vendor);
870    if (v == 0) v = orientation.compare(o.orientation);
871    if (v == 0) v = density.compare(o.density);
872    if (v == 0) v = touchscreen.compare(o.touchscreen);
873    if (v == 0) v = keysHidden.compare(o.keysHidden);
874    if (v == 0) v = keyboard.compare(o.keyboard);
875    if (v == 0) v = navigation.compare(o.navigation);
876    if (v == 0) v = screenSize.compare(o.screenSize);
877    if (v == 0) v = screenLayout.compare(o.screenLayout);
878    if (v == 0) v = version.compare(o.version);
879    return v;
880}
881
882ResTable_config AaptGroupEntry::toParams() const
883{
884    ResTable_config params;
885    memset(&params, 0, sizeof(params));
886    getMccName(mcc.string(), &params);
887    getMncName(mnc.string(), &params);
888    getLocaleName(locale.string(), &params);
889    getOrientationName(orientation.string(), &params);
890    getDensityName(density.string(), &params);
891    getTouchscreenName(touchscreen.string(), &params);
892    getKeysHiddenName(keysHidden.string(), &params);
893    getKeyboardName(keyboard.string(), &params);
894    getNavigationName(navigation.string(), &params);
895    getScreenSizeName(screenSize.string(), &params);
896    getScreenLayoutName(screenLayout.string(), &params);
897    getVersionName(version.string(), &params);
898    return params;
899}
900
901// =========================================================================
902// =========================================================================
903// =========================================================================
904
905void* AaptFile::editData(size_t size)
906{
907    if (size <= mBufferSize) {
908        mDataSize = size;
909        return mData;
910    }
911    size_t allocSize = (size*3)/2;
912    void* buf = realloc(mData, allocSize);
913    if (buf == NULL) {
914        return NULL;
915    }
916    mData = buf;
917    mDataSize = size;
918    mBufferSize = allocSize;
919    return buf;
920}
921
922void* AaptFile::editData(size_t* outSize)
923{
924    if (outSize) {
925        *outSize = mDataSize;
926    }
927    return mData;
928}
929
930void* AaptFile::padData(size_t wordSize)
931{
932    const size_t extra = mDataSize%wordSize;
933    if (extra == 0) {
934        return mData;
935    }
936
937    size_t initial = mDataSize;
938    void* data = editData(initial+(wordSize-extra));
939    if (data != NULL) {
940        memset(((uint8_t*)data) + initial, 0, wordSize-extra);
941    }
942    return data;
943}
944
945status_t AaptFile::writeData(const void* data, size_t size)
946{
947    size_t end = mDataSize;
948    size_t total = size + end;
949    void* buf = editData(total);
950    if (buf == NULL) {
951        return UNKNOWN_ERROR;
952    }
953    memcpy(((char*)buf)+end, data, size);
954    return NO_ERROR;
955}
956
957void AaptFile::clearData()
958{
959    if (mData != NULL) free(mData);
960    mData = NULL;
961    mDataSize = 0;
962    mBufferSize = 0;
963}
964
965String8 AaptFile::getPrintableSource() const
966{
967    if (hasData()) {
968        String8 name(mGroupEntry.locale.string());
969        name.appendPath(mGroupEntry.vendor.string());
970        name.appendPath(mPath);
971        name.append(" #generated");
972        return name;
973    }
974    return mSourceFile;
975}
976
977// =========================================================================
978// =========================================================================
979// =========================================================================
980
981status_t AaptGroup::addFile(const sp<AaptFile>& file)
982{
983    if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
984        file->mPath = mPath;
985        mFiles.add(file->getGroupEntry(), file);
986        return NO_ERROR;
987    }
988
989    SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
990                                               getPrintableSource().string());
991    return UNKNOWN_ERROR;
992}
993
994void AaptGroup::removeFile(size_t index)
995{
996	mFiles.removeItemsAt(index);
997}
998
999void AaptGroup::print() const
1000{
1001    printf("  %s\n", getPath().string());
1002    const size_t N=mFiles.size();
1003    size_t i;
1004    for (i=0; i<N; i++) {
1005        sp<AaptFile> file = mFiles.valueAt(i);
1006        const AaptGroupEntry& e = file->getGroupEntry();
1007        if (file->hasData()) {
1008            printf("      Gen: (%s) %d bytes\n", e.toString().string(),
1009                    (int)file->getSize());
1010        } else {
1011            printf("      Src: %s\n", file->getPrintableSource().string());
1012        }
1013    }
1014}
1015
1016String8 AaptGroup::getPrintableSource() const
1017{
1018    if (mFiles.size() > 0) {
1019        // Arbitrarily pull the first source file out of the list.
1020        return mFiles.valueAt(0)->getPrintableSource();
1021    }
1022
1023    // Should never hit this case, but to be safe...
1024    return getPath();
1025
1026}
1027
1028// =========================================================================
1029// =========================================================================
1030// =========================================================================
1031
1032status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1033{
1034    if (mFiles.indexOfKey(name) >= 0) {
1035        return ALREADY_EXISTS;
1036    }
1037    mFiles.add(name, file);
1038    return NO_ERROR;
1039}
1040
1041status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1042{
1043    if (mDirs.indexOfKey(name) >= 0) {
1044        return ALREADY_EXISTS;
1045    }
1046    mDirs.add(name, dir);
1047    return NO_ERROR;
1048}
1049
1050sp<AaptDir> AaptDir::makeDir(const String8& path)
1051{
1052    String8 name;
1053    String8 remain = path;
1054
1055    sp<AaptDir> subdir = this;
1056    while (name = remain.walkPath(&remain), remain != "") {
1057        subdir = subdir->makeDir(name);
1058    }
1059
1060    ssize_t i = subdir->mDirs.indexOfKey(name);
1061    if (i >= 0) {
1062        return subdir->mDirs.valueAt(i);
1063    }
1064    sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1065    subdir->mDirs.add(name, dir);
1066    return dir;
1067}
1068
1069void AaptDir::removeFile(const String8& name)
1070{
1071    mFiles.removeItem(name);
1072}
1073
1074void AaptDir::removeDir(const String8& name)
1075{
1076    mDirs.removeItem(name);
1077}
1078
1079status_t AaptDir::renameFile(const sp<AaptFile>& file, const String8& newName)
1080{
1081	sp<AaptGroup> origGroup;
1082
1083	// Find and remove the given file with shear, brute force!
1084	const size_t NG = mFiles.size();
1085	size_t i;
1086	for (i=0; origGroup == NULL && i<NG; i++) {
1087		sp<AaptGroup> g = mFiles.valueAt(i);
1088		const size_t NF = g->getFiles().size();
1089		for (size_t j=0; j<NF; j++) {
1090			if (g->getFiles().valueAt(j) == file) {
1091				origGroup = g;
1092				g->removeFile(j);
1093				if (NF == 1) {
1094					mFiles.removeItemsAt(i);
1095				}
1096				break;
1097			}
1098		}
1099	}
1100
1101	//printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1102
1103	// Place the file under its new name.
1104	if (origGroup != NULL) {
1105		return addLeafFile(newName, file);
1106	}
1107
1108	return NO_ERROR;
1109}
1110
1111status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
1112{
1113    sp<AaptGroup> group;
1114    if (mFiles.indexOfKey(leafName) >= 0) {
1115        group = mFiles.valueFor(leafName);
1116    } else {
1117        group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1118        mFiles.add(leafName, group);
1119    }
1120
1121    return group->addFile(file);
1122}
1123
1124ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
1125                            const AaptGroupEntry& kind, const String8& resType)
1126{
1127    Vector<String8> fileNames;
1128
1129    {
1130        DIR* dir = NULL;
1131
1132        dir = opendir(srcDir.string());
1133        if (dir == NULL) {
1134            fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1135            return UNKNOWN_ERROR;
1136        }
1137
1138        /*
1139         * Slurp the filenames out of the directory.
1140         */
1141        while (1) {
1142            struct dirent* entry;
1143
1144            entry = readdir(dir);
1145            if (entry == NULL)
1146                break;
1147
1148            if (isHidden(srcDir.string(), entry->d_name))
1149                continue;
1150
1151            fileNames.add(String8(entry->d_name));
1152        }
1153
1154        closedir(dir);
1155    }
1156
1157    ssize_t count = 0;
1158
1159    /*
1160     * Stash away the files and recursively descend into subdirectories.
1161     */
1162    const size_t N = fileNames.size();
1163    size_t i;
1164    for (i = 0; i < N; i++) {
1165        String8 pathName(srcDir);
1166        FileType type;
1167
1168        pathName.appendPath(fileNames[i].string());
1169        type = getFileType(pathName.string());
1170        if (type == kFileTypeDirectory) {
1171            sp<AaptDir> subdir;
1172            bool notAdded = false;
1173            if (mDirs.indexOfKey(fileNames[i]) >= 0) {
1174                subdir = mDirs.valueFor(fileNames[i]);
1175            } else {
1176                subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
1177                notAdded = true;
1178            }
1179            ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
1180                                                resType);
1181            if (res < NO_ERROR) {
1182                return res;
1183            }
1184            if (res > 0 && notAdded) {
1185                mDirs.add(fileNames[i], subdir);
1186            }
1187            count += res;
1188        } else if (type == kFileTypeRegular) {
1189            sp<AaptFile> file = new AaptFile(pathName, kind, resType);
1190            status_t err = addLeafFile(fileNames[i], file);
1191            if (err != NO_ERROR) {
1192                return err;
1193            }
1194
1195            count++;
1196
1197        } else {
1198            if (bundle->getVerbose())
1199                printf("   (ignoring non-file/dir '%s')\n", pathName.string());
1200        }
1201    }
1202
1203    return count;
1204}
1205
1206status_t AaptDir::validate() const
1207{
1208    const size_t NF = mFiles.size();
1209    const size_t ND = mDirs.size();
1210    size_t i;
1211    for (i = 0; i < NF; i++) {
1212        if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
1213            SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1214                    "Invalid filename.  Unable to add.");
1215            return UNKNOWN_ERROR;
1216        }
1217
1218        size_t j;
1219        for (j = i+1; j < NF; j++) {
1220            if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1221                           mFiles.valueAt(j)->getLeaf().string()) == 0) {
1222                SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1223                        "File is case-insensitive equivalent to: %s",
1224                        mFiles.valueAt(j)->getPrintableSource().string());
1225                return UNKNOWN_ERROR;
1226            }
1227
1228            // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1229            // (this is mostly caught by the "marked" stuff, below)
1230        }
1231
1232        for (j = 0; j < ND; j++) {
1233            if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1234                           mDirs.valueAt(j)->getLeaf().string()) == 0) {
1235                SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1236                        "File conflicts with dir from: %s",
1237                        mDirs.valueAt(j)->getPrintableSource().string());
1238                return UNKNOWN_ERROR;
1239            }
1240        }
1241    }
1242
1243    for (i = 0; i < ND; i++) {
1244        if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
1245            SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1246                    "Invalid directory name, unable to add.");
1247            return UNKNOWN_ERROR;
1248        }
1249
1250        size_t j;
1251        for (j = i+1; j < ND; j++) {
1252            if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
1253                           mDirs.valueAt(j)->getLeaf().string()) == 0) {
1254                SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1255                        "Directory is case-insensitive equivalent to: %s",
1256                        mDirs.valueAt(j)->getPrintableSource().string());
1257                return UNKNOWN_ERROR;
1258            }
1259        }
1260
1261        status_t err = mDirs.valueAt(i)->validate();
1262        if (err != NO_ERROR) {
1263            return err;
1264        }
1265    }
1266
1267    return NO_ERROR;
1268}
1269
1270void AaptDir::print() const
1271{
1272    const size_t ND=getDirs().size();
1273    size_t i;
1274    for (i=0; i<ND; i++) {
1275        getDirs().valueAt(i)->print();
1276    }
1277
1278    const size_t NF=getFiles().size();
1279    for (i=0; i<NF; i++) {
1280        getFiles().valueAt(i)->print();
1281    }
1282}
1283
1284String8 AaptDir::getPrintableSource() const
1285{
1286    if (mFiles.size() > 0) {
1287        // Arbitrarily pull the first file out of the list as the source dir.
1288        return mFiles.valueAt(0)->getPrintableSource().getPathDir();
1289    }
1290    if (mDirs.size() > 0) {
1291        // Or arbitrarily pull the first dir out of the list as the source dir.
1292        return mDirs.valueAt(0)->getPrintableSource().getPathDir();
1293    }
1294
1295    // Should never hit this case, but to be safe...
1296    return mPath;
1297
1298}
1299
1300// =========================================================================
1301// =========================================================================
1302// =========================================================================
1303
1304sp<AaptFile> AaptAssets::addFile(
1305        const String8& filePath, const AaptGroupEntry& entry,
1306        const String8& srcDir, sp<AaptGroup>* outGroup,
1307        const String8& resType)
1308{
1309    sp<AaptDir> dir = this;
1310    sp<AaptGroup> group;
1311    sp<AaptFile> file;
1312    String8 root, remain(filePath), partialPath;
1313    while (remain.length() > 0) {
1314        root = remain.walkPath(&remain);
1315        partialPath.appendPath(root);
1316
1317        const String8 rootStr(root);
1318
1319        if (remain.length() == 0) {
1320            ssize_t i = dir->getFiles().indexOfKey(rootStr);
1321            if (i >= 0) {
1322                group = dir->getFiles().valueAt(i);
1323            } else {
1324                group = new AaptGroup(rootStr, filePath);
1325                status_t res = dir->addFile(rootStr, group);
1326                if (res != NO_ERROR) {
1327                    return NULL;
1328                }
1329            }
1330            file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
1331            status_t res = group->addFile(file);
1332            if (res != NO_ERROR) {
1333                return NULL;
1334            }
1335            break;
1336
1337        } else {
1338            ssize_t i = dir->getDirs().indexOfKey(rootStr);
1339            if (i >= 0) {
1340                dir = dir->getDirs().valueAt(i);
1341            } else {
1342                sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
1343                status_t res = dir->addDir(rootStr, subdir);
1344                if (res != NO_ERROR) {
1345                    return NULL;
1346                }
1347                dir = subdir;
1348            }
1349        }
1350    }
1351
1352    mGroupEntries.add(entry);
1353    if (outGroup) *outGroup = group;
1354    return file;
1355}
1356
1357void AaptAssets::addResource(const String8& leafName, const String8& path,
1358                const sp<AaptFile>& file, const String8& resType)
1359{
1360    sp<AaptDir> res = AaptDir::makeDir(kResString);
1361    String8 dirname = file->getGroupEntry().toDirName(resType);
1362    sp<AaptDir> subdir = res->makeDir(dirname);
1363    sp<AaptGroup> grr = new AaptGroup(leafName, path);
1364    grr->addFile(file);
1365
1366    subdir->addFile(leafName, grr);
1367}
1368
1369
1370ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
1371{
1372    int count;
1373    int totalCount = 0;
1374    FileType type;
1375    const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
1376    const size_t dirCount =resDirs.size();
1377    sp<AaptAssets> current = this;
1378
1379    const int N = bundle->getFileSpecCount();
1380
1381    /*
1382     * If a package manifest was specified, include that first.
1383     */
1384    if (bundle->getAndroidManifestFile() != NULL) {
1385        // place at root of zip.
1386        String8 srcFile(bundle->getAndroidManifestFile());
1387        addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
1388                NULL, String8());
1389        totalCount++;
1390    }
1391
1392    /*
1393     * If a directory of custom assets was supplied, slurp 'em up.
1394     */
1395    if (bundle->getAssetSourceDir()) {
1396        const char* assetDir = bundle->getAssetSourceDir();
1397
1398        FileType type = getFileType(assetDir);
1399        if (type == kFileTypeNonexistent) {
1400            fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
1401            return UNKNOWN_ERROR;
1402        }
1403        if (type != kFileTypeDirectory) {
1404            fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1405            return UNKNOWN_ERROR;
1406        }
1407
1408        String8 assetRoot(assetDir);
1409        sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
1410        AaptGroupEntry group;
1411        count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
1412                                            String8());
1413        if (count < 0) {
1414            totalCount = count;
1415            goto bail;
1416        }
1417        if (count > 0) {
1418            mGroupEntries.add(group);
1419        }
1420        totalCount += count;
1421
1422        if (bundle->getVerbose())
1423            printf("Found %d custom asset file%s in %s\n",
1424                   count, (count==1) ? "" : "s", assetDir);
1425    }
1426
1427    /*
1428     * If a directory of resource-specific assets was supplied, slurp 'em up.
1429     */
1430    for (size_t i=0; i<dirCount; i++) {
1431        const char *res = resDirs[i];
1432        if (res) {
1433            type = getFileType(res);
1434            if (type == kFileTypeNonexistent) {
1435                fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
1436                return UNKNOWN_ERROR;
1437            }
1438            if (type == kFileTypeDirectory) {
1439                if (i>0) {
1440                    sp<AaptAssets> nextOverlay = new AaptAssets();
1441                    current->setOverlay(nextOverlay);
1442                    current = nextOverlay;
1443                }
1444                count = current->slurpResourceTree(bundle, String8(res));
1445
1446                if (count < 0) {
1447                    totalCount = count;
1448                    goto bail;
1449                }
1450                totalCount += count;
1451            }
1452            else {
1453                fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
1454                return UNKNOWN_ERROR;
1455            }
1456        }
1457
1458    }
1459    /*
1460     * Now do any additional raw files.
1461     */
1462    for (int arg=0; arg<N; arg++) {
1463        const char* assetDir = bundle->getFileSpecEntry(arg);
1464
1465        FileType type = getFileType(assetDir);
1466        if (type == kFileTypeNonexistent) {
1467            fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
1468            return UNKNOWN_ERROR;
1469        }
1470        if (type != kFileTypeDirectory) {
1471            fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1472            return UNKNOWN_ERROR;
1473        }
1474
1475        String8 assetRoot(assetDir);
1476
1477        if (bundle->getVerbose())
1478            printf("Processing raw dir '%s'\n", (const char*) assetDir);
1479
1480        /*
1481         * Do a recursive traversal of subdir tree.  We don't make any
1482         * guarantees about ordering, so we're okay with an inorder search
1483         * using whatever order the OS happens to hand back to us.
1484         */
1485        count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8());
1486        if (count < 0) {
1487            /* failure; report error and remove archive */
1488            totalCount = count;
1489            goto bail;
1490        }
1491        totalCount += count;
1492
1493        if (bundle->getVerbose())
1494            printf("Found %d asset file%s in %s\n",
1495                   count, (count==1) ? "" : "s", assetDir);
1496    }
1497
1498    count = validate();
1499    if (count != NO_ERROR) {
1500        totalCount = count;
1501        goto bail;
1502    }
1503
1504
1505bail:
1506    return totalCount;
1507}
1508
1509ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
1510                                    const AaptGroupEntry& kind,
1511                                    const String8& resType)
1512{
1513    ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType);
1514    if (res > 0) {
1515        mGroupEntries.add(kind);
1516    }
1517
1518    return res;
1519}
1520
1521ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
1522{
1523    ssize_t err = 0;
1524
1525    DIR* dir = opendir(srcDir.string());
1526    if (dir == NULL) {
1527        fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1528        return UNKNOWN_ERROR;
1529    }
1530
1531    status_t count = 0;
1532
1533    /*
1534     * Run through the directory, looking for dirs that match the
1535     * expected pattern.
1536     */
1537    while (1) {
1538        struct dirent* entry = readdir(dir);
1539        if (entry == NULL) {
1540            break;
1541        }
1542
1543        if (isHidden(srcDir.string(), entry->d_name)) {
1544            continue;
1545        }
1546
1547        String8 subdirName(srcDir);
1548        subdirName.appendPath(entry->d_name);
1549
1550        AaptGroupEntry group;
1551        String8 resType;
1552        bool b = group.initFromDirName(entry->d_name, &resType);
1553        if (!b) {
1554            fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
1555                    entry->d_name);
1556            err = -1;
1557            continue;
1558        }
1559
1560        FileType type = getFileType(subdirName.string());
1561
1562        if (type == kFileTypeDirectory) {
1563            sp<AaptDir> dir = makeDir(String8(entry->d_name));
1564            ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
1565                                                resType);
1566            if (res < 0) {
1567                count = res;
1568                goto bail;
1569            }
1570            if (res > 0) {
1571                mGroupEntries.add(group);
1572                count += res;
1573            }
1574
1575            mDirs.add(dir);
1576        } else {
1577            if (bundle->getVerbose()) {
1578                fprintf(stderr, "   (ignoring file '%s')\n", subdirName.string());
1579            }
1580        }
1581    }
1582
1583bail:
1584    closedir(dir);
1585    dir = NULL;
1586
1587    if (err != 0) {
1588        return err;
1589    }
1590    return count;
1591}
1592
1593ssize_t
1594AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
1595{
1596    int count = 0;
1597    SortedVector<AaptGroupEntry> entries;
1598
1599    ZipFile* zip = new ZipFile;
1600    status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
1601    if (err != NO_ERROR) {
1602        fprintf(stderr, "error opening zip file %s\n", filename);
1603        count = err;
1604        delete zip;
1605        return -1;
1606    }
1607
1608    const int N = zip->getNumEntries();
1609    for (int i=0; i<N; i++) {
1610        ZipEntry* entry = zip->getEntryByIndex(i);
1611        if (entry->getDeleted()) {
1612            continue;
1613        }
1614
1615        String8 entryName(entry->getFileName());
1616
1617        String8 dirName = entryName.getPathDir();
1618        sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
1619
1620        String8 resType;
1621        AaptGroupEntry kind;
1622
1623        String8 remain;
1624        if (entryName.walkPath(&remain) == kResourceDir) {
1625            // these are the resources, pull their type out of the directory name
1626            kind.initFromDirName(remain.walkPath().string(), &resType);
1627        } else {
1628            // these are untyped and don't have an AaptGroupEntry
1629        }
1630        if (entries.indexOf(kind) < 0) {
1631            entries.add(kind);
1632            mGroupEntries.add(kind);
1633        }
1634
1635        // use the one from the zip file if they both exist.
1636        dir->removeFile(entryName.getPathLeaf());
1637
1638        sp<AaptFile> file = new AaptFile(entryName, kind, resType);
1639        status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
1640        if (err != NO_ERROR) {
1641            fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
1642            count = err;
1643            goto bail;
1644        }
1645        file->setCompressionMethod(entry->getCompressionMethod());
1646
1647#if 0
1648        if (entryName == "AndroidManifest.xml") {
1649            printf("AndroidManifest.xml\n");
1650        }
1651        printf("\n\nfile: %s\n", entryName.string());
1652#endif
1653
1654        size_t len = entry->getUncompressedLen();
1655        void* data = zip->uncompress(entry);
1656        void* buf = file->editData(len);
1657        memcpy(buf, data, len);
1658
1659#if 0
1660        const int OFF = 0;
1661        const unsigned char* p = (unsigned char*)data;
1662        const unsigned char* end = p+len;
1663        p += OFF;
1664        for (int i=0; i<32 && p < end; i++) {
1665            printf("0x%03x ", i*0x10 + OFF);
1666            for (int j=0; j<0x10 && p < end; j++) {
1667                printf(" %02x", *p);
1668                p++;
1669            }
1670            printf("\n");
1671        }
1672#endif
1673
1674        free(data);
1675
1676        count++;
1677    }
1678
1679bail:
1680    delete zip;
1681    return count;
1682}
1683
1684sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
1685{
1686    sp<AaptSymbols> sym = mSymbols.valueFor(name);
1687    if (sym == NULL) {
1688        sym = new AaptSymbols();
1689        mSymbols.add(name, sym);
1690    }
1691    return sym;
1692}
1693
1694status_t AaptAssets::buildIncludedResources(Bundle* bundle)
1695{
1696    if (!mHaveIncludedAssets) {
1697        // Add in all includes.
1698        const Vector<const char*>& incl = bundle->getPackageIncludes();
1699        const size_t N=incl.size();
1700        for (size_t i=0; i<N; i++) {
1701            if (bundle->getVerbose())
1702                printf("Including resources from package: %s\n", incl[i]);
1703            if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
1704                fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
1705                        incl[i]);
1706                return UNKNOWN_ERROR;
1707            }
1708        }
1709        mHaveIncludedAssets = true;
1710    }
1711
1712    return NO_ERROR;
1713}
1714
1715status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
1716{
1717    const ResTable& res = getIncludedResources();
1718    // XXX dirty!
1719    return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL);
1720}
1721
1722const ResTable& AaptAssets::getIncludedResources() const
1723{
1724    return mIncludedAssets.getResources(false);
1725}
1726
1727void AaptAssets::print() const
1728{
1729    printf("Locale/Vendor pairs:\n");
1730    const size_t N=mGroupEntries.size();
1731    for (size_t i=0; i<N; i++) {
1732        printf("   %s/%s\n",
1733               mGroupEntries.itemAt(i).locale.string(),
1734               mGroupEntries.itemAt(i).vendor.string());
1735    }
1736
1737    printf("\nFiles:\n");
1738    AaptDir::print();
1739}
1740
1741bool
1742valid_symbol_name(const String8& symbol)
1743{
1744    static char const * const KEYWORDS[] = {
1745        "abstract", "assert", "boolean", "break",
1746        "byte", "case", "catch", "char", "class", "const", "continue",
1747        "default", "do", "double", "else", "enum", "extends", "final",
1748        "finally", "float", "for", "goto", "if", "implements", "import",
1749        "instanceof", "int", "interface", "long", "native", "new", "package",
1750        "private", "protected", "public", "return", "short", "static",
1751        "strictfp", "super", "switch", "synchronized", "this", "throw",
1752        "throws", "transient", "try", "void", "volatile", "while",
1753        "true", "false", "null",
1754        NULL
1755    };
1756    const char*const* k = KEYWORDS;
1757    const char*const s = symbol.string();
1758    while (*k) {
1759        if (0 == strcmp(s, *k)) {
1760            return false;
1761        }
1762        k++;
1763    }
1764    return true;
1765}
1766