<Hermetic> Implement CPython2 Launcher in C++.

The launcher is actually a wrapper which will statically link Python
interpreter within the .par file. It is used to bootstrap embedded
interpreter.

The next step is to change/integrate with Soong to make this hermetic .par
generation process more automatic.

Bug: b/62380596

Test: The launcher has been tested using real files:
zip -r hermetic.zip entry_point.txt Stdlib/ runfiles/
cat launcher | cat - hermetic.zip > executable && chmod u+x executable

Change-Id: I293cae2fe74d46766044f3e3c4b654a54d319b67
diff --git a/Modules/config.c b/Modules/config.c
index 4f0e55e..807d1e9 100644
--- a/Modules/config.c
+++ b/Modules/config.c
@@ -75,6 +75,7 @@
 extern void initresource(void);
 extern void init_multibytecodec(void);
 extern void init_multiprocessing(void);
+extern void initzlib(void);
 
 /* -- ADDMODULE MARKER 1 -- */
 
@@ -138,6 +139,7 @@
     {"resource", initresource},
     {"_multibytecodec", init_multibytecodec},
     {"_multiprocessing", init_multiprocessing},
+    {"zlib", initzlib},
 
 /* -- ADDMODULE MARKER 2 -- */
 
diff --git a/Modules/getpath.c b/Modules/getpath.c
index c42ce31..e9d969b 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -104,6 +104,14 @@
 #define LANDMARK "os.py"
 #endif
 
+#ifndef INTERNALDIR
+#define INTERNALDIR "internal"
+#endif
+
+#ifndef STDLIBDIR
+#define STDLIBDIR "stdlib"
+#endif
+
 static char prefix[MAXPATHLEN+1];
 static char exec_prefix[MAXPATHLEN+1];
 static char progpath[MAXPATHLEN+1];
@@ -255,8 +263,11 @@
         return 1;
     }
 
-    /* Check to see if argv[0] is in the build directory */
+    // GOOGLE(nanzhang): Always set prefix with hermetic executable full path.
     strcpy(prefix, argv0_path);
+    return 1;
+
+    /* Check to see if argv[0] is in the build directory */
     joinpath(prefix, "Modules/Setup");
     if (isfile(prefix)) {
         /* Check VPATH to see if argv0_path is in the build directory. */
@@ -314,10 +325,13 @@
         return 1;
     }
 
+    // GOOGLE(nanzhang): Always set exec_prefix with hermetic executable full path.
+    strcpy(exec_prefix, argv0_path);
+    return 1;
+
     /* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
        is written by setup.py and contains the relative path to the location
        of shared library modules. */
-    strcpy(exec_prefix, argv0_path);
     joinpath(exec_prefix, "pybuilddir.txt");
     if (isfile(exec_prefix)) {
       FILE *f = fopen(exec_prefix, "r");
@@ -363,19 +377,62 @@
 calculate_path(void)
 {
     extern char *Py_GetProgramName(void);
-
     static char delimiter[2] = {DELIM, '\0'};
     static char separator[2] = {SEP, '\0'};
     char *pythonpath = PYTHONPATH;
-    char *rtpypath = Py_GETENV("PYTHONPATH");
     char *home = Py_GetPythonHome();
-    char *path = getenv("PATH");
+    // We have overrided argv[0] using the full path to the hermetic Python
+    // launcher itself. And then Py_SetProgramName(argv[0]) was invoked at
+    // launcher_main.cpp. The launcher_main.cpp has guaranteed that
+    // strlen(Py_GetProgramName()) must not exceed MAXPATHLEN.
     char *prog = Py_GetProgramName();
     char argv0_path[MAXPATHLEN+1];
-    char zip_path[MAXPATHLEN+1];
-    int pfound, efound; /* 1 if found; -1 if found build directory */
     char *buf;
     size_t bufsz;
+
+    strncpy(progpath, prog, MAXPATHLEN);
+    progpath[MAXPATHLEN] = '\0' /* In case of no NUL-termination. */;
+    strncpy(argv0_path, prog, MAXPATHLEN);
+    argv0_path[MAXPATHLEN] = '\0' /* In case of no NUL-termination. */;
+
+    // We don't reduce the path of prefix, and exec_prefix.
+    search_for_prefix(argv0_path, home);
+    search_for_exec_prefix(argv0_path, home);
+
+    // Calculate size of return buffer.
+    bufsz = strlen(prog) + 1 + sizeof(INTERNALDIR) /* 1 is for SEP */;
+    bufsz += strlen(prog) + 1 + sizeof(INTERNALDIR) + 1 + sizeof(STDLIBDIR) /* 1 is for SEP */;
+
+    /* This is the only malloc call in this file */
+    buf = (char *)PyMem_Malloc(bufsz);
+
+    if (buf == NULL) {
+        /* We can't exit, so print a warning and limp along */
+        fprintf(stderr, "Not enough memory for dynamic PYTHONPATH.\n");
+        fprintf(stderr, "Using default static PYTHONPATH.\n");
+        exit(1);
+    } else {
+        buf[0] = '\0';
+        strcat(buf, prefix);
+        strcat(buf, separator);
+        strcat(buf, INTERNALDIR);
+        strcat(buf, delimiter);
+
+        strcat(buf, prefix);
+        strcat(buf, separator);
+        strcat(buf, INTERNALDIR);
+        strcat(buf, separator);
+        strcat(buf, STDLIBDIR);
+
+        module_search_path = buf;
+    }
+    // GOOGLE(nanzhang): Don't need all the code below for embedded Python launcher.
+    return;
+
+    char *path = getenv("PATH");
+    char *rtpypath = Py_GETENV("PYTHONPATH");
+    char zip_path[MAXPATHLEN+1];
+    int pfound, efound; /* 1 if found; -1 if found build directory */
     size_t prefixsz;
     char *defpath = pythonpath;
 #ifdef WITH_NEXT_FRAMEWORK
diff --git a/Modules/zipimport.c b/Modules/zipimport.c
index 1691773..0a7cd0f 100644
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -43,9 +43,11 @@
 static PyObject *ZipImportError;
 static PyObject *zip_directory_cache = NULL;
 
+// GOOGLE(nanzhang): Changed two functions below to be visible to launcher so
+// that launcher can access the zip metadata section.
 /* forward decls */
-static PyObject *read_directory(const char *archive);
-static PyObject *get_data(const char *archive, PyObject *toc_entry);
+PyObject *read_directory(const char *archive);
+PyObject *get_data(const char *archive, PyObject *toc_entry);
 static PyObject *get_module_code(ZipImporter *self, char *fullname,
                                  int *p_ispackage, char **p_modpath);
 
@@ -702,7 +704,7 @@
    Directories can be recognized by the trailing SEP in the name,
    data_size and file_offset are 0.
 */
-static PyObject *
+PyObject *
 read_directory(const char *archive)
 {
     PyObject *files = NULL;
@@ -912,7 +914,7 @@
 
 /* Given a path to a Zip file and a toc_entry, return the (uncompressed)
    data as a new reference. */
-static PyObject *
+PyObject *
 get_data(const char *archive, PyObject *toc_entry)
 {
     PyObject *raw_data = NULL, *data, *decompress;