Move String8 path functions to androidfw and aapt
Test: m checkbuild
Bug: 295394788
Change-Id: I9488bc5632cbd47c83f6b5f2df4c87eb324a1e8e
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index c80fb18..86e1fe3d 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -80,7 +80,10 @@
export_include_dirs: ["include"],
export_shared_lib_headers: ["libz"],
static_libs: ["libincfs-utils"],
- whole_static_libs: ["libincfs-utils"],
+ whole_static_libs: [
+ "libandroidfw_pathutils",
+ "libincfs-utils",
+ ],
export_static_lib_headers: ["libincfs-utils"],
target: {
android: {
@@ -132,6 +135,28 @@
},
}
+cc_library_static {
+ name: "libandroidfw_pathutils",
+ defaults: ["libandroidfw_defaults"],
+ host_supported: true,
+ export_include_dirs: ["include_pathutils"],
+ srcs: [
+ "PathUtils.cpp",
+ ],
+ shared_libs: [
+ "libutils",
+ ],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ visibility: [
+ ":__subpackages__",
+ "//frameworks/base/tools/aapt",
+ ],
+}
+
common_test_libs = [
"libandroidfw",
"libbase",
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 795bb3c..fd6e18e 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -26,6 +26,7 @@
#include <androidfw/AssetDir.h>
#include <androidfw/AssetManager.h>
#include <androidfw/misc.h>
+#include <androidfw/PathUtils.h>
#include <androidfw/ResourceTypes.h>
#include <androidfw/ZipFileRO.h>
#include <cutils/atomic.h>
@@ -88,7 +89,7 @@
const char* root = getenv("ANDROID_DATA");
LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
String8 path(root);
- path.appendPath(kResourceCache);
+ appendPath(path, kResourceCache);
char buf[256]; // 256 chars should be enough for anyone...
strncpy(buf, pkgPath.c_str(), 255);
@@ -104,7 +105,7 @@
}
++p;
}
- path.appendPath(filename);
+ appendPath(path, filename);
path.append("@idmap");
return path;
@@ -181,7 +182,7 @@
String8 realPath(path);
if (kAppZipName) {
- realPath.appendPath(kAppZipName);
+ appendPath(realPath, kAppZipName);
}
ap.type = ::getFileType(realPath.c_str());
if (ap.type == kFileTypeRegular) {
@@ -367,7 +368,7 @@
LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
String8 path(root);
- path.appendPath(kSystemAssets);
+ appendPath(path, kSystemAssets);
return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
}
@@ -439,7 +440,7 @@
LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
String8 assetName(kAssetsRoot);
- assetName.appendPath(fileName);
+ appendPath(assetName, fileName);
/*
* For each top-level asset path, search for the asset.
@@ -587,8 +588,8 @@
const char* data = getenv("ANDROID_DATA");
LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
String8 overlaysListPath(data);
- overlaysListPath.appendPath(kResourceCache);
- overlaysListPath.appendPath("overlays.list");
+ appendPath(overlaysListPath, kResourceCache);
+ appendPath(overlaysListPath, "overlays.list");
addSystemOverlays(overlaysListPath.c_str(), ap.path, sharedRes, nextEntryIdx);
#endif
sharedRes = const_cast<AssetManager*>(this)->
@@ -789,7 +790,7 @@
/* look at the filesystem on disk */
if (ap.type == kFileTypeDirectory) {
String8 path(ap.path);
- path.appendPath(fileName);
+ appendPath(path, fileName);
pAsset = openAssetFromFileLocked(path, mode);
@@ -841,9 +842,9 @@
sourceName.append(zipFileName);
sourceName.append(":");
if (dirName.length() > 0) {
- sourceName.appendPath(dirName);
+ appendPath(sourceName, dirName);
}
- sourceName.appendPath(fileName);
+ appendPath(sourceName, fileName);
return sourceName;
}
@@ -853,7 +854,7 @@
String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
{
String8 path(ap.path);
- if (rootDir != NULL) path.appendPath(rootDir);
+ if (rootDir != NULL) appendPath(path, rootDir);
return path;
}
@@ -897,7 +898,7 @@
{
Asset* pAsset = NULL;
- if (strcasecmp(pathName.getPathExtension().c_str(), ".gz") == 0) {
+ if (strcasecmp(getPathExtension(pathName).c_str(), ".gz") == 0) {
//printf("TRYING '%s'\n", (const char*) pathName);
pAsset = Asset::createFromCompressedFile(pathName.c_str(), mode);
} else {
@@ -1078,8 +1079,7 @@
//printf("scanAndMergeDir: %s %s %s\n", ap.path.c_str(), rootDir, dirName);
String8 path = createPathNameLocked(ap, rootDir);
- if (dirName[0] != '\0')
- path.appendPath(dirName);
+ if (dirName[0] != '\0') appendPath(path, dirName);
SortedVector<AssetDir::FileInfo>* pContents = scanDirLocked(path);
if (pContents == NULL)
@@ -1176,7 +1176,7 @@
fileType = kFileTypeUnknown;
#else
// stat the file
- fileType = ::getFileType(path.appendPathCopy(entry->d_name).c_str());
+ fileType = ::getFileType(appendPathCopy(path, entry->d_name).c_str());
#endif
if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
@@ -1184,9 +1184,9 @@
AssetDir::FileInfo info;
info.set(String8(entry->d_name), fileType);
- if (strcasecmp(info.getFileName().getPathExtension().c_str(), ".gz") == 0)
- info.setFileName(info.getFileName().getBasePath());
- info.setSourceName(path.appendPathCopy(info.getFileName()));
+ if (strcasecmp(getPathExtension(info.getFileName()).c_str(), ".gz") == 0)
+ info.setFileName(getBasePath(info.getFileName()));
+ info.setSourceName(appendPathCopy(path, info.getFileName()));
pContents->add(info);
}
@@ -1220,7 +1220,7 @@
/* convert "sounds" to "rootDir/sounds" */
if (rootDir != NULL) dirName = rootDir;
- dirName.appendPath(baseDirName);
+ appendPath(dirName, baseDirName);
/*
* Scan through the list of files, looking for a match. The files in
@@ -1269,7 +1269,7 @@
if (nextSlash == NULL) {
/* this is a file in the requested directory */
- info.set(String8(nameBuf).getPathLeaf(), kFileTypeRegular);
+ info.set(getPathLeaf(String8(nameBuf)), kFileTypeRegular);
info.setSourceName(
createZipSourceNameLocked(zipName, dirName, info.getFileName()));
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index 3582609..1a6a952 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -30,6 +30,7 @@
#include <utime.h>
#include <zlib.h>
+#include <androidfw/PathUtils.h>
#include <log/log.h>
#include <utils/ByteOrder.h>
#include <utils/KeyedVector.h>
@@ -606,14 +607,14 @@
prefix += packageName;
}
if (domain.length() > 0) {
- prefix.appendPath(domain);
+ appendPath(prefix, domain);
}
// pax extended means we don't put in a prefix field, and put a different
// string in the basic name field. We can also construct the full path name
// out of the substrings we've now built.
fullname = prefix;
- fullname.appendPath(relpath);
+ appendPath(fullname, relpath);
// ustar:
// [ 0 : 100 ]; file name/path
@@ -654,7 +655,7 @@
// Now build the pax *header* templated on the ustar header
memcpy(paxHeader, buf, 512);
- String8 leaf = fullname.getPathLeaf();
+ String8 leaf = getPathLeaf(fullname);
memset(paxHeader, 0, 100); // rewrite the name area
snprintf(paxHeader, 100, "PaxHeader/%s", leaf.c_str());
memset(paxHeader + 345, 0, 155); // rewrite the prefix area
diff --git a/libs/androidfw/PathUtils.cpp b/libs/androidfw/PathUtils.cpp
new file mode 100644
index 0000000..df7a9f0
--- /dev/null
+++ b/libs/androidfw/PathUtils.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2023 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 <androidfw/PathUtils.h>
+
+#include <utils/Compat.h>
+
+namespace android {
+
+String8 getPathLeaf(const String8& str) {
+ const char* cp;
+ const char*const buf = str.c_str();
+
+ cp = strrchr(buf, OS_PATH_SEPARATOR);
+ if (cp == nullptr)
+ return str;
+ else
+ return String8(cp+1);
+}
+
+String8 getPathDir(const String8& str8) {
+ const char* cp;
+ const char*const str = str8.c_str();
+
+ cp = strrchr(str, OS_PATH_SEPARATOR);
+ if (cp == nullptr)
+ return String8();
+ else
+ return String8(str, cp - str);
+}
+
+static char* findExtension(const String8& str8) {
+ const char* lastSlash;
+ const char* lastDot;
+ const char* const str = str8.c_str();
+
+ // only look at the filename
+ lastSlash = strrchr(str, OS_PATH_SEPARATOR);
+ if (lastSlash == nullptr)
+ lastSlash = str;
+ else
+ lastSlash++;
+
+ // find the last dot
+ lastDot = strrchr(lastSlash, '.');
+ if (lastDot == nullptr)
+ return nullptr;
+
+ // looks good, ship it
+ return const_cast<char*>(lastDot);
+}
+
+String8 getPathExtension(const String8& str) {
+ char* ext;
+
+ ext = findExtension(str);
+ if (ext != nullptr)
+ return String8(ext);
+ else
+ return String8();
+}
+
+String8 getBasePath(const String8& str8) {
+ char* ext;
+ const char* const str = str8.c_str();
+
+ ext = findExtension(str8);
+ if (ext == nullptr)
+ return str8;
+ else
+ return String8(str, ext - str);
+}
+
+static void setPathName(String8& s, const char* name) {
+ size_t len = strlen(name);
+ char* buf = s.lockBuffer(len);
+
+ memcpy(buf, name, len);
+
+ // remove trailing path separator, if present
+ if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
+ buf[len] = '\0';
+
+ s.unlockBuffer(len);
+}
+
+String8& appendPath(String8& str, const char* name) {
+ // TODO: The test below will fail for Win32 paths. Fix later or ignore.
+ if (name[0] != OS_PATH_SEPARATOR) {
+ if (*name == '\0') {
+ // nothing to do
+ return str;
+ }
+
+ size_t len = str.length();
+ if (len == 0) {
+ // no existing filename, just use the new one
+ setPathName(str, name);
+ return str;
+ }
+
+ // make room for oldPath + '/' + newPath
+ int newlen = strlen(name);
+
+ char* buf = str.lockBuffer(len+1+newlen);
+
+ // insert a '/' if needed
+ if (buf[len-1] != OS_PATH_SEPARATOR)
+ buf[len++] = OS_PATH_SEPARATOR;
+
+ memcpy(buf+len, name, newlen+1);
+ len += newlen;
+
+ str.unlockBuffer(len);
+ return str;
+ } else {
+ setPathName(str, name);
+ return str;
+ }
+}
+
+} // namespace android
diff --git a/libs/androidfw/include_pathutils/androidfw/PathUtils.h b/libs/androidfw/include_pathutils/androidfw/PathUtils.h
new file mode 100644
index 0000000..4debe8d
--- /dev/null
+++ b/libs/androidfw/include_pathutils/androidfw/PathUtils.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+#include <utils/String8.h>
+
+/* This library contains path manipulation functions that are used only by androidfw and aapt.
+ * When it's possible, migrate all uses to std::filesystem::path.
+ */
+
+namespace android {
+
+/**
+ * Get just the filename component.
+ *
+ * DEPRECATED: use std::filesystem::path::filename
+ *
+ * "/tmp/foo/bar.c" --> "bar.c"
+ */
+String8 getPathLeaf(const String8& str);
+
+/**
+ * Remove the last (file name) component, leaving just the directory
+ * name.
+ *
+ * DEPRECATED: use std::filesystem::path::parent_path
+ *
+ * "/tmp/foo/bar.c" --> "/tmp/foo"
+ * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
+ * "bar.c" --> ""
+ */
+String8 getPathDir(const String8& str);
+
+/**
+ * Return the filename extension. This is the last '.' and any number
+ * of characters that follow it. The '.' is included in case we
+ * decide to expand our definition of what constitutes an extension.
+ *
+ * DEPRECATED: use std::filesystem::path::extension
+ *
+ * "/tmp/foo/bar.c" --> ".c"
+ * "/tmp" --> ""
+ * "/tmp/foo.bar/baz" --> ""
+ * "foo.jpeg" --> ".jpeg"
+ * "foo." --> ""
+ */
+String8 getPathExtension(const String8& str);
+
+/**
+ * Return the path without the extension. Rules for what constitutes
+ * an extension are described in the comment for getPathExtension().
+ *
+ * DEPRECATED: use std::filesystem::path::stem and std::filesystem::path::parent_path
+ *
+ * "/tmp/foo/bar.c" --> "/tmp/foo/bar"
+ */
+String8 getBasePath(const String8& str);
+
+/**
+ * Add a component to the pathname. We guarantee that there is
+ * exactly one path separator between the old path and the new.
+ * If there is no existing name, we just copy the new name in.
+ *
+ * DEPRECATED: use std::filesystem::path::operator/=
+ *
+ * If leaf is a fully qualified path (i.e. starts with '/', it
+ * replaces whatever was there before.
+ */
+String8& appendPath(String8& str, const char* leaf);
+inline String8& appendPath(String8& str, const String8& leaf) {
+ return appendPath(str, leaf.c_str());
+}
+
+/**
+ * Like appendPath(), but does not affect this string. Returns a new one instead.
+ *
+ * DEPRECATED: use std::filesystem::operator/
+ */
+inline String8 appendPathCopy(String8 str, const char* leaf) { return appendPath(str, leaf); }
+inline String8 appendPathCopy(String8 str, const String8& leaf) {
+ return appendPath(str, leaf.c_str());
+}
+
+} // namespace android