Gridarta Editor
SpellsUtils.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.gui.spells;
21 
22 import java.awt.Component;
23 import java.io.BufferedReader;
24 import java.io.EOFException;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileNotFoundException;
28 import java.io.FileOutputStream;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.InputStreamReader;
32 import java.io.OutputStreamWriter;
33 import java.io.PrintWriter;
34 import java.io.Reader;
35 import java.nio.charset.StandardCharsets;
36 import java.util.Date;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.TreeMap;
40 import javax.swing.JFileChooser;
41 import javax.swing.filechooser.FileFilter;
43 import net.sf.japi.swing.action.ActionBuilder;
44 import net.sf.japi.swing.action.ActionBuilderFactory;
45 import net.sf.japi.util.filter.file.FilenameFileFilter;
46 import org.apache.log4j.Category;
47 import org.apache.log4j.Logger;
48 import org.jetbrains.annotations.NotNull;
49 import org.jetbrains.annotations.Nullable;
50 
54 public class SpellsUtils {
55 
59  private static final long READ_MAX = 10000L;
60 
64  @NotNull
65  private static final Category LOG = Logger.getLogger(SpellsUtils.class);
66 
70  @NotNull
71  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
72 
76  @NotNull
77  private static final FileFilter SPELL_LIST_H_FILE_FILTER = new FilenameFileFilter(true, "spellist.h", "spellist.h");
78 
82  @NotNull
83  private final String spellFile;
84 
89  public SpellsUtils(@NotNull final String spellFile) {
90  this.spellFile = spellFile;
91  }
92 
98  public void importSpells(@NotNull final File dir, @NotNull final Component parent) {
99  // open a file chooser window
100  final JFileChooser fileChooser = new JFileChooser();
101  fileChooser.setDialogTitle("Open CF Spell List File");
102  fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
103  fileChooser.setMultiSelectionEnabled(false);
104  fileChooser.setFileFilter(SPELL_LIST_H_FILE_FILTER); // apply file filter
105  final File cd = new File(System.getProperty("user.dir"));
106  final File sd = new File(cd, "../server/src/include");
107  FileChooserUtils.setCurrentDirectory(fileChooser, sd.exists() ? sd : cd);
108 
109  final int returnVal = fileChooser.showOpenDialog(parent);
110 
111  if (returnVal == JFileChooser.APPROVE_OPTION) {
112  // now import spells from selected file
113  final File tmpSpellFile = fileChooser.getSelectedFile();
114  final int spNum = importSpells(tmpSpellFile, dir);
115  if (spNum > 0) {
116  // yeah it worked
117  ACTION_BUILDER.showMessageDialog(parent, "importSpellsSuccess", spNum);
118  } else {
119  // spell collect failed
120  ACTION_BUILDER.showMessageDialog(parent, "importSpellsFailed");
121  }
122  }
123  }
124 
132  private int importSpells(@NotNull final File spellFile, @NotNull final File dir) {
133  final Map<String, String> spells = new TreeMap<>();
134  if (spellFile.getName().equalsIgnoreCase("spellist.h")) {
135  try {
136  try (InputStream fis = new FileInputStream(spellFile.getAbsolutePath())) {
137  try (Reader isr = new InputStreamReader(fis)) {
138  try (Reader in = new BufferedReader(isr)) {
139  readUntil(in, "spell spells", null);
140  readUntil(in, "{", null);
141 
142  int counter = 0;
143  while (true) {
144  try {
145  readUntil(in, "{", "}");
146  } catch (final EOFException ignored) {
147  // Eventually expected exception, don't handle.
148  break;
149  }
150  readUntil(in, "\"", null);
151  final String name = readUntil(in, "\"").trim();
152  readUntil(in, "}", null);
153 
154  spells.put(name, Integer.toString(counter++));
155  }
156  }
157  }
158  }
159  } catch (final FileNotFoundException ignored) {
160  LOG.error("File '" + spellFile.getAbsolutePath() + "' not found!");
161  } catch (final IOException ex) {
162  LOG.error("Cannot read file '" + spellFile.getAbsolutePath() + "': " + ex.getMessage());
163  }
164  }
165 
166  // --------- now write the "spells.def" file ---------
167  if (!spells.isEmpty()) {
168  // FIXME: This should use DOM for writing the file.
169  // create new file for writing (replaces old one if existent)
170  if (!dir.exists() || !dir.isDirectory()) { // FIXME What if dir exists and is not a directory? mkdirs will fail then!
171  // create the config dir
172  dir.mkdirs();
173  }
174  final File dirFile = new File(dir, this.spellFile);
175 
176  try {
177  try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(dirFile), StandardCharsets.UTF_8))) {
178  // header:
179  out.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
180  out.println("<!DOCTYPE spells SYSTEM \"spells.dtd\">");
181  out.println("<!--");
182  out.println(" - ##########################################################");
183  out.println(" - # You may add new spells to this file, but there's no #");
184  out.println(" - # need to do it because the file can be auto-generated. #");
185  out.println(" - # In the editor, select menu \"Resources->Collect Spells\" #");
186  out.println(" - # to generate a new version of this file. #");
187  out.println(" - ##########################################################");
188  out.println(" -->");
189  out.println("<!-- Generated on: " + new Date() + " -->");
190  out.println("<spells>");
191 
192  final String[] spaces = { " ", " ", "" };
193  for (final Entry<String, String> entry : spells.entrySet()) {
194  final String id = entry.getValue();
195  out.println(" <spell id=\"" + id + '\"' + spaces[id.length() - 1] + " name=\"" + entry.getKey() + "\" />");
196  }
197  out.println("</spells>");
198  }
199  } catch (final IOException ex) {
200  LOG.error("Cannot write file '" + dirFile.getAbsolutePath() + "': " + ex.getMessage());
201  }
202  }
203  return spells.size();
204  }
205 
221  private static void readUntil(@NotNull final Reader stream, @NotNull final CharSequence tag, @Nullable final CharSequence abort) throws IOException {
222  int c; // character value, read from the stream
223  int t = 0; // tag index
224  int a = 0; // abort index
225 
226  if (abort == null) {
227  // look only for 'tag'
228  do {
229  c = stream.read();
230  if (c == tag.charAt(t)) {
231  t++;
232  } else {
233  t = 0;
234  }
235  } while (t < tag.length() && c != -1);
236  } else {
237  // look both for 'tag' and 'abort'
238  do {
239  c = stream.read();
240  if (c == tag.charAt(t)) {
241  t++;
242  } else {
243  t = 0;
244  }
245  if (c == abort.charAt(a)) {
246  a++;
247  } else {
248  a = 0;
249  }
250  } while (t < tag.length() && a < abort.length() && c != -1);
251  }
252 
253  // if we did not find the tag, an EOFException is thrown
254  if (c == -1) {
255  throw new EOFException("tag '" + tag + "' not found");
256  }
257 
258  // if we found the string 'abort', throw EOFException as well
259  if (abort != null && a == abort.length()) {
260  throw new EOFException("tag '" + tag + "' not found before '" + abort + "'");
261  }
262  }
263 
275  private static String readUntil(@NotNull final Reader stream, @NotNull final CharSequence tag) throws IOException {
276  final StringBuilder sb = new StringBuilder();
277  int c; // character value, read from the stream
278  int t = 0; // index
279 
280  long count = 0L; // counter (to realize when shooting past EOF)
281  final long maxCount = READ_MAX; // bail out when counter exceeds this value
282 
283  do {
284  c = stream.read(); // read one character
285  sb.append((char) c);
286  if (c == tag.charAt(t)) {
287  t++;
288  } else {
289  t = 0;
290  }
291  } while (t < tag.length() && c != -1 && count++ < maxCount);
292 
293  // if we did not find the tag, an EOFException is thrown
294  if (c == -1 || count >= maxCount) {
295  throw new EOFException("tag '" + tag + "' not found");
296  }
297  // cut 'tag' off, at the end of the string
298  return sb.substring(0, sb.length() - tag.length());
299  }
300 
301 }
net.sf.gridarta.gui.spells.SpellsUtils
Definition: SpellsUtils.java:54
net.sf.gridarta.gui.spells.SpellsUtils.SpellsUtils
SpellsUtils(@NotNull final String spellFile)
Definition: SpellsUtils.java:89
net.sf.gridarta
net.sf.gridarta.utils.FileChooserUtils.setCurrentDirectory
static void setCurrentDirectory(@NotNull final JFileChooser fileChooser, @Nullable final File dir)
Definition: FileChooserUtils.java:48
net.sf
net.sf.gridarta.gui.spells.SpellsUtils.READ_MAX
static final long READ_MAX
Definition: SpellsUtils.java:59
net.sf.gridarta.gui.spells.SpellsUtils.spellFile
final String spellFile
Definition: SpellsUtils.java:83
net
net.sf.gridarta.gui.spells.SpellsUtils.importSpells
int importSpells(@NotNull final File spellFile, @NotNull final File dir)
Definition: SpellsUtils.java:132
net.sf.gridarta.gui.spells.SpellsUtils.SPELL_LIST_H_FILE_FILTER
static final FileFilter SPELL_LIST_H_FILE_FILTER
Definition: SpellsUtils.java:77
net.sf.gridarta.gui.spells.SpellsUtils.importSpells
void importSpells(@NotNull final File dir, @NotNull final Component parent)
Definition: SpellsUtils.java:98
net.sf.gridarta.gui.spells.SpellsUtils.readUntil
static void readUntil(@NotNull final Reader stream, @NotNull final CharSequence tag, @Nullable final CharSequence abort)
Definition: SpellsUtils.java:221
net.sf.gridarta.gui.spells.SpellsUtils.LOG
static final Category LOG
Definition: SpellsUtils.java:65
net.sf.gridarta.utils.FileChooserUtils
Definition: FileChooserUtils.java:31
net.sf.gridarta.gui.spells.SpellsUtils.ACTION_BUILDER
static final ActionBuilder ACTION_BUILDER
Definition: SpellsUtils.java:71
net.sf.gridarta.utils
Definition: ActionBuilderUtils.java:20
net.sf.gridarta.gui.spells.SpellsUtils.readUntil
static String readUntil(@NotNull final Reader stream, @NotNull final CharSequence tag)
Definition: SpellsUtils.java:275