/* * This file is part of the L2J Mobius project. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.l2jmobius.xml; import java.io.File; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; import java.util.Map; import com.l2jmobius.L2ClientDat; import com.l2jmobius.clientcryptor.crypt.DatCrypter; import com.l2jmobius.config.ConfigDebug; import com.l2jmobius.data.GameDataName; import com.l2jmobius.util.ByteReader; import com.l2jmobius.util.DebugUtil; public class DescriptorReader { private static DescriptorReader _instance = new DescriptorReader(); final String eq = "="; final String tab = "\t"; final String nl = System.getProperty("line.separator"); final String semi = ";"; final String lb = "["; final String rb = "]"; public static DescriptorReader getInstance() { return _instance; } public String parseData(File currentFile, DatCrypter crypter, Descriptor desc, ByteBuffer data) throws Exception { String stringData; if (desc.isRawData()) { StringBuilder builder = new StringBuilder(); readVariables(currentFile, crypter, desc.getNodes().get(0), new HashMap(), data, builder, true); stringData = builder.toString(); } else { stringData = this.parseData(currentFile, crypter, data, null, desc.getNodes(), 1, new HashMap(), false, 0).trim(); } if (desc.getFormat() != null) { stringData = desc.getFormat().decode(stringData); } int pos = desc.isSafePackage() ? data.position() + 13 : data.position(); if (data.limit() > pos) { L2ClientDat.addLogConsole("Unpacked not full " + data.position() + "/" + data.limit() + " diff: " + (data.limit() - pos), true); } return stringData; } private String parseData(File currentFile, DatCrypter crypter, ByteBuffer data, ParamNode lastNode, List nodes, int cycleSize, Map vars, boolean isNameHidden, int cycleNameLevel) throws Exception { if (cycleSize > 0) { StringBuilder out = new StringBuilder(); for (int i = 0; i < cycleSize; ++i) { boolean isAddCycleName = !isNameHidden && (lastNode != null) && lastNode.getEntityType().isCycle(); if (isAddCycleName) { for (int k = 0; k < cycleNameLevel; ++k) { out.append("\t"); } out.append(lastNode.getName().concat("_begin")); ++cycleNameLevel; } int nodeSize = nodes.size(); int nNode = 0; for (ParamNode n : nodes) { if (n.isIterator()) { continue; } ++nNode; } if (isNameHidden && (nNode > 1)) { out.append("{"); } for (int j = 0; j < nodeSize; ++j) { ParamNode node = nodes.get(j); if (node.getEntityType().isIf()) { Variant var = vars.get(node.getParamIf()); if ((var == null) || !var.toString().equalsIgnoreCase(node.getValIf())) { continue; } out.append(this.parseData(currentFile, crypter, data, null, node.getSubNodes(), 1, vars, isNameHidden, cycleNameLevel)); continue; } if (!(node.isIterator() || node.getEntityType().isConstant() || isNameHidden || (!node.getEntityType().isWrapper() && !node.isNameHidden()))) { out.append("\t").append(node.getName()).append("="); } if (node.getEntityType().isWrapper()) { out.append(this.parseData(currentFile, crypter, data, null, node.getSubNodes(), 1, vars, true, cycleNameLevel)); } else if (node.getEntityType().isCycle()) { int size; if (node.getSize() >= 0) { size = node.getSize(); } else { Variant var = vars.get(node.getCycleName()); if (var.isInt()) { size = var.getInt(); } else if (var.isShort()) { size = var.getShort(); } else { throw new Exception("Wrong cycle variable format for cycle: " + node.getName() + " iterator: " + node.getCycleName()); } } if (node.isNameHidden()) { out.append("{"); } out.append(this.parseData(currentFile, crypter, data, node, node.getSubNodes(), size, vars, node.isNameHidden(), cycleNameLevel)); if (node.isNameHidden()) { out.append("}"); } } else if (node.getEntityType().isConstant()) { out.append(node.getName().replace("\\t", "\t").replace("\\r\\n", "\r\n")); } else if (node.getEntityType().isVariable()) { readVariables(currentFile, crypter, node, vars, data, out, false); } if (!node.isIterator() && !node.getEntityType().isConstant() && isNameHidden && (j != (nodeSize - 1))) { out.append(";"); } if (!vars.containsKey(node.getName())) { continue; } DebugUtil.debugPos(data.position(), node.getName(), vars.get(node.getName())); } if (isNameHidden) { if (nNode > 1) { out.append("}"); } if (i < (cycleSize - 1)) { out.append(";"); } } if (!isAddCycleName) { continue; } if (out.charAt(out.length() - 1) != '\n') { out.append("\t"); } out.append(lastNode.getName()).append("_end\r\n"); --cycleNameLevel; } return out.toString(); } return ""; } private void readVariables(File currentFile, DatCrypter crypter, ParamNode node, Map vars, ByteBuffer data, StringBuilder out, boolean isRaw) throws Exception { switch (node.getType()) { case UCHAR: { short value = (byte) ByteReader.readChar(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, Short.class)); break; } case UBYTE: { int value = ByteReader.readUByte(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, Integer.class)); break; } case SHORT: { short value = ByteReader.readShort(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, Short.class)); break; } case USHORT: { int value = ByteReader.readShort(data) & 65535; if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, Integer.class)); break; } case UINT: { int value = ByteReader.readUInt(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, Integer.class)); break; } case INT: { int value = ByteReader.readInt(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, Integer.class)); break; } case CNTR: { int value = ByteReader.readCompactInt(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, Integer.class)); break; } case UNICODE: { String str = ByteReader.readUtfString(data, isRaw); if (isRaw) { out.append(str); break; } if (!node.isIterator()) { out.append("[").append(str).append("]"); } vars.put(node.getName(), new Variant(str, String.class)); break; } case ASCF: { String str = ByteReader.readString(data, isRaw); if (isRaw) { out.append(str); break; } if (!node.isIterator()) { out.append("[").append(str).append("]"); } vars.put(node.getName(), new Variant(str, String.class)); break; } case DOUBLE: { double value = ByteReader.readDouble(data); if (!node.isIterator()) { out.append(new BigDecimal(Double.toString(value)).toPlainString()); } vars.put(node.getName(), new Variant(value, Double.class)); break; } case FLOAT: { float value = ByteReader.readFloat(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(Float.valueOf(value), Float.class)); break; } case LONG: { long value = ByteReader.readLong(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, Long.class)); break; } case RGBA: { String value = ByteReader.readRGBA(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, String.class)); break; } case RGB: { String value = ByteReader.readRGB(data); if (!node.isIterator()) { out.append(value); } vars.put(node.getName(), new Variant(value, String.class)); break; } case HEX: { int value = ByteReader.readUByte(data); if (!node.isIterator()) { String hex = Integer.toHexString(value).toUpperCase(); if (hex.length() == 1) { hex = "0" + hex; } out.append(hex); } vars.put(node.getName(), new Variant(value, Integer.class)); break; } case MAP_INT: { int index = ByteReader.readUInt(data); if (ConfigDebug.DAT_REPLACEMENT_NAMES) { String paramName = GameDataName.getInstance().getString(currentFile, crypter, index); if (!node.isIterator()) { out.append(paramName); } vars.put(node.getName(), new Variant(paramName, String.class)); break; } if (!node.isIterator()) { out.append(index); } vars.put(node.getName(), new Variant(index, Integer.class)); break; } } } }