Skip to content

Commit

Permalink
Add very bad demo
Browse files Browse the repository at this point in the history
  • Loading branch information
kubukoz committed Nov 13, 2022
1 parent bc6a6b8 commit 21ded9b
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 1 deletion.
13 changes: 12 additions & 1 deletion build.sbt
Expand Up @@ -61,8 +61,19 @@ lazy val examples = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.dependsOn(codecs)
.enablePlugins(NoPublishPlugin)

lazy val demo = crossProject(JSPlatform)
.crossType(CrossType.Pure)
.settings(
scalaJSUseMainModuleInitializer := true,
libraryDependencies ++= Seq(
"org.scala-js" %%% "scalajs-dom" % "2.2.0",
"com.lihaoyi" %%% "scalatags" % "0.12.0",
),
)
.dependsOn(examples)

lazy val root = tlCrossRootProject
.aggregate(core, codecs, examples)
.aggregate(core, codecs, examples, demo)
.settings(
Compile / doc / sources := Seq(),
sonatypeProfileName := "org.polyvariant",
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/scala/org/polyvariant/classfile/ClassFile.scala
Expand Up @@ -32,6 +32,25 @@ case class ClassFile(
attributes: List[AttributeInfo],
)

object raw {

type ??? = Nothing

case class ClassFile(
minorVersion: Int,
majorVersion: Int,
constants: ConstantPool,
accessFlags: Set[ClassAccessFlag],
thisClass: ???,
superClass: ???,
interfaces: List[???],
fields: List[FieldInfo],
methods: List[MethodInfo],
attributes: List[AttributeInfo],
)

}

final case class ConstantPool private (private val constants: Array[Constant | Null])
extends AnyVal {
// ConstantIndex is 1-based, so we subtract 1
Expand Down
23 changes: 23 additions & 0 deletions demo/index.html
@@ -0,0 +1,23 @@
<html>
<body>
<h1>Classfile analyzer v0.0.0.0.0.1</h1>
<h2>Pls upload classfile</h2>
<input type="file" id="file_input" accept=".class" />
<div id="output"></div>
</body>
<script
type="text/javascript"
src=".js/target/scala-3.2.1/demo-fastopt.js"
></script>
<style>
*,
*:before,
*:after {
box-sizing: border-box;
}
td {
border: 1px solid black;
padding: 10px;
}
</style>
</html>
100 changes: 100 additions & 0 deletions demo/src/main/scala/org/polyvariant/classfile/demo/DemoMain.scala
@@ -0,0 +1,100 @@
package org.polyvariant.classfile.demo

import org.scalajs.dom._
import org.scalajs.dom.HTMLInputElement
import scala.scalajs.js.typedarray.Uint8Array
import scalatags.JsDom.all._
import scodec.bits.ByteVector
import org.polyvariant.classfile.codecs.ClassFileCodecs
import org.polyvariant.classfile.examples.ExampleCode
import org.polyvariant.classfile.examples.MethodModel
import scalatags.JsDom.TypedTag
import org.polyvariant.classfile.examples.AttributeModel

object DemoMain {

val fileInput = document.getElementById("file_input").asInstanceOf[HTMLInputElement]

val output = document.getElementById("output")

def renderMethod(method: MethodModel): TypedTag[Element] = tr(
td(method.name),
td(method.descriptor),
td(
table(
tbody(
method.attributes.map { attr =>
val extras =
attr match {
case c: AttributeModel.Code =>
List(
td("max stack: " + c.maxStack),
td("max locals: " + c.maxLocals),
td("instruction count: " + c.code.length),
td("exception table count: " + c.exceptionTable.length),
td("attriute count: " + c.attributes.length),
)
case _ => td("attribute unknown") :: Nil
}

tr(
td(attr.attrName),
extras,
)
}
)
)
),
)

def handleBytes(
bytes: Array[Byte]
): Unit = {
while (output.firstChild != null)
output.removeChild(output.firstChild)

output.appendChild(p(s"Loaded ", b(bytes.length), " bytes").render)

val bits = ByteVector(bytes).bits

val decoded =
ClassFileCodecs
.classFile
.decode(bits)
.map(_.value)
.map(ExampleCode.decode)
.toTry
.get

output.appendChild(
div(
p("Loaded class: " + decoded.thisClass),
p("Superclass: " + decoded.superClass),
p("Methods:"),
table(
thead(
tr(
th("name"),
th("descriptor"),
th("attributes"),
)
),
tbody(
decoded.methods.map(renderMethod)
),
),
p("toString: "),
pre(code(pprint(decoded).plainText)),
).render
)
}

def main(args: Array[String]): Unit =
fileInput.onchange = { _ =>
val file = fileInput.files.item(0)
file
.arrayBuffer()
.`then`(bytes => handleBytes(new Uint8Array(bytes).toArray.map(_.toByte)))
}

}

0 comments on commit 21ded9b

Please sign in to comment.