Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee46239c authored by Elliott Hughes's avatar Elliott Hughes Committed by Gerrit Code Review
Browse files

Merge "adb: win32: make adb_getenv() case-insensitive"

parents 933f4fd4 e6ae5735
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -78,6 +78,9 @@ LIBADB_TEST_linux_SRCS := \
LIBADB_TEST_darwin_SRCS := \
    fdevent_test.cpp \

LIBADB_TEST_windows_SRCS := \
    sysdeps_win32_test.cpp \

include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := libadbd
@@ -153,6 +156,7 @@ LOCAL_SRC_FILES := \

LOCAL_SRC_FILES_linux := $(LIBADB_TEST_linux_SRCS)
LOCAL_SRC_FILES_darwin := $(LIBADB_TEST_darwin_SRCS)
LOCAL_SRC_FILES_windows := $(LIBADB_TEST_windows_SRCS)
LOCAL_SANITIZE := $(adb_host_sanitize)
LOCAL_SHARED_LIBRARIES := libbase
LOCAL_STATIC_LIBRARIES := \
@@ -160,6 +164,8 @@ LOCAL_STATIC_LIBRARIES := \
    libcrypto_static \
    libcutils \

# Set entrypoint to wmain from sysdeps_win32.cpp instead of main
LOCAL_LDFLAGS_windows := -municode
LOCAL_LDLIBS_linux := -lrt -ldl -lpthread
LOCAL_LDLIBS_darwin := -framework CoreFoundation -framework IOKit
LOCAL_LDLIBS_windows := -lws2_32 -luserenv
+0 −26
Original line number Diff line number Diff line
@@ -169,34 +169,8 @@ int adb_main(int is_daemon, int server_port, int ack_reply_fd) {
    return 0;
}

#ifdef _WIN32
static bool _argv_is_utf8 = false;
#endif

int main(int argc, char** argv) {
#ifdef _WIN32
    if (!_argv_is_utf8) {
        fatal("_argv_is_utf8 is not set, suggesting that wmain was not "
              "called. Did you forget to link with -municode?");
    }
#endif

    adb_sysdeps_init();
    adb_trace_init(argv);
    return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
}

#ifdef _WIN32

extern "C"
int wmain(int argc, wchar_t **argv) {
    // Set diagnostic flag to try to detect if the build system was not
    // configured to call wmain.
    _argv_is_utf8 = true;

    // Convert args from UTF-16 to UTF-8 and pass that to main().
    NarrowArgs narrow_args(argc, argv);
    return main(argc, narrow_args.data());
}

#endif
+42 −6
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>

#include <algorithm>
#include <memory>
#include <string>
#include <unordered_map>
@@ -3776,6 +3777,29 @@ FILE* adb_fopen(const char* f, const char* m) {
    return _wfopen(widen(f).c_str(), widen(m).c_str());
}

// Return a lowercase version of the argument. Uses C Runtime tolower() on
// each byte which is not UTF-8 aware, and theoretically uses the current C
// Runtime locale (which in practice is not changed, so this becomes a ASCII
// conversion).
static std::string ToLower(const std::string& anycase) {
    // copy string
    std::string str(anycase);
    // transform the copy
    std::transform(str.begin(), str.end(), str.begin(), tolower);
    return str;
}

extern "C" int main(int argc, char** argv);

// Link with -municode to cause this wmain() to be used as the program
// entrypoint. It will convert the args from UTF-16 to UTF-8 and call the
// regular main() with UTF-8 args.
extern "C" int wmain(int argc, wchar_t **argv) {
    // Convert args from UTF-16 to UTF-8 and pass that to main().
    NarrowArgs narrow_args(argc, argv);
    return main(argc, narrow_args.data());
}

// Shadow UTF-8 environment variable name/value pairs that are created from
// _wenviron the first time that adb_getenv() is called. Note that this is not
// currently updated if putenv, setenv, unsetenv are called. Note that no
@@ -3790,6 +3814,13 @@ static void _ensure_env_setup() {
        return;
    }

    if (_wenviron == nullptr) {
        // If _wenviron is null, then -municode probably wasn't used. That
        // linker flag will cause the entry point to setup _wenviron. It will
        // also require an implementation of wmain() (which we provide above).
        fatal("_wenviron is not set, did you link with -municode?");
    }

    // Read name/value pairs from UTF-16 _wenviron and write new name/value
    // pairs to UTF-8 g_environ_utf8. Note that it probably does not make sense
    // to use the D() macro here because that tracing only works if the
@@ -3803,21 +3834,26 @@ static void _ensure_env_setup() {
            continue;
        }

        const std::string name_utf8(narrow(std::wstring(*env, equal - *env)));
        // Store lowercase name so that we can do case-insensitive searches.
        const std::string name_utf8(ToLower(narrow(
                std::wstring(*env, equal - *env))));
        char* const value_utf8 = strdup(narrow(equal + 1).c_str());

        // Overwrite any duplicate name, but there shouldn't be a dup in the
        // first place.
        g_environ_utf8[name_utf8] = value_utf8;
        // Don't overwrite a previus env var with the same name. In reality,
        // the system probably won't let two env vars with the same name exist
        // in _wenviron.
        g_environ_utf8.insert({name_utf8, value_utf8});
    }
}

// Version of getenv() that takes a UTF-8 environment variable name and
// retrieves a UTF-8 value.
// retrieves a UTF-8 value. Case-insensitive to match getenv() on Windows.
char* adb_getenv(const char* name) {
    _ensure_env_setup();

    const auto it = g_environ_utf8.find(std::string(name));
    // Case-insensitive search by searching for lowercase name in a map of
    // lowercase names.
    const auto it = g_environ_utf8.find(ToLower(std::string(name)));
    if (it == g_environ_utf8.end()) {
        return nullptr;
    }
+69 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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 <gtest/gtest.h>

#include "sysdeps.h"

TEST(sysdeps_win32, adb_getenv) {
    // Insert all test env vars before first call to adb_getenv() which will
    // read the env var block only once.
    ASSERT_EQ(0, _putenv("SYSDEPS_WIN32_TEST_UPPERCASE=1"));
    ASSERT_EQ(0, _putenv("sysdeps_win32_test_lowercase=2"));
    ASSERT_EQ(0, _putenv("Sysdeps_Win32_Test_MixedCase=3"));

    // UTF-16 value
    ASSERT_EQ(0, _wputenv(L"SYSDEPS_WIN32_TEST_UNICODE=\u00a1\u0048\u006f\u006c"
                          L"\u0061\u0021\u03b1\u03b2\u03b3\u0061\u006d\u0062"
                          L"\u0075\u006c\u014d\u043f\u0440\u0438\u0432\u0435"
                          L"\u0442"));

    // Search for non-existant env vars.
    EXPECT_STREQ(nullptr, adb_getenv("SYSDEPS_WIN32_TEST_NONEXISTANT"));

    // Search for existing env vars.

    // There is no test for an env var with a value of a zero-length string
    // because _putenv() does not support inserting such an env var.

    // Search for env var that is uppercase.
    EXPECT_STREQ("1", adb_getenv("SYSDEPS_WIN32_TEST_UPPERCASE"));
    EXPECT_STREQ("1", adb_getenv("sysdeps_win32_test_uppercase"));
    EXPECT_STREQ("1", adb_getenv("Sysdeps_Win32_Test_Uppercase"));

    // Search for env var that is lowercase.
    EXPECT_STREQ("2", adb_getenv("SYSDEPS_WIN32_TEST_LOWERCASE"));
    EXPECT_STREQ("2", adb_getenv("sysdeps_win32_test_lowercase"));
    EXPECT_STREQ("2", adb_getenv("Sysdeps_Win32_Test_Lowercase"));

    // Search for env var that is mixed-case.
    EXPECT_STREQ("3", adb_getenv("SYSDEPS_WIN32_TEST_MIXEDCASE"));
    EXPECT_STREQ("3", adb_getenv("sysdeps_win32_test_mixedcase"));
    EXPECT_STREQ("3", adb_getenv("Sysdeps_Win32_Test_MixedCase"));

    // Check that UTF-16 was converted to UTF-8.
    EXPECT_STREQ("\xc2\xa1\x48\x6f\x6c\x61\x21\xce\xb1\xce\xb2\xce\xb3\x61\x6d"
                 "\x62\x75\x6c\xc5\x8d\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5"
                 "\xd1\x82",
                 adb_getenv("SYSDEPS_WIN32_TEST_UNICODE"));

    // Check an env var that should always be set.
    const char* path_val = adb_getenv("PATH");
    EXPECT_NE(nullptr, path_val);
    if (path_val != nullptr) {
        EXPECT_GT(strlen(path_val), 0);
    }
}