/* BSD 2-Clause License - see OPAL/LICENSE for details. */ package org.opalj package da import scala.io.Source import scala.xml.Node import scala.xml.NodeSeq import scala.xml.Text import scala.xml.Unparsed import org.opalj.io.process import org.opalj.bi.AccessFlags import org.opalj.bi.reader.Constant_PoolAbstractions import org.opalj.bi.ACC_PUBLIC import org.opalj.bi.ACC_SUPER /** * @author Michael Eichberg * @author Wael Alkhatib * @author Isbel Isbel * @author Noorulla Sharief * @author Andre Pacak */ case class ClassFile( constant_pool: Constant_Pool, minor_version: Int, major_version: Int, access_flags: Int = ACC_PUBLIC.mask | ACC_SUPER.mask, this_class: Constant_Pool_Index, super_class: Constant_Pool_Index, interfaces: Interfaces = NoInterfaces, fields: Fields = NoFields, methods: Methods = NoMethods, attributes: Attributes = NoAttributes ) { assert({ val cp0 = constant_pool(0) (cp0 eq null) || cp0.isInstanceOf[Constant_PoolAbstractions#DeferredActionsStore] }) /** * Size of the class file in bytes. */ def size: Int = { 4 + // magic 2 + // minor_version 2 + // major_version 2 + // constant_pool_count { val cpIt = constant_pool.iterator cpIt.next() // the first entry is always empty in the class file cpIt. filter(_ ne null /*handles the case of Constant_Long and Constant_Double*/ ). map(_.size). sum } + 2 + // access_flags 2 + // this_class 2 + // super_class 2 + // interfaces count interfaces.length * 2 + // interfaces[interfaces_count] 2 + // fields_count fields.view.map(_.size).sum + 2 + // methods_count methods.view.map(_.size).sum + 2 + // attributes_count attributes.view.map(_.size).sum } def jdkVersion: String = org.opalj.bi.jdkVersion(major_version) private[this] implicit val cp = constant_pool /** * The fully qualified name of this class in Java notation (i.e., using dots * to seperate packages.) */ final val thisType: ObjectTypeInfo = cp(this_class).asConstantClass.asJavaClassOrInterfaceType final val superTypes = { { if (super_class != 0) Seq( Text("extends "), asJavaObjectType(cp(super_class).toString).asSpan("extends"), Text(" ") ) else NodeSeq.Empty } ++ { if (interfaces.nonEmpty) Seq( Text("implements "), asJavaObjectType(cp(interfaces.head).toString).asSpan("implements"), interfaces.tail.map { i => Seq(Text(", "), asJavaObjectType(cp(i).toString).asSpan("implements")) } ) else NodeSeq.Empty } } /** * Converts the constant pool to (x)HTML5. */ def cpToXHTML: Node = { val cpEntries = for { cpIndex <- 1 until constant_pool.length cpNode = cp(cpIndex) if cpNode != null /* <= need for constant_double/_long entries */ } yield {
  • { cpNode.asCPNode }
  • }
      { cpEntries }
    } def attributeToXHTML(attribute: Attribute): Node = { attribute match { case ica: InnerClasses_attribute => ica.toXHTML(thisType) case _ => attribute.toXHTML(cp) } } def fieldsToXHTML: Iterator[Node] = fields.iterator.map { field => field.toXHTML } def methodsToXHTML: Iterator[Node] = { methods.iterator.zipWithIndex.map { mi => val (method, index) = mi; method.toXHTML(index) } } protected def accessFlags: Node = { { AccessFlags.classFlagsToJava(access_flags) } } protected def filter: Node = {
    Filter
    } /** * Creates an XHTML representation of the ClassFile. * * @param embeddedCSS A string which contains a CSS. * @param cssFile Reference to a(nother) CSS file. * @param jsFile Reference to a JavaScript file. * @return The generatd HTML. */ def toXHTML( source: Option[AnyRef], embeddedCSS: Option[String] = Some(ClassFile.TheCSS), cssFile: Option[String] = None, jsFile: Option[String] = None, withMethodsFilter: Boolean = true ): Node = Java Bytecode of { thisType.asJava } { if (embeddedCSS.isDefined) } { if (cssFile.isDefined) }{ if (withMethodsFilter) } { if (jsFile.isDefined) } { classFileToXHTML(source, withMethodsFilter) } def classFileToXHTML(source: Option[AnyRef]): Node = classFileToXHTML(source, false) // this file is private to ensure that no meaningless html files are generated // (i.e. with the fields for the filter, but without the necessary logic) private[this] def classFileToXHTML(source: Option[AnyRef], withMethodsFilter: Boolean): Node = { val (sourceFileAttributes, attributes0) = partitionByType(attributes, classOf[SourceFile_attribute]) val (signatureAttributes, attributes1) = partitionByType(attributes0, classOf[Signature_attribute])
    { if (source.isDefined)
    { source.get }
    }
    { accessFlags } { thisType.asJava } { superTypes } { if (signatureAttributes.nonEmpty) { Seq(
    , signatureAttributes.head.signatureSpan) } }
    { sourceFileAttributes.headOption.map { a => Seq( Text("Source file: "), { a.sourceFile } , Unparsed("  —  ") ) }.getOrElse(NodeSeq.Empty) } Version: { s"$major_version.$minor_version ($jdkVersion)" }   —   Size: { size }bytes
    Constant Pool { cpToXHTML }
    { if (attributes1.nonEmpty)
    Attributes { attributes1.map[Node](attributeToXHTML) }
    }{ if (fields.nonEmpty) {
    Fields{ fieldsToXHTML }
    } } { if (methods.nonEmpty) {
    Methods { if (withMethodsFilter) filter else NodeSeq.Empty } { methodsToXHTML }
    } }
    } } object ClassFile { private def loadResource(js: String): String = { process(this.getClass.getResourceAsStream(js))(Source.fromInputStream(_).mkString) } final val ResetCSS: String = loadResource("reset.css") final val TheCSS: String = loadResource("style.css") final val FilterJS: String = loadResource("filter.js") }