Initial Contribution
diff --git a/tools/dexpreopt/afar/Android.mk b/tools/dexpreopt/afar/Android.mk
new file mode 100644
index 0000000..d224675
--- /dev/null
+++ b/tools/dexpreopt/afar/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	main.c
+
+# Just for adler32()
+LOCAL_C_INCLUDES := external/zlib
+LOCAL_SHARED_LIBRARIES := libz
+
+LOCAL_MODULE := afar
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/tools/dexpreopt/afar/main.c b/tools/dexpreopt/afar/main.c
new file mode 100644
index 0000000..d66d59c
--- /dev/null
+++ b/tools/dexpreopt/afar/main.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include <zlib.h>   // for adler32()
+
+static int verbose = 0;
+
+/*
+ * Android File Archive format:
+ *
+ * magic[5]: 'A' 'F' 'A' 'R' '\n'
+ * version[4]: 0x00 0x00 0x00 0x01
+ * for each file:
+ *     file magic[4]: 'F' 'I' 'L' 'E'
+ *     namelen[4]: Length of file name, including NUL byte (big-endian)
+ *     name[*]: NUL-terminated file name
+ *     datalen[4]: Length of file (big-endian)
+ *     data[*]: Unencoded file data
+ *     adler32[4]: adler32 of the unencoded file data (big-endian)
+ *     file end magic[4]: 'f' 'i' 'l' 'e'
+ * end magic[4]: 'E' 'N' 'D' 0x00
+ *
+ * This format is about as simple as possible;  it was designed to
+ * make it easier to transfer multiple files over an stdin/stdout
+ * pipe to another process, so word-alignment wasn't necessary.
+ */
+
+static void
+die(const char *why, ...)
+{
+    va_list ap;
+    
+    va_start(ap, why);
+    fprintf(stderr, "error: ");
+    vfprintf(stderr, why, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(1);
+}
+
+static void
+write_big_endian(size_t v)
+{
+    putchar((v >> 24) & 0xff);
+    putchar((v >> 16) & 0xff);
+    putchar((v >>  8) & 0xff);
+    putchar( v        & 0xff);
+}
+
+static void
+_eject(struct stat *s, char *out, int olen, char *data, size_t datasize)
+{
+    unsigned long adler;
+
+    /* File magic.
+     */
+    printf("FILE");
+
+    /* Name length includes the NUL byte.
+     */
+    write_big_endian(olen + 1);
+
+    /* File name and terminating NUL.
+     */
+    printf("%s", out);
+    putchar('\0');
+
+    /* File length.
+     */
+    write_big_endian(datasize);
+
+    /* File data.
+     */
+    if (fwrite(data, 1, datasize, stdout) != datasize) {
+        die("Error writing file data");
+    }
+
+    /* Checksum.
+     */
+    adler = adler32(0, NULL, 0);
+    adler = adler32(adler, (unsigned char *)data, datasize);
+    write_big_endian(adler);
+
+    /* File end magic.
+     */
+    printf("file");
+}
+
+static void _archive(char *in, int ilen);
+
+static void
+_archive_dir(char *in, int ilen)
+{
+    int t;
+    DIR *d;
+    struct dirent *de;
+
+    if (verbose) {
+        fprintf(stderr, "_archive_dir('%s', %d)\n", in, ilen);
+    }
+    
+    d = opendir(in);
+    if (d == 0) {
+        die("cannot open directory '%s'", in);
+    }
+    
+    while ((de = readdir(d)) != 0) {
+            /* xxx: feature? maybe some dotfiles are okay */
+        if (strcmp(de->d_name, ".") == 0 ||
+            strcmp(de->d_name, "..") == 0)
+        {
+            continue;
+        }
+
+        t = strlen(de->d_name);
+        in[ilen] = '/';
+        memcpy(in + ilen + 1, de->d_name, t + 1);
+
+        _archive(in, ilen + t + 1);
+
+        in[ilen] = '\0';
+    }
+}
+
+static void
+_archive(char *in, int ilen)
+{
+    struct stat s;
+
+    if (verbose) {
+        fprintf(stderr, "_archive('%s', %d)\n", in, ilen);
+    }
+    
+    if (lstat(in, &s)) {
+        die("could not stat '%s'\n", in);
+    }
+
+    if (S_ISREG(s.st_mode)) {
+        char *tmp;
+        int fd;
+
+        fd = open(in, O_RDONLY);
+        if (fd < 0) {
+            die("cannot open '%s' for read", in);
+        }
+
+        tmp = (char*) malloc(s.st_size);
+        if (tmp == 0) {
+            die("cannot allocate %d bytes", s.st_size);
+        }
+
+        if (read(fd, tmp, s.st_size) != s.st_size) {
+            die("cannot read %d bytes", s.st_size);
+        }
+
+        _eject(&s, in, ilen, tmp, s.st_size);
+        
+        free(tmp);
+        close(fd);
+    } else if (S_ISDIR(s.st_mode)) {
+        _archive_dir(in, ilen);
+    } else {
+        /* We don't handle links, etc. */
+        die("Unknown '%s' (mode %d)?\n", in, s.st_mode);
+    }
+}
+
+void archive(const char *start)
+{
+    char in[8192];
+
+    strcpy(in, start);
+
+    _archive_dir(in, strlen(in));
+}
+
+int
+main(int argc, char *argv[])
+{
+    struct termios old_termios;
+
+    if (argc == 1) {
+        die("usage: %s <dir-list>", argv[0]);
+    }
+    argc--;
+    argv++;
+
+    /* Force stdout into raw mode.
+     */
+    struct termios s;
+    if (tcgetattr(1, &s) < 0) {
+        die("Could not get termios for stdout");
+    }
+    old_termios = s;
+    cfmakeraw(&s);
+    if (tcsetattr(1, TCSANOW, &s) < 0) {
+        die("Could not set termios for stdout");
+    }
+
+    /* Print format magic and version.
+     */
+    printf("AFAR\n");
+    write_big_endian(1);
+
+    while (argc-- > 0) {
+        archive(*argv++);
+    }
+
+    /* Print end magic.
+     */
+    printf("END");
+    putchar('\0');
+
+    /* Restore stdout.
+     */
+    if (tcsetattr(1, TCSANOW, &old_termios) < 0) {
+        die("Could not restore termios for stdout");
+    }
+
+    return 0;
+}