Skip to content

Instantly share code, notes, and snippets.

@esafirm
Created July 5, 2023 05:25
Show Gist options
  • Save esafirm/d0cbe7a6b43f66f27520120c0cdbdca2 to your computer and use it in GitHub Desktop.
Save esafirm/d0cbe7a6b43f66f27520120c0cdbdca2 to your computer and use it in GitHub Desktop.
/**
* Parse the result from [apkanalyzer dex packages <apk>] and give us summary about the data
*
* Author @esafirm
*/
// (type/state/defined methods/referenced methods /byte size/name)
// P, C, M, and F indicate packages, classes, methods, and fields, respectively. And x, k, r, and d indicate removed, kept, referenced and defined nodes, respectively.
enum Type {
Packages,
Classes,
Methods,
Fields,
}
namespace Type {
export function of(type: string): Type {
switch (type) {
case "P":
return Type.Packages;
case "C":
return Type.Classes;
case "M":
return Type.Methods;
case "F":
return Type.Fields;
}
throw new Error(`Unknown type: ${type}`);
}
}
enum State {
Removed,
Kept,
Referenced,
Defined,
}
namespace State {
export function of(state: string): State {
switch (state) {
case "x":
return State.Removed;
case "k":
return State.Kept;
case "r":
return State.Referenced;
case "d":
return State.Defined;
}
throw new Error(`Unknown state: ${state}`);
}
}
function sizeToHumandReadable(size: string): string {
const sizeInByte = parseInt(size);
const sizeInKb = sizeInByte / 1024;
const sizeInMb = sizeInKb / 1024;
if (sizeInMb > 1) {
return `${sizeInMb.toFixed(2)} MB`;
} else if (sizeInKb > 1) {
return `${sizeInKb.toFixed(2)} KB`;
} else {
return `${sizeInByte} B`;
}
}
type TableRow = {
size: string;
name: string;
};
/* Main */
/* ------------------------------------------ */
//@ts-ignore also declaared in index.ts
const fs = require("fs");
const readline = require("readline");
//@ts-ignore also declaared in index.ts
const inputPath = "info.txt";
const outputPath = "info.html";
if (!fs.existsSync(inputPath)) {
throw new Error(`Input not exists at: ${inputPath}`);
}
const lineReader = readline.createInterface({
input: fs.createReadStream(inputPath),
});
const rows: TableRow[] = [];
lineReader.on("line", (line: string) => {
const [typeString, stateString, defined, referenced, size, name] = line.split(/\s+/);
const type = Type.of(typeString);
if (type === Type.Packages) {
if (name.split(".").length <= 3) {
rows.push({
size: sizeToHumandReadable(size),
name: name,
});
}
}
});
lineReader.on("error", (err: Error) => {
throw err;
});
lineReader.on("close", () => {
// create HTML table from the rows data
const content = `
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
</head>
<body>
<table>
<tr>
<th>Size</th>
<th>Name</th>
</tr>
${rows.map((row) => `<tr><td>${row.size}</td><td>${row.name}</td></tr>`).join("\n")}
</table>
</body>
</html>
`;
fs.writeFile(outputPath, content, (err: Error) => {
if (err) {
console.log("Error is happening!");
console.error(err);
} else {
console.log("Report parsing success!");
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment