public class ACharacter {
    // Character label data.
    private String name;
    private String pid;
    private String sound;

    // Character stat data.
    private byte[] stats;
    private byte[] modifiers;
    private Skill[] skills;
    private short id;
    private byte level;

    // Character flags.
    private boolean male;
    private boolean promoted;
    private CharacterType characterType;

    // Class data.
    private Job characterClass;
    private Job[] reclasses;

    // Randomizer-only data.
    private String targetPid;
    private String linkedPid; // Used for Parent/child randomization.
    private transient boolean hasSwappedStats;

    public ACharacter() {}

    @Override
    public String toString() {
        boolean[] options = FatesGui.getInstance().getSelectedOptions();
        StringBuilder res = new StringBuilder();
        res.append("Name: ").append(name).append("\n");
        if(id != 0) {
            res.append("Stats: ").append(ByteUtils.toString(stats)).append("\n");
            res.append("Modifiers: ").append(ByteUtils.toString(modifiers)).append("\n");
        }
        if(options[0]) {
            res.append("Class: ").append(characterClass).append("\n");
            res.append("Reclasses: ").append(Arrays.toString(reclasses)).append("\n");
        }
        if(options[1]) {
            res.append("Skills: ").append(Arrays.toString(skills)).append("\n");
        }
        if(options[3]) {
            if(targetPid != null)
                res.append("Replacing: ").append(ACharacters.getInstance().getByPid(targetPid).getName()).append("\n");
            if(linkedPid != null)
                res.append("Parent/Child: ").append(ACharacters.getInstance().getByPid(linkedPid).getName()).append("\n");
            res.append("Level: ").append(level).append("\n");
        }
        return res.toString();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getSound() {
        return sound;
    }

    public void setSound(String sound) {
        this.sound = sound;
    }

    public byte[] getStats() {
        return stats;
    }

    public void setStats(byte[] stats) {
        this.stats = stats;
    }

    public byte[] getModifiers() {
        return modifiers;
    }

    public void setModifiers(byte[] modifiers) {
        this.modifiers = modifiers;
    }

    public Skill[] getSkills() {
        return skills;
    }

    public void setSkills(Skill[] skills) {
        this.skills = skills;
    }

    public boolean isMale() {
        return male;
    }

    public void setMale(boolean male) {
        this.male = male;
    }

    public boolean isPromoted() {
        return promoted;
    }

    public void setPromoted(boolean promoted) {
        this.promoted = promoted;
    }

    public short getId() {
        return id;
    }

    public void setId(short id) {
        this.id = id;
    }

    public byte getLevel() {
        return level;
    }

    public void setLevel(byte level) {
        this.level = level;
    }

    public Job getCharacterClass() {
        return characterClass;
    }

    public void setCharacterClass(Job characterClass) {
        this.characterClass = characterClass;
    }

    public Job[] getReclasses() {
        return reclasses;
    }

    public void setReclasses(Job[] reclasses) {
        this.reclasses = reclasses;
    }

    public String getTaglessPid() {
        return pid.substring(4);
    }

    public String getAid() {
        return pid.replace("PID_", "AID_");
    }

    public String getFid() {
        return pid.replace("PID_", "FID_");
    }

    public String getMPid() {
        return pid.replace("PID_", "MPID_");
    }

    public String getMPidH() {
        return pid.replace("PID_", "MPID_H_");
    }

    public CharacterType getCharacterType() {
        return characterType;
    }

    public void setCharacterType(CharacterType characterType) {
        this.characterType = characterType;
    }

    public String getTargetPid() {
        return targetPid;
    }

    public void setTargetPid(String targetPid) {
        this.targetPid = targetPid;
    }

    public String getLinkedPid() {
        return linkedPid;
    }

    public void setLinkedPid(String linkedPid) {
        this.linkedPid = linkedPid;
    }

    public boolean hasSwappedStats() {
        return hasSwappedStats;
    }

    public void setHasSwappedStats(boolean hasSwappedStats) {
        this.hasSwappedStats = hasSwappedStats;
    }

    public String getPidA() {
        return pid.replace("PID_", "PID_A_");
    }

    public String getPidB() {
        return pid.replace("PID_", "PID_B_");
    }

    public String getPidC() {
        return pid.replace("PID_", "PID_C_");
    }
} public class ACharacters {
    private static ACharacters instance;
    private List<ACharacter> characters;

    private ACharacters() {
        Type characterType = new TypeToken<List<ACharacter>>() {}.getType();
        try {
            Gson gson = new Gson();
            JsonReader reader = new JsonReader(new BufferedReader(new InputStreamReader(Randomizer.class
                    .getResourceAsStream("data/json/AwakeningCharacters.json"), "UTF-8")));
            characters = gson.fromJson(reader, characterType);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static ACharacters getInstance() {
        if (instance == null)
            instance = new ACharacters();
        return instance;
    }

    public List<ACharacter> getSelectedCharacters() {
        boolean[] selected = AGui.getInstance().getSelectedCharacters();
        List<ACharacter> selectedCharacters = new ArrayList<>();
        List<ACharacter> npcs = getCharactersByType(CharacterType.NPC);
        for(ACharacter c : characters) {
            if(c.getCharacterType() != CharacterType.NPC)
                selectedCharacters.add(c);
        }
        for(int x = 0; x < npcs.size(); x++) {
           if(selected[x]) {
               selectedCharacters.add(npcs.get(x));
           }
        }
        return selectedCharacters;
    }

    public List<ACharacter> getCharactersByType(CharacterType type) {
        List<ACharacter> ACharacters = new ArrayList<>();
        for(ACharacter c : characters) {
            if(c.getCharacterType() == type)
                ACharacters.add(c);
        }
        return ACharacters;
    }

    public ACharacter getByPid(String pid) {
        for(ACharacter c : characters) {
            if(c.getPid().equals(pid))
                return c;
        }
        return null;
    }

    public ACharacter getReplacement(List<ACharacter> characters, String pid) {
        for(ACharacter c : characters) {
            if(c.getTargetPid().equals(pid))
                return c;
        }
        return null;
    }

    public List<ACharacter> getCharacters() {
        return characters;
    }
} public class AItems {
    private static AItems instance;
    private List<FEItem> items;

    private AItems() {
        Type itemType = new TypeToken<List<FEItem>>() {}.getType();

        try {
            Gson gson = new Gson();
            JsonReader reader = new JsonReader(new BufferedReader(new InputStreamReader(Randomizer.class
                    .getResourceAsStream("data/json/AwakeningItems.json"), "UTF-8")));
            items = gson.fromJson(reader, itemType);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static AItems getInstance() {
        if (instance == null)
            instance = new AItems();
        return instance;
    }

    List<FEItem> getWeapons() {
        List<FEItem> weapons = new ArrayList<>();
        for(FEItem i : items) {
            if(i.getType() != ItemType.Treasure)
                weapons.add(i);
        }
        return weapons;
    }

    public List<FEItem> getSelectedItems(ItemType type) {
        List<FEItem> selected = new ArrayList<>();
        List<FEItem> weapons = getWeapons();
        boolean[] selectedItems = AGui.getInstance().getSelectedItems();
        for(int x = 0; x < weapons.size(); x++) {
            if(weapons.get(x).getType() == type && selectedItems[x])
                selected.add(weapons.get(x));
        }
        return selected;
    }

    public FEItem generateEligibleItem(ItemType type, int maxLength) {
        List<FEItem> eligible = new ArrayList<>();
        try {
            for(FEItem i : getSelectedItems(type)) {
                if(i.getIid().getBytes("shift-jis").length <= maxLength)
                    eligible.add(i);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Random random = new Random();
        return eligible.get(random.nextInt(eligible.size()));
    }

    public FEItem generateItem(Job j) {
        Random random = new Random();
        List<FEItem> items = getSelectedItems(j.getItemType());
        return items.get(random.nextInt(items.size()));
    }

    public List<FEItem> getItems() {
        return items;
    }
} public class AJobs {
    private static AJobs instance;
    private List<Job> jobs;

    private AJobs() {
        Type jobType = new TypeToken<List<Job>>() {}.getType();
        try {
            Gson gson = new Gson();
            JsonReader reader = new JsonReader(new BufferedReader(new InputStreamReader(Randomizer.class
                    .getResourceAsStream("data/json/AwakeningClasses.json"), "UTF-8")));
            jobs = gson.fromJson(reader, jobType);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static AJobs getInstance() {
        if (instance == null)
            instance = new AJobs();
        return instance;
    }

    public List<Job> getMaleBaseClasses() {
        List<Job> current = new ArrayList<>();
        boolean[] selectedJobs = AGui.getInstance().getSelectedJobs();
        for(int x = 0; x < jobs.size(); x++) {
            Job j = jobs.get(x);
            if((j.getGender() == 0 || j.getGender() == 2) && j.getState() != JobState.Promoted && selectedJobs[x])
                current.add(j);
        }
        return current;
    }

    public List<Job> getFemaleBaseClasses() {
        List<Job> current = new ArrayList<>();
        boolean[] selectedJobs = AGui.getInstance().getSelectedJobs();
        for(int x = 0; x < jobs.size(); x++) {
            Job j = jobs.get(x);
            if((j.getGender() == 1 || j.getGender() == 2) && j.getState() != JobState.Promoted && selectedJobs[x])
                current.add(j);
        }
        return current;
    }

    public List<Job> getMalePromotedClasses() {
        List<Job> current = new ArrayList<>();
        boolean[] selectedJobs = AGui.getInstance().getSelectedJobs();
        for(int x = 0; x < jobs.size(); x++) {
            Job j = jobs.get(x);
            if((j.getGender() == 0 || j.getGender() == 2) && j.getState() != JobState.Base && selectedJobs[x])
                current.add(j);
        }
        return current;
    }

    public List<Job> getFemalePromotedClasses() {
        List<Job> current = new ArrayList<>();
        boolean[] selectedJobs = AGui.getInstance().getSelectedJobs();
        for(int x = 0; x < jobs.size(); x++) {
            Job j = jobs.get(x);
            if((j.getGender() == 1 || j.getGender() == 2) && j.getState() != JobState.Base && selectedJobs[x])
                current.add(j);
        }
        return current;
    }

    public List<Job> getEligibleJobs(boolean male, int maxLength) {
        List<Job> eligible = new ArrayList<>();
        List<Job> pool;
        if(male)
            pool = getMaleBaseClasses();
        else
            pool = getFemaleBaseClasses();
        try {
            for(Job j : pool) {
                if(j.getJid().getBytes("shift-jis").length <= maxLength && j.getItemType()
                        != ItemType.Staves && j.getItemType() != ItemType.Beaststone)
                    eligible.add(j);
            }
        } catch(UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return eligible;
    }
    
    public byte[] generateWeaponsRanks(Job j) {
        byte[] weaponRanks = new byte[5];
        if(j.getItemType() == ItemType.Swords) {
            weaponRanks[0] = (byte) WeaponRank.C.value();
        }
        else if(j.getItemType() == ItemType.Lances) {
            weaponRanks[1] = (byte) WeaponRank.C.value();
        }
        else if(j.getItemType() == ItemType.Axes) {
            weaponRanks[2] = (byte) WeaponRank.C.value();
        }
        else if(j.getItemType() == ItemType.Bows) {
            weaponRanks[3] = (byte) WeaponRank.C.value();
        }
        else if(j.getItemType() == ItemType.Tomes) {
            weaponRanks[4] = (byte) WeaponRank.C.value();
        }
        return weaponRanks;
    }

    public List<Job> getJobs() {
        return jobs;
    }
} public class ASkills {
    private static ASkills instance;

    private List<Skill> skills;

    private ASkills() {
        Type skillType = new TypeToken<List<Skill>>() {}.getType();
        try {
            Gson gson = new Gson();
            JsonReader reader = new JsonReader(new BufferedReader(new InputStreamReader(Randomizer.class
                    .getResourceAsStream("data/json/AwakeningSkills.json"), "UTF-8")));
            skills = gson.fromJson(reader, skillType);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static ASkills getInstance() {
        if (instance == null)
            instance = new ASkills();
        return instance;
    }

    public Skill getSkillById(int id) {
        for(Skill s : skills) {
            if(s.getId() == id)
                return s;
        }
        return null;
    }

    public List<Skill> getSelectedSkills() {
        boolean[] selected = AGui.getInstance().getSelectedSkills();
        List<Skill> selectedSkills = new ArrayList<>();
        for(int x = 0; x < skills.size(); x++) {
            if(skills.get(x).getType() == SkillType.Personal && !AGui.getInstance().getSelectedOptions()[10])
                continue;
            if(selected[x])
                selectedSkills.add(skills.get(x));
        }
        return selectedSkills;
    }

    public List<Skill> getSelectedPersonalSkills() {
        boolean[] selected = AGui.getInstance().getSelectedSkills();
        List<Skill> selectedSkills = new ArrayList<>();
        for(int x = 0; x < skills.size(); x++) {
            if(skills.get(x).getType() != SkillType.Personal)
                continue;
            if(selected[x])
                selectedSkills.add(skills.get(x));
        }
        return selectedSkills;
    }

    public List<Skill> getSkills() {
        return skills;
    }
} public enum CharacterType {
    FirstGen, SecondGen, NPC, Player
} public class FEItem {
    private String iid;
    private String name;
    private ItemType type;

    public FEItem() {

    }

    public String getIid() {
        return iid;
    }

    public void setIid(String iid) {
        this.iid = iid;
    }

    public ItemType getType() {
        return type;
    }

    public void setType(ItemType type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
} public class Job 
{
	private JobState state;
	private String jid;
	private String name;
	private ItemType itemType;
	private short tiedJob;
	private short id;
	private byte weaponRank;
	private byte gender;
	
	private Skill[] skills;
	
	public Job() {
		
	}
	
	@Override public String toString()
	{
		return name;
	}

	public JobState getState() {
		return state;
	}

	public void setState(JobState state) {
		this.state = state;
	}

	public String getJid() {
		return jid;
	}

	public void setJid(String jid) {
		this.jid = jid;
	}

	public short getId() {
		return id;
	}

	public void setId(short id) {
		this.id = id;
	}

	public byte getWeaponRank() {
		return weaponRank;
	}

	public void setWeaponRank(byte weaponRank) {
		this.weaponRank = weaponRank;
	}

	public Short getTiedJob() {
		return tiedJob;
	}

	public void setTiedJob(Short tiedJob) {
		this.tiedJob = tiedJob;
	}

	public ItemType getItemType() {
		return itemType;
	}

	public void setItemType(ItemType weaponType) {
		this.itemType = weaponType;
	}

	public int getGender() {
		return gender;
	}

	public void setGender(byte gender) {
		this.gender = gender;
	}

	public Skill[] getSkills() {
		return skills;
	}

	public void setSkills(Skill[] skills) {
		this.skills = skills;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
} public class Skill 
{
	private String seid;
	private String name;
	private SkillType type;
	private short id;
	
	public Skill() {
		
	}

	@Override
	public String toString()
	{
		return name;
	}
	
	public String getSeid() {
		return seid;
	}

	public void setSeid(String seid) {
		this.seid = seid;
	}

	public SkillType getType() {
		return type;
	}

	public void setType(SkillType type) {
		this.type = type;
	}

	public short getId() {
		return id;
	}

	public void setId(short id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
} public class CompressionUtils 
{
	public static byte[] decompress(File file)
	{	
		try 
		{
			int[] output = new int[0];
			HexInputStream hexStream;
			byte[] bytes = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
			if (bytes[0] == 0x13) 
			{
				byte[] tmp = new byte[bytes.length - 4];
				System.arraycopy(bytes, 4, tmp, 0, tmp.length);
				bytes = tmp;
			}
			hexStream = new HexInputStream(new ByteArrayInputStream(bytes));
			output = JavaDSDecmp.decompress(hexStream);
			bytes = new byte[output.length];
			for (int i = 0; i < output.length; i++) 
				bytes[i] = (byte) output[i];
			return bytes;
		} catch (IOException e) {
			e.printStackTrace();
			return new byte[0];
		}
	}
	
	public static byte[] compress(File file)
	{
		try {
			byte[] cmp = JavaDSDecmp.compressLZ11(Files.readAllBytes(Paths.get(file.getCanonicalPath())));
			byte[] cmp2 = new byte[cmp.length + 4];
			cmp2[0] = 0x13;
			System.arraycopy(cmp, 0, cmp2, 4, cmp.length);
			System.arraycopy(cmp, 1, cmp2, 1, 3);
			return cmp2;
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
			return new byte[0];
		}
	}
	
	public static byte[] compress(byte[] bytes)
	{
		byte[] cmp = JavaDSDecmp.compressLZ11(bytes);
		byte[] cmp2 = new byte[cmp.length + 4];
		cmp2[0] = 0x13;
		System.arraycopy(cmp, 0, cmp2, 4, cmp.length);
		System.arraycopy(cmp, 1, cmp2, 1, 3);
		return cmp2;
	}
} public class MessageBinUtils
{
    /**
     * Extracts the passed bytes as a Fire Emblem message archive and returns
     * their content as an array of Strings.
     *
     * @param archive the bytes to extract
     * @return the content of the passed bytes
     */
    public static String[] extractMessageArchive(byte[] archive) {
        return extractMessageArchive(null, archive, false);
    }

    /**
     * Extracts the passed bytes as a Fire Emblem message archive and returns
     * their content as an array of Strings. Saves the content in the given file.
     *
     * @param outname the file to which output should be written
     * @param archive the bytes to extract
     * @return the content of the passed bytes
     */
    public static String[] extractMessageArchive(String outname, byte[] archive) {
        return extractMessageArchive(outname, archive, true);
    }

    /**
     * Extracts the passed bytes as a Fire Emblem message archive and returns
     * their content as an array of Strings. Can save the content in the given
     * file.
     *
     * @param outname the file to which output should be written
     * @param archive the bytes to extract
     * @param save whether or not to save the output
     * @return the content of the passed bytes
     */
    public static String[] extractMessageArchive(String outname, byte[] archive,
                                                 boolean save) {
        if (archive.length < 0x20) {
            return null;
        }
        try {
            ArrayList<Byte> bytes = new ArrayList<>();
            for (int i = 0x20; i < archive.length; i++) {
                if (archive[i] == 0) {
                    break;
                } else {
                    bytes.add(archive[i]);
                }
            }
            byte[] string = new byte[bytes.size()];
            for (int i = 0; i < bytes.size(); i++) {
                string[i] = bytes.get(i);
            }
            String archiveName = new String(string, "Shift_JIS");
            int textPartitionLen = ByteUtils.toInt(archive, 4);
            int stringCount = ByteUtils.toInt(archive, 0xC);
            int stringMetaOffset = 0x20 + textPartitionLen;
            int namesOffset = stringMetaOffset + 0x8 * stringCount;
            if (archive.length < (0x20 + (long) textPartitionLen +
                    (0x8 * ((long) stringCount - 1)) + 4)) {
                return null;
            }
            String[] messageNames = new String[stringCount];
            String[] messages = new String[stringCount];
            for (int i = 0; i < stringCount; i++) {
                int messageOffset = 0x20 + ByteUtils.toInt(archive,
                        stringMetaOffset + 0x8 * i);
                int messageLen = 0;
                while (ByteUtils.toShort(archive, messageOffset + messageLen) != 0) {
                    messageLen += 2;
                }
                byte[] message = new byte[messageLen];
                System.arraycopy(archive, messageOffset + 0, message, 0, messageLen);
                try {
                    messages[i] = new String(message, "UTF-16LE").replace("\n","\\n")
                            .replace("\r","\\r");
                } catch (UnsupportedEncodingException ex) {
                    ex.printStackTrace();
                }
                int nameOffset = namesOffset + ByteUtils.toInt(archive,
                        stringMetaOffset + (0x8 * i) + 4);
                bytes.clear();
                for (int j = nameOffset; j < archive.length; j++) {
                    if (archive[j] == 0) {
                        break;
                    } else {
                        bytes.add(archive[j]);
                    }
                }
                string = new byte[bytes.size()];
                for (int j = 0; j < bytes.size(); j++) {
                    string[j] = bytes.get(j);
                }
                messageNames[i] = new String(string, "Shift_JIS");
            }
            ArrayList<String> lines = new ArrayList<>();
            lines.add(archiveName);
            lines.add(System.getProperty("line.separator"));
            lines.add("Message Name: Message");
            lines.add(System.getProperty("line.separator"));
            for (int i = 0; i < stringCount; i++) {
                lines.add(messageNames[i] + ": " + messages[i]);
            }
            if (save) {
                try {
                    Files.write(Paths.get(outname), lines);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            return lines.toArray(new String[lines.size()]);
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * Creates an array of bytes containing a Fire Emblem message archive with the
     * passed content.
     *
     * @param lines the content of the message archive
     * @return the byte data for the message archive
     */
    public static byte[] makeMessageArchive(String[] lines) {
        try {
            int stringCount = lines.length - 6;
            String[] messages = new String[stringCount];
            String[] names = new String[stringCount];
            int[] mPos = new int[stringCount];
            int[] nPos = new int[stringCount];
            for (int i = 6; i < lines.length; i++) {
                int ind = lines[i].indexOf(": ");
                names[i - 6] = lines[i].substring(0, ind);
                messages[i - 6] = lines[i].substring(ind + 2).replace("\\n", "\n")
                        .replace("\\r", "\r");
            }
            byte[] header = new byte[0x20];
            byte[] stringTable;
            byte[] metaTable = new byte[stringCount * 8];
            byte[] namesTable;
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                try (DataOutputStream dos = new DataOutputStream(baos)) {
                    byte[] bytes = lines[0].getBytes("Shift_JIS");
                    dos.write(bytes, 0, bytes.length);
                    dos.write((byte) 0);
                    while (baos.size() % 4 != 0) {
                        dos.write((byte) 0);
                    }
                    for (int i = 0; i < stringCount; i++) {
                        mPos[i] = baos.size();
                        bytes = messages[i].getBytes("UTF-16LE");
                        dos.write(bytes, 0, bytes.length);
                        dos.write((byte) 0);
                        dos.write((byte) 0);
                        while (baos.size() % 4 != 0) {
                            dos.write((byte) 0);
                        }
                    }
                    stringTable = baos.toByteArray();
                }
            }
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                try (DataOutputStream dos = new DataOutputStream(baos)) {
                    for (int i = 0; i < stringCount; i++) {
                        nPos[i] = baos.size();
                        byte[] bytes = names[i].getBytes("Shift_JIS");
                        dos.write(bytes, 0, bytes.length);
                        dos.write((byte) 0);
                    }
                    namesTable = baos.toByteArray();
                }
            }
            for (int i = 0; i < stringCount; i++) {
                System.arraycopy(DecUtils.getBytes(mPos[i]), 0, metaTable, (i * 8), 4);
                System.arraycopy(DecUtils.getBytes(nPos[i]), 0, metaTable, (i * 8) + 4,
                        4);
            }
            byte[] archive = new byte[header.length + stringTable.length +
                    metaTable.length + namesTable.length];
            System.arraycopy(DecUtils.getBytes(archive.length), 0, header, 0, 4);
            System.arraycopy(DecUtils.getBytes(stringTable.length), 0, header, 4, 4);
            System.arraycopy(DecUtils.getBytes(stringCount), 0, header, 0xC, 4);
            System.arraycopy(header, 0, archive, 0, header.length);
            System.arraycopy(stringTable, 0, archive, header.length,
                    stringTable.length);
            System.arraycopy(metaTable, 0, archive, header.length +
                    stringTable.length, metaTable.length);
            System.arraycopy(namesTable, 0, archive, header.length +
                            stringTable.length + metaTable.length,
                    namesTable.length);
            return archive;
        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        }
    }
}
import randomizer.awakening.model.structures.ACharacter;
import randomizer.awakening.singletons.ACharacters;
import randomizer.awakening.singletons.AItems;
import randomizer.awakening.singletons.AJobs;
import randomizer.awakening.singletons.ASkills;
import randomizer.common.enums.CharacterType;
import randomizer.common.structures.FEItem;
import randomizer.common.structures.Job;
import randomizer.common.structures.Skill;
import randomizer.common.utils.CompressionUtils;
import randomizer.common.utils.MessageBinUtils;
import java.io.File;
import java.util.HashMap;
package randomizer.awakening.model.processors.prep;



public class NameMatcher {
    /**
     * Opens up the given GameData text file and assigns characters,
     * skills, items, and classes the correct names for the current
     * region by matching IDs with text.
     *
     * @param file A compressed GameData text file.
     */
    public static void matchNames(File file) {
        String[] lines = MessageBinUtils.extractMessageArchive(CompressionUtils.decompress(file));
        HashMap<String, String> map = new HashMap<>();
        for(int x = 6; x < lines.length; x++) {
            String[] split = lines[x].split(": ");
            if(split.length > 1) {
                map.put(split[0], split[1]);
            }
        }

        // Use the map to assign names.
        for(ACharacter c : ACharacters.getInstance().getCharacters()) {