l2j_mobius/L2ClientDat/java/com/l2jmobius/data/GameDataName.java
2018-05-13 21:57:11 +00:00

238 lines
6.9 KiB
Java

/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.data;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.l2jmobius.L2ClientDat;
import com.l2jmobius.clientcryptor.DatFile;
import com.l2jmobius.clientcryptor.crypt.DatCrypter;
import com.l2jmobius.config.ConfigDebug;
import com.l2jmobius.util.ByteReader;
import com.l2jmobius.util.ByteWriter;
import com.l2jmobius.util.Util;
import com.l2jmobius.xml.ParamNode;
public class GameDataName
{
private static final byte[] endFileBytes = new byte[]
{
12,
83,
97,
102,
101,
80,
97,
99,
107,
97,
103,
101,
0
};
private final Map<Integer, String> names = new HashMap<>();
private final Map<String, Integer> nameHash = new HashMap<>();
private final Map<String, Integer> nameLowHash = new HashMap<>();
private void load(File currentFile, DatCrypter decCrypter) throws Exception
{
names.clear();
nameHash.clear();
nameLowHash.clear();
if (decCrypter.isEncrypt())
{
File file = new File(currentFile.getParent(), "L2GameDataName.txt");
if (file.exists())
{
List<String> list = Files.readAllLines(file.toPath());
for (int i = 0; i < list.size(); ++i)
{
String str = list.get(i);
Map<String, String> map = Util.stringToMap(str);
String name = map.get("name");
name = name.substring(1, name.length() - 1);
names.put(i, name);
nameHash.put(name, i);
nameLowHash.put(name.toLowerCase(), i);
}
L2ClientDat.addLogConsole("GameDataName: Load " + names.size() + " count.", true);
}
}
else
{
File file = new File(currentFile.getParent(), "L2GameDataName.dat");
FileInputStream fis = new FileInputStream(file);
if (fis.available() < 28)
{
L2ClientDat.addLogConsole(file.getName() + " The file is too small.", true);
fis.close();
return;
}
byte[] head = new byte[28];
fis.read(head);
fis.close();
String header = new String(head, "UTF-16LE");
if (!header.startsWith("Lineage2Ver"))
{
L2ClientDat.addLogConsole("GameDataName: File " + file.getName() + " not encrypted. Skip decrypt.", true);
return;
}
if (Integer.valueOf(header.substring(11)).intValue() != decCrypter.getCode())
{
L2ClientDat.addLogConsole("GameDataName: File " + file.getName() + " encrypted code: " + header + ". Skip decrypt.", true);
return;
}
L2ClientDat.addLogConsole("Unpacking [" + file.getName() + "]", true);
DatFile dat = new DatFile(file.getAbsolutePath());
dat.decrypt(decCrypter);
ByteBuffer buff = dat.getBuff();
int size = ByteReader.readUInt(buff);
for (int i = 0; i < size; ++i)
{
String name = ByteReader.readUtfString(buff, false);
if (name.contains("[") || name.contains("]"))
{
L2ClientDat.addLogConsole("GameDataName: Error index: " + i + " string: " + name, true);
}
names.put(i, name);
nameHash.put(name, i);
nameLowHash.put(name.toLowerCase(), i);
}
L2ClientDat.addLogConsole("GameDataName: Load " + names.size() + " count.", true);
}
}
public String getString(File currentFile, DatCrypter crypter, int index) throws Exception
{
String val;
if (names.isEmpty())
{
load(currentFile, crypter);
}
if (!names.containsKey(index))
{
L2ClientDat.addLogConsole("GameDataName: Not found index: " + index, true);
}
if ((val = names.getOrDefault(index, String.valueOf(index))).isEmpty())
{
L2ClientDat.addLogConsole("GameDataName: String name Empty!!! file: " + currentFile.getName(), true);
}
return "[" + val + "]";
}
public synchronized int getId(File currentFile, DatCrypter crypter, ParamNode node, String str) throws Exception
{
String low;
if (!str.startsWith("[") || !str.endsWith("]"))
{
L2ClientDat.addLogConsole("GameDataName: String name not brackets!!! file: " + currentFile.getName() + " str: " + str + " node: " + node, true);
}
if ((str = str.substring(1, str.length() - 1)).isEmpty())
{
L2ClientDat.addLogConsole("GameDataName: String name Empty!!! file: " + currentFile.getName() + " node: " + node, true);
return -1;
}
if (nameLowHash.isEmpty())
{
load(currentFile, crypter);
}
if (nameLowHash.containsKey(low = str.toLowerCase()))
{
return nameLowHash.get(low);
}
int newIndex = nameLowHash.size();
nameLowHash.put(low, newIndex);
nameHash.put(str, nameHash.size());
return newIndex;
}
public void checkAndUpdate(String currentDir, DatCrypter crypter) throws Exception
{
if (!nameHash.isEmpty())
{
HashSet<String> setList = new HashSet<>();
TreeMap<Integer, String> sortedMap = new TreeMap<>();
for (String key : nameHash.keySet())
{
sortedMap.put(nameHash.get(key), key);
if (setList.add(key.toLowerCase()))
{
continue;
}
L2ClientDat.addLogConsole("GameDataName: name " + key + " conflicted.", true);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write((byte[]) ByteWriter.writeInt(sortedMap.size()).array());
for (String key : sortedMap.values())
{
baos.write((byte[]) ByteWriter.writeUtfString(key, false).array());
}
byte[] bytes = baos.toByteArray();
byte[] resultBytes = new byte[bytes.length + endFileBytes.length];
System.arraycopy(bytes, 0, resultBytes, 0, bytes.length);
System.arraycopy(endFileBytes, 0, resultBytes, bytes.length, endFileBytes.length);
String file = currentDir + "/L2GameDataName.dat";
if (ConfigDebug.ENCRYPT)
{
DatFile.encrypt(resultBytes, file, crypter);
}
else
{
FileOutputStream os = new FileOutputStream(file, false);
os.write(resultBytes);
os.close();
}
L2ClientDat.addLogConsole("GameDataName: packed " + sortedMap.size() + " count.", true);
names.clear();
nameHash.clear();
nameLowHash.clear();
}
}
public void clear()
{
names.clear();
nameHash.clear();
nameLowHash.clear();
}
public static GameDataName getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
static final GameDataName _instance = new GameDataName();
private SingletonHolder()
{
}
}
}