// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.search; import java.awt.Component; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.infinity.datatype.ProRef; import org.infinity.datatype.ResourceRef; import org.infinity.datatype.TextString; import org.infinity.resource.AbstractStruct; import org.infinity.resource.Resource; import org.infinity.resource.ResourceFactory; import org.infinity.resource.StructEntry; import org.infinity.resource.bcs.BcsResource; import org.infinity.resource.bcs.Compiler; import org.infinity.resource.bcs.Decompiler; import org.infinity.resource.dlg.AbstractCode; import org.infinity.resource.dlg.Action; import org.infinity.resource.dlg.DlgResource; import org.infinity.resource.graphics.BamResource; import org.infinity.resource.graphics.MosResource; import org.infinity.resource.graphics.TisResource; import org.infinity.resource.key.ResourceEntry; import org.infinity.resource.other.EffResource; import org.infinity.resource.sav.SavResource; import org.infinity.resource.text.PlainTextResource; public final class ReferenceSearcher extends AbstractReferenceSearcher { public ReferenceSearcher(ResourceEntry targetEntry, Component parent) { super(targetEntry, AbstractReferenceSearcher.FILE_TYPES, parent); } public ReferenceSearcher(ResourceEntry targetEntry, String[] fileTypes, Component parent) { super(targetEntry, fileTypes, parent); } public ReferenceSearcher(ResourceEntry targetEntry, String[] fileTypes, boolean[] preselect, Component parent) { super(targetEntry, fileTypes, preselect, parent); } @Override protected void search(ResourceEntry entry, Resource resource) { if (resource instanceof DlgResource) { searchDialog(entry, (AbstractStruct)resource); } else if (resource instanceof SavResource) { searchSave(entry, (SavResource)resource); } else if (resource instanceof BamResource) { searchBam(entry, (BamResource)resource); } else if (resource instanceof MosResource) { searchMos(entry, (MosResource)resource); } else if (resource instanceof TisResource) { searchTis(entry, (TisResource)resource); } else if (resource instanceof PlainTextResource) { searchText(entry, (PlainTextResource)resource); } else if (resource instanceof AbstractStruct) { searchStruct(entry, (AbstractStruct)resource); } else if (resource instanceof BcsResource) { searchScript(entry, (BcsResource)resource); } } private void searchDialog(ResourceEntry entry, AbstractStruct dialog) { boolean hit = false; for (int i = 0; i < dialog.getFieldCount(); i++) { StructEntry o = dialog.getField(i); if (o instanceof ResourceRef && ((ResourceRef)o).getResourceName().equalsIgnoreCase(targetEntry.toString())) { addHit(entry, entry.getSearchString(), o); } else if (o instanceof AbstractCode) { AbstractCode sourceCode = (AbstractCode)o; try { Compiler compiler = new Compiler(sourceCode.toString(), (sourceCode instanceof Action) ? Compiler.ScriptType.ACTION : Compiler.ScriptType.TRIGGER); String code = compiler.getCode(); if (compiler.getErrors().size() == 0) { Decompiler decompiler = new Decompiler(code, true); if (o instanceof Action) { decompiler.setScriptType(Decompiler.ScriptType.ACTION); } else { decompiler.setScriptType(Decompiler.ScriptType.TRIGGER); } decompiler.decompile(); for (final ResourceEntry resourceUsed : decompiler.getResourcesUsed()) { if (targetEntry.toString().equalsIgnoreCase(resourceUsed.toString())) { hit = true; addHit(entry, entry.getSearchString(), sourceCode); } else if (targetEntry == resourceUsed) { // searching for symbolic spell names String s = org.infinity.resource.spl.Viewer.getSymbolicName(targetEntry, false); if (s != null && s.equalsIgnoreCase(resourceUsed.toString())) { addHit(entry, s, sourceCode); } } } if (!hit && targetEntryName != null) { Pattern p = Pattern.compile("\\b" + targetEntryName + "\\b", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher(code); if (m.find()) { addHit(entry, targetEntryName, sourceCode); } } } } catch (Exception e) { System.out.println("Exception in " + dialog.getName() + " - " + sourceCode.getName()); e.printStackTrace(); } } else if (o instanceof AbstractStruct) searchDialog(entry, (AbstractStruct)o); } } private void searchSavStruct(ResourceEntry entry, ResourceEntry saventry, AbstractStruct struct) { for (int i = 0; i < struct.getFieldCount(); i++) { StructEntry o = struct.getField(i); if (o instanceof ResourceRef && ((ResourceRef)o).getResourceName().equalsIgnoreCase(targetEntry.toString())) addHit(entry, saventry.toString(), o); else if (o instanceof AbstractStruct) searchSavStruct(entry, saventry, (AbstractStruct)o); } } private void searchSave(ResourceEntry entry, SavResource savfile) { List<? extends ResourceEntry> entries = savfile.getFileHandler().getFileEntries(); for (int i = 0; i < entries.size(); i++) { ResourceEntry saventry = entries.get(i); Resource resource = ResourceFactory.getResource(saventry); if (resource instanceof AbstractStruct) searchSavStruct(entry, saventry, (AbstractStruct)resource); } } private void searchScript(ResourceEntry entry, BcsResource bcsfile) { boolean hit = false; Decompiler decompiler = new Decompiler(bcsfile.getCode(), true); String code = decompiler.decompile(); if (decompiler.getResourcesUsed().contains(targetEntry)) { hit = true; addHit(entry, entry.getSearchString(), null); } if (!hit && targetEntryName != null) { Pattern p = Pattern.compile("\\b" + targetEntryName + "\\b", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher(code); if (m.find()) { addHit(entry, targetEntryName, null); } } } private void searchStruct(ResourceEntry entry, AbstractStruct struct) { for (int i = 0; i < struct.getFieldCount(); i++) { StructEntry o = struct.getField(i); if (o instanceof ResourceRef && ((ResourceRef)o).getResourceName().equalsIgnoreCase(targetEntry.toString())) { addHit(entry, entry.getSearchString(), o); } else if (o instanceof ProRef && ((ProRef)o).getSelectedEntry() == targetEntry) { addHit(entry, entry.getSearchString(), o); } else if (o instanceof AbstractStruct) { searchStruct(entry, (AbstractStruct)o); } } // special cases final String keyword = (targetEntry.toString().lastIndexOf('.') >= 0) ? targetEntry.toString().substring(0, targetEntry.toString().lastIndexOf('.')) : targetEntry.toString(); if (struct instanceof EffResource) { // checking resource2/3 fields final String[] fieldName = {"Resource 2", "Resource 3"}; for (int i = 0; i < fieldName.length; i++) { StructEntry o = struct.getAttribute(fieldName[i]); if (o instanceof TextString) { if (o.toString().equalsIgnoreCase(keyword)) { addHit(entry, entry.getSearchString(), o); } } } } } private void searchBam(ResourceEntry entry, BamResource bam) { Pattern pattern = Pattern.compile("MOS([0-9]{4,5})\\.PVRZ$", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(getTargetEntry().getResourceName()); if (matcher.find()) { int index = -1; try { index = Integer.parseInt(matcher.group(1)); } catch (NumberFormatException e) { } if (index >= 0 && index <= 99999) { if (bam.containsPvrzReference(index)) { addHit(entry, null, null); } } } } private void searchMos(ResourceEntry entry, MosResource mos) { Pattern pattern = Pattern.compile("MOS([0-9]{4,5})\\.PVRZ$", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(getTargetEntry().getResourceName()); if (matcher.find()) { int index = -1; try { index = Integer.parseInt(matcher.group(1)); } catch (NumberFormatException e) { } if (index >= 0 && index <= 99999) { if (mos.containsPvrzReference(index)) { addHit(entry, null, null); } } } } private void searchTis(ResourceEntry entry, TisResource tis) { Pattern pGeneric = Pattern.compile("MOS[0-9]{4,5}\\.PVRZ$", Pattern.CASE_INSENSITIVE); Pattern pArea = Pattern.compile("(.)(.{4})(N?)([0-9]{2})\\.PVRZ$", Pattern.CASE_INSENSITIVE); Matcher mGeneric = pGeneric.matcher(getTargetEntry().getResourceName()); if (!mGeneric.find()) { Matcher mArea = pArea.matcher(getTargetEntry().getResourceName()); if (mArea.find()) { String prefix = mArea.group(1); String code = mArea.group(2); String night = mArea.group(3); String page = mArea.group(4); Pattern pTis; if (night.isEmpty()) { pTis = Pattern.compile(String.format("%1$s.%2$s\\.TIS$", prefix.toUpperCase(Locale.ENGLISH), code), Pattern.CASE_INSENSITIVE); } else { pTis = Pattern.compile(String.format("%1$s.%2$sN\\.TIS$", prefix.toUpperCase(Locale.ENGLISH), code), Pattern.CASE_INSENSITIVE); } int index = -1; try { index = Integer.parseInt(page); } catch (NumberFormatException e) { } if (pTis.matcher(entry.getResourceName()).find() && index >= 0 && index <= 99) { if (tis.containsPvrzReference(index)) { addHit(entry, null, null); } } } } } private void searchText(ResourceEntry entry, PlainTextResource text) { String name = getTargetEntry().getResourceName(); int idx = name.lastIndexOf('.'); if (idx > 0) { name = name.substring(0, idx); } Pattern p = Pattern.compile("\\b(AP_|GA_)?" + name + "\\b", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher(text.getText()); if (m.find()) { addHit(entry, entry.getSearchString(), null); } if (targetEntryName != null && !targetEntryName.equalsIgnoreCase(name)) { p = Pattern.compile("\\b" + targetEntryName + "\\b", Pattern.CASE_INSENSITIVE); m = p.matcher(text.getText()); if (m.find()) { addHit(entry, targetEntryName, null); } } } }