All Downloads are FREE. Search and download functionalities are using the official Maven repository.

apparat.tools.stripper.Stripper.scala Maven / Gradle / Ivy

/*
 * This file is part of Apparat.
 *
 * Apparat is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Apparat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Apparat. If not, see .
 *
 * Copyright (C) 2009 Joa Ebert
 * http://www.joa-ebert.com/
 *
 */
package apparat.tools.stripper

import apparat.tools.{ApparatConfiguration, ApparatApplication, ApparatTool}
import java.io.{File => JFile}
import apparat.utils.TagContainer
import apparat.actors.Futures._
import apparat.abc._
import apparat.bytecode.operations._
import apparat.bytecode.combinator._
import apparat.bytecode.combinator.BytecodeChains._
import apparat.swf._

/**
 * @author Joa Ebert
 */
object Stripper {
	def main(args: Array[String]): Unit = ApparatApplication(new StripperTool, args)

	class StripperTool extends ApparatTool
	{
		/**
		 * The namespace of the trace() method.
		 */
		private lazy val qname = AbcQName('trace, AbcNamespace(AbcNamespaceKind.Package, Symbol("")))

		/**
		 * Rewrite rule that converts CallProperty into CallPropVoid.
		 *
		 * CallProperty(trace, N) Pop() => CallPropVoid(trace, N)
		 */
		private lazy val traceVoid = {
			partial { case CallProperty(name, args) if name == qname => args } ~ Pop() ^^ {
				case args ~ Pop() => CallPropVoid(qname, args) :: Nil
				case _ => error("Internal error.")
			}
		}

		/**
		 * Rewrite rule that will replace "trace(x, y)" with "x, y"
		 * on a bytecode level.
		 *
		 * FindPropStrict(trace) AnyOp* CallPropVoid(trace,N) => AnyOp* repeat(Pop(), N)
		 */
		private lazy val trace = {
			(FindPropStrict(qname) ~
				(filter {
					case CallPropVoid(name, args) if name == qname => false
					case _ => true
				}*) ~
				partial {
					case CallPropVoid(name, args) if name == qname => CallPropVoid(name, args)
				}
			) ^^ {
				case findProp ~ ops ~ callProp if ops.length == callProp.numArguments => {
					ops ::: (List.fill(callProp.numArguments) { Pop() })
				}
				case findProp ~ ops ~ callProp => findProp :: ops ::: List(callProp)
				case _ => error("Internal error.")
			}
		}

		var input: JFile = _
		var output: JFile = _
		
		override def name = "Stripper"

		override def help = """  -i [file]	Input file
  -o [file]	Output file (optional)"""

		override def configure(config: ApparatConfiguration): Unit = configure(StripperConfigurationFactory fromConfiguration config)

		def configure(config: StripperConfiguration): Unit = {
			input = config.input
			output = config.output
		}

		override def run() = {
			SwfTags.tagFactory = (kind: Int) => kind match {
				case SwfTags.DoABC => Some(new DoABC)
				case SwfTags.DoABC1 => Some(new DoABC)
				case _ => None
			}

			val cont = TagContainer fromFile input
			cont foreachTag strip
			cont write output
		}

		private def strip: PartialFunction[SwfTag, Unit] = {
			case doABC: DoABC => {
				val abc = Abc fromDoABC doABC

				abc.loadBytecode()

				for {
					method <- abc.methods
					body <- method.body
					bytecode <- body.bytecode
				} {
					//
					// Strip all debug information.
					//

					bytecode removeAll {
						_.opCode match {
							case Op.debug | Op.debugfile | Op.debugline => true
							case _ => false
						}
					}

					//
					// Strip all traces.
					//

					bytecode rewrite traceVoid
					bytecode rewrite trace
				}

				abc.saveBytecode()
				abc write doABC
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy