blob: b6e12d76a81ed045fc6d1d0ba6376db74b39e158 [file] [log] [blame] [raw]
package li.cil.oc.server.component
import java.util.zip.DeflaterOutputStream
import java.util.zip.InflaterOutputStream
import com.google.common.hash.Hashing
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.Network
import li.cil.oc.api.machine.Arguments
import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context
import li.cil.oc.api.network.Node
import li.cil.oc.api.network.Visibility
import li.cil.oc.api.prefab
import li.cil.oc.util.ExtendedNBT._
import net.minecraft.nbt.NBTTagCompound
import org.apache.commons.codec.binary.Base64
import org.apache.commons.io.output.ByteArrayOutputStream
class DataCard extends prefab.ManagedEnvironment {
override val node = Network.newNode(this, Visibility.Neighbors).
withComponent("data", Visibility.Neighbors).
withConnector().
create()
val romData = Option(api.FileSystem.asManagedEnvironment(api.FileSystem.
fromClass(OpenComputers.getClass, Settings.resourceDomain, "lua/component/data"), "data"))
@Callback(direct = true, doc = """function():number -- The maximum size of data that can be passed to other functions of the card.""")
def getLimit(context: Context, args: Arguments): Array[AnyRef] = {
result(Settings.get.dataCardHardLimit)
}
@Callback(direct = true, limit = 32, doc = """function(data:string):string -- Applies base64 encoding to the data.""")
def encode64(context: Context, args: Arguments): Array[AnyRef] = {
result(Base64.encodeBase64(checkLimits(context, args, Settings.get.dataCardComplex)))
}
@Callback(direct = true, limit = 32, doc = """function(data:string):string -- Applies base64 decoding to the data.""")
def decode64(context: Context, args: Arguments): Array[AnyRef] = {
result(Base64.decodeBase64(checkLimits(context, args, Settings.get.dataCardComplex)))
}
@Callback(direct = true, limit = 6, doc = """function(data:string):string -- Applies deflate compression to the data.""")
def deflate(context: Context, args: Arguments): Array[AnyRef] = {
val data = checkLimits(context, args, Settings.get.dataCardComplex)
val baos = new ByteArrayOutputStream(512)
val deos = new DeflaterOutputStream(baos)
deos.write(data)
deos.finish()
result(baos.toByteArray)
}
@Callback(direct = true, limit = 6, doc = """function(data:string):string -- Applies inflate decompression to the data.""")
def inflate(context: Context, args: Arguments): Array[AnyRef] = {
val data = checkLimits(context, args, Settings.get.dataCardComplex)
val baos = new ByteArrayOutputStream(512)
val inos = new InflaterOutputStream(baos)
inos.write(data)
inos.finish()
result(baos.toByteArray)
}
@Callback(direct = true, limit = 32, doc = """function(data:string):string -- Computes SHA2-256 hash of the data. Result is in binary format.""")
def sha256(context: Context, args: Arguments): Array[AnyRef] = {
val data = checkLimits(context, args, Settings.get.dataCardSimple)
result(Hashing.sha256().hashBytes(data).asBytes())
}
@Callback(direct = true, limit = 32, doc = """function(data:string):string -- Computes MD5 hash of the data. Result is in binary format""")
def md5(context: Context, args: Arguments): Array[AnyRef] = {
val data = checkLimits(context, args, Settings.get.dataCardSimple)
result(Hashing.md5().hashBytes(data).asBytes())
}
@Callback(direct = true, limit = 32, doc = """function(data:string):string -- Computes CRC-32 hash of the data. Result is in binary format""")
def crc32(context: Context, args: Arguments): Array[AnyRef] = {
val data = checkLimits(context, args, Settings.get.dataCardSimple)
result(Hashing.crc32().hashBytes(data).asBytes())
}
private def checkLimits(context: Context, args: Arguments, cost: Double): Array[Byte] = {
val data = args.checkByteArray(0)
if (data.length > Settings.get.dataCardHardLimit) throw new IllegalArgumentException("data size limit exceeded")
if (!node.tryChangeBuffer(-cost)) throw new Exception("not enough energy")
if (data.length > Settings.get.dataCardSoftLimit) context.pause(Settings.get.dataCardTimeout)
data
}
// ----------------------------------------------------------------------- //
override def onConnect(node: Node) {
super.onConnect(node)
if (node.isNeighborOf(this.node)) {
romData.foreach(fs => node.connect(fs.node))
}
}
override def onDisconnect(node: Node) {
super.onDisconnect(node)
if (node == this.node) {
romData.foreach(_.node.remove())
}
}
override def load(nbt: NBTTagCompound) {
super.load(nbt)
romData.foreach(_.load(nbt.getCompoundTag("romData")))
}
override def save(nbt: NBTTagCompound) {
super.save(nbt)
romData.foreach(fs => nbt.setNewCompoundTag("romData", fs.save))
}
}