diff --git a/.gitattributes b/.gitattributes
index 7c84b36f35c..5615d83d75c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -11637,6 +11637,7 @@ src/main/java/forge/util/IItemSerializer.java -text
src/main/java/forge/util/IStorage.java -text
src/main/java/forge/util/IStorageView.java -text
src/main/java/forge/util/IgnoringXStream.java -text
+src/main/java/forge/util/LineReader.java -text
src/main/java/forge/util/MyRandom.java svneol=native#text/plain
src/main/java/forge/util/Predicate.java -text
src/main/java/forge/util/PredicateString.java -text
diff --git a/src/main/java/forge/CardReader.java b/src/main/java/forge/CardReader.java
index 26ac0d99cdb..894afdab6c7 100644
--- a/src/main/java/forge/CardReader.java
+++ b/src/main/java/forge/CardReader.java
@@ -51,6 +51,8 @@ import forge.card.replacement.ReplacementHandler;
import forge.card.trigger.TriggerHandler;
import forge.error.ErrorViewer;
import forge.gui.toolbox.FProgressBar;
+import forge.util.FileUtil;
+import forge.util.LineReader;
import forge.view.SplashFrame;
/**
@@ -341,35 +343,6 @@ public class CardReader implements Runnable {
}
}
- /**
- *
- * Reads a line from the given reader and handles exceptions.
- *
- *
- * @param reader
- * a {@link java.io.BufferedReader} object.
- * @return a {@link java.lang.String} object.
- */
- public static String readLine(final BufferedReader reader) {
- // makes the checked exception, into an unchecked runtime exception
- try {
- String line = reader.readLine();
- if (line != null) {
- line = line.trim();
- }
- return line;
- } catch (final Exception ex) {
- ErrorViewer.showError(ex);
- throw new RuntimeException("CardReader : readLine(Card) error", ex);
- // by
- // Braids
- // on
- // 8/18/11
- // 10:53
- // PM
- }
- } // readLine(BufferedReader)
-
/**
*
* load a card.
@@ -381,142 +354,9 @@ public class CardReader implements Runnable {
* @return the card loaded from the stream
*/
protected final Card loadCard(final InputStream inputStream) {
- final Card card = new Card();
this.rulesReader.reset();
-
- InputStreamReader inputStreamReader = null;
- BufferedReader reader = null;
- try {
- inputStreamReader = new InputStreamReader(inputStream, this.charset);
- reader = new BufferedReader(inputStreamReader);
-
- String line = CardReader.readLine(reader);
- while (!"End".equals(line)) {
- this.rulesReader.parseLine(line);
- if (line.isEmpty()) {
- // Ignore empty lines.
- } else if (line.charAt(0) == '#') {
- // 8/18/11 10:59 PM
- // no need to do anything, this indicates a comment line
- } else if (line.startsWith("Name:")) {
- final String value = line.substring(5);
- // System.out.println(s);
- if (this.mapToFill.containsKey(value)) {
- break; // this card has already been loaded.
- } else {
- card.setName(value);
- }
- } else if (line.startsWith("ManaCost:")) {
- final String value = line.substring(9);
- // System.out.println(s);
- if (!"no cost".equals(value)) {
- card.setManaCost(value);
- }
- } else if (line.startsWith("Types:")) {
- CardReader.addTypes(card, line.substring("Types:".length()));
- } else if (line.startsWith("Text:")) {
- String value = line.substring("Text:".length());
- // if (!t.equals("no text"));
- if ("no text".equals(value)) {
- value = "";
- }
- card.setText(value);
- } else if (line.startsWith("PT:")) {
- final String value = line.substring("PT:".length());
- final String[] powTough = value.split("/");
- int att;
- if (powTough[0].contains("*")) {
- att = 0;
- } else {
- att = Integer.parseInt(powTough[0]);
- }
-
- int def;
- if (powTough[1].contains("*")) {
- def = 0;
- } else {
- def = Integer.parseInt(powTough[1]);
- }
-
- card.setBaseAttackString(powTough[0]);
- card.setBaseDefenseString(powTough[1]);
- card.setBaseAttack(att);
- card.setBaseDefense(def);
- } else if (line.startsWith("Loyalty:")) {
- final String[] splitStr = line.split(":");
- final int loyal = Integer.parseInt(splitStr[1]);
- card.setBaseLoyalty(loyal);
- } else if (line.startsWith("K:")) {
- final String value = line.substring(2);
- card.addIntrinsicKeyword(value);
- } else if (line.startsWith("SVar:")) {
- final String[] value = line.split(":", 3);
- card.setSVar(value[1], value[2]);
- } else if (line.startsWith("A:")) {
- final String value = line.substring(2);
- card.addIntrinsicAbility(value);
- } else if (line.startsWith("T:")) {
- final String value = line.substring(2);
- card.addTrigger(TriggerHandler.parseTrigger(value, card, true));
- } else if (line.startsWith("S:")) {
- final String value = line.substring(2);
- card.addStaticAbilityString(value);
- } else if (line.startsWith("R:")) {
- final String value = line.substring(2);
- card.addReplacementEffect(ReplacementHandler.parseReplacement(value, card));
- } else if (line.startsWith("SetInfo:")) {
- final String value = line.substring("SetInfo:".length());
- card.addSet(new EditionInfo(value));
- // 8/18/11 11:08 PM
- } else if (line.equals("ALTERNATE")) {
- String mode;
- if (card.isFlip()) {
- mode = "Flipped";
- } else if (card.isDoubleFaced()) {
- mode = "Transformed";
- } else {
- mode = card.isTransformable();
- }
- card.addAlternateState(mode);
- card.setState(mode);
- } else if (line.startsWith("AlternateMode:")) {
- final String value = line.substring("AlternateMode:".length());
- if (value.equalsIgnoreCase("Flip")) {
- card.setFlip(true);
- } else if (value.equalsIgnoreCase("DoubleFaced")) {
- card.setDoubleFaced(true);
- } else {
- card.setTransformable(value);
- }
- } else if (line.startsWith("Colors:")) {
- final String value = line.substring("Colors:".length());
- final ArrayList newCols = new ArrayList();
- for (final String col : value.split(",")) {
- final CardColor newCol = new CardColor(card);
- newCol.addToCardColor(col);
- newCols.add(newCol);
- }
-
- card.setColor(newCols);
- card.setCardColorsOverridden(true);
- }
-
- line = CardReader.readLine(reader);
- } // while !End
- } finally {
- try {
- reader.close();
- } catch (final IOException ignored) {
- // 11:08
- // PM
- }
- try {
- inputStreamReader.close();
- } catch (final IOException ignored) {
- // 11:08
- // PM
- }
- }
+
+ Card card = readCard( new LineReader(inputStream, this.charset), this.rulesReader, mapToFill );
if (card.isInAlternateState()) {
card.setState("Original");
@@ -526,6 +366,141 @@ public class CardReader implements Runnable {
this.mapToFill.put(card.getName(), card);
return card;
}
+
+ public static Card readCard(Iterable lines)
+ {
+ return readCard(lines, null, null);
+ }
+
+ /**
+ * Returns the card read from input stream
+ * @param lines are input lines
+ * @param rulesReader is used to fill CardPrinted characteristics
+ * @param mapToFill is used to eliminate duplicates
+ * @return the card
+ */
+ public static Card readCard(Iterable lines, CardRulesReader rulesReader, Map mapToFill) {
+ final Card card = new Card();
+ boolean ignoreTheRest = false;
+
+ for(String line : lines ) {
+ line = line.trim();
+
+ if("End".equals(line)) { ignoreTheRest = true; continue; }
+ if(ignoreTheRest) { continue; } // have to deplete the iterator
+ // otherwise the underlying class would close its stream on finalize only
+
+ if (line.isEmpty() || line.charAt(0) == '#')
+ continue;
+
+ if ( null != rulesReader )
+ rulesReader.parseLine(line);
+
+ if (line.startsWith("Name:")) {
+ final String value = line.substring(5);
+ // System.out.println(s);
+ if (mapToFill != null && mapToFill.containsKey(value)) {
+ break; // this card has already been loaded.
+ } else {
+ card.setName(value);
+ }
+ } else if (line.startsWith("ManaCost:")) {
+ final String value = line.substring(9);
+ // System.out.println(s);
+ if (!"no cost".equals(value)) {
+ card.setManaCost(value);
+ }
+ } else if (line.startsWith("Types:")) {
+ CardReader.addTypes(card, line.substring("Types:".length()));
+ } else if (line.startsWith("Text:")) {
+ String value = line.substring("Text:".length());
+ // if (!t.equals("no text"));
+ if ("no text".equals(value)) {
+ value = "";
+ }
+ card.setText(value);
+ } else if (line.startsWith("PT:")) {
+ final String value = line.substring("PT:".length());
+ final String[] powTough = value.split("/");
+ int att;
+ if (powTough[0].contains("*")) {
+ att = 0;
+ } else {
+ att = Integer.parseInt(powTough[0]);
+ }
+
+ int def;
+ if (powTough[1].contains("*")) {
+ def = 0;
+ } else {
+ def = Integer.parseInt(powTough[1]);
+ }
+
+ card.setBaseAttackString(powTough[0]);
+ card.setBaseDefenseString(powTough[1]);
+ card.setBaseAttack(att);
+ card.setBaseDefense(def);
+ } else if (line.startsWith("Loyalty:")) {
+ final String[] splitStr = line.split(":");
+ final int loyal = Integer.parseInt(splitStr[1]);
+ card.setBaseLoyalty(loyal);
+ } else if (line.startsWith("K:")) {
+ final String value = line.substring(2);
+ card.addIntrinsicKeyword(value);
+ } else if (line.startsWith("SVar:")) {
+ final String[] value = line.split(":", 3);
+ card.setSVar(value[1], value[2]);
+ } else if (line.startsWith("A:")) {
+ final String value = line.substring(2);
+ card.addIntrinsicAbility(value);
+ } else if (line.startsWith("T:")) {
+ final String value = line.substring(2);
+ card.addTrigger(TriggerHandler.parseTrigger(value, card, true));
+ } else if (line.startsWith("S:")) {
+ final String value = line.substring(2);
+ card.addStaticAbilityString(value);
+ } else if (line.startsWith("R:")) {
+ final String value = line.substring(2);
+ card.addReplacementEffect(ReplacementHandler.parseReplacement(value, card));
+ } else if (line.startsWith("SetInfo:")) {
+ final String value = line.substring("SetInfo:".length());
+ card.addSet(new EditionInfo(value));
+ // 8/18/11 11:08 PM
+ } else if (line.equals("ALTERNATE")) {
+ String mode;
+ if (card.isFlip()) {
+ mode = "Flipped";
+ } else if (card.isDoubleFaced()) {
+ mode = "Transformed";
+ } else {
+ mode = card.isTransformable();
+ }
+ card.addAlternateState(mode);
+ card.setState(mode);
+ } else if (line.startsWith("AlternateMode:")) {
+ final String value = line.substring("AlternateMode:".length());
+ if (value.equalsIgnoreCase("Flip")) {
+ card.setFlip(true);
+ } else if (value.equalsIgnoreCase("DoubleFaced")) {
+ card.setDoubleFaced(true);
+ } else {
+ card.setTransformable(value);
+ }
+ } else if (line.startsWith("Colors:")) {
+ final String value = line.substring("Colors:".length());
+ final ArrayList newCols = new ArrayList();
+ for (final String col : value.split(",")) {
+ final CardColor newCol = new CardColor(card);
+ newCol.addToCardColor(col);
+ newCols.add(newCol);
+ }
+
+ card.setColor(newCols);
+ card.setCardColorsOverridden(true);
+ }
+ } // while !End
+ return card;
+ }
/**
* Set the character encoding to use when loading cards.
diff --git a/src/main/java/forge/game/limited/CardRatings.java b/src/main/java/forge/game/limited/CardRatings.java
index c44e8fbe603..6606e4c7976 100644
--- a/src/main/java/forge/game/limited/CardRatings.java
+++ b/src/main/java/forge/game/limited/CardRatings.java
@@ -19,6 +19,7 @@ package forge.game.limited;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
@@ -36,7 +37,7 @@ public class CardRatings {
private static Map blockRatings = new TreeMap();
private static Map customRatings = new TreeMap();
- private static ArrayList tempRatings = new ArrayList();
+ private static List tempRatings = new ArrayList();
/**
* Instantiates a new card ratings.
@@ -60,7 +61,7 @@ public class CardRatings {
}
private void loadFullRatings() {
- final ArrayList sRatings = FileUtil.readFile("res/draft/fullRatings.dat");
+ final List sRatings = FileUtil.readFile("res/draft/fullRatings.dat");
if (sRatings.size() > 1) {
for (final String s : sRatings) {
if (s.length() > 3) {
@@ -74,7 +75,7 @@ public class CardRatings {
}
private void loadBlockRatings() {
- final ArrayList sRatings = FileUtil.readFile("res/draft/blockRatings.dat");
+ final List sRatings = FileUtil.readFile("res/draft/blockRatings.dat");
if (sRatings.size() > 1) {
for (final String s : sRatings) {
if (s.length() > 3) {
@@ -88,7 +89,7 @@ public class CardRatings {
}
private void loadCustomRatings() {
- final ArrayList sRatings = FileUtil.readFile("res/draft/customRatings.dat");
+ final List sRatings = FileUtil.readFile("res/draft/customRatings.dat");
if (sRatings.size() > 1) {
for (final String s : sRatings) {
if (s.length() > 3) {
diff --git a/src/main/java/forge/game/limited/SealedDeck.java b/src/main/java/forge/game/limited/SealedDeck.java
index 48e66a46aca..e8921558b6a 100644
--- a/src/main/java/forge/game/limited/SealedDeck.java
+++ b/src/main/java/forge/game/limited/SealedDeck.java
@@ -136,7 +136,7 @@ public class SealedDeck {
for (final String element : dList) {
if (element.endsWith(".sealed")) {
- final ArrayList dfData = FileUtil.readFile("res/sealed/" + element);
+ final List dfData = FileUtil.readFile("res/sealed/" + element);
final CustomLimited cs = CustomLimited.parse(dfData, Singletons.getModel().getDecks().getCubes());
customs.add(cs);
}
diff --git a/src/main/java/forge/model/FModel.java b/src/main/java/forge/model/FModel.java
index cbc93e42293..ecfba1adfb6 100644
--- a/src/main/java/forge/model/FModel.java
+++ b/src/main/java/forge/model/FModel.java
@@ -181,7 +181,7 @@ public enum FModel {
*/
public static void loadDynamicGamedata() {
if (!Constant.CardTypes.LOADED[0]) {
- final ArrayList typeListFile = FileUtil.readFile("res/gamedata/TypeLists.txt");
+ final List typeListFile = FileUtil.readFile("res/gamedata/TypeLists.txt");
ArrayList tList = null;
@@ -262,7 +262,7 @@ public enum FModel {
}
if (!Constant.Keywords.LOADED[0]) {
- final ArrayList nskwListFile = FileUtil.readFile("res/gamedata/NonStackingKWList.txt");
+ final List nskwListFile = FileUtil.readFile("res/gamedata/NonStackingKWList.txt");
Constant.Keywords.NON_STACKING_LIST[0] = new ConstantStringArrayList();
diff --git a/src/main/java/forge/quest/data/pet/QuestPetPlant.java b/src/main/java/forge/quest/data/pet/QuestPetPlant.java
index a86da2be57f..5da98c06a37 100644
--- a/src/main/java/forge/quest/data/pet/QuestPetPlant.java
+++ b/src/main/java/forge/quest/data/pet/QuestPetPlant.java
@@ -92,6 +92,7 @@ public class QuestPetPlant extends QuestPetAbstract {
petCard.setBaseDefense(4);
petCard.addIntrinsicKeyword("Deathtouch");
+ // A:AB$ GainLife | Cost$ T | LifeAmount$ 1 | SpellDescription$ You gain 1 life.
final Cost abCost = new Cost("T", petCard.getName(), true);
final SpellAbility ability = new AbilityActivated(petCard, abCost, null) {
private static final long serialVersionUID = 7546242087593613719L;
diff --git a/src/main/java/forge/util/FileUtil.java b/src/main/java/forge/util/FileUtil.java
index fcf175da227..5f971072f36 100644
--- a/src/main/java/forge/util/FileUtil.java
+++ b/src/main/java/forge/util/FileUtil.java
@@ -26,6 +26,7 @@ import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.Reader;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
@@ -116,7 +117,7 @@ public final class FileUtil {
* a {@link java.lang.String} object.
* @return a {@link java.util.ArrayList} object.
*/
- public static ArrayList readFile(final String filename) {
+ public static List readFile(final String filename) {
return FileUtil.readFile(new File(filename));
}
@@ -132,30 +133,47 @@ public final class FileUtil {
* a {@link java.io.File} object.
* @return a {@link java.util.ArrayList} object.
*/
- public static ArrayList readFile(final File file) {
- final ArrayList list = new ArrayList();
- BufferedReader in;
-
+ public static List readFile(final File file) {
try {
if ((file == null) || !file.exists()) {
- return list;
+ return new ArrayList();
}
-
- in = new BufferedReader(new FileReader(file));
-
- String line;
- while ((line = in.readLine()) != null) {
- list.add(line);
- }
- in.close();
+ return readAllLines(new FileReader(file), false);
} catch (final Exception ex) {
ErrorViewer.showError(ex);
throw new RuntimeException("FileUtil : readFile() error, " + ex);
}
-
- return list;
} // readFile()
+ public static List readAllLines(Reader reader){
+ return readAllLines(reader, false);
+ }
+
+ /**
+ * Reads all lines from given reader to a list of strings
+ * @param reader is a reader (e.g. FileReader, InputStreamReader)
+ * @param mayTrim defines whether to trim lines.
+ * @return list of strings
+ */
+ public static List readAllLines(Reader reader, boolean mayTrim){
+ final ArrayList list = new ArrayList();
+ try {
+ BufferedReader in = new BufferedReader(reader);
+ String line;
+ while ((line = in.readLine()) != null) {
+ if ( mayTrim ) {
+ line = line.trim();
+ }
+ list.add(line);
+ }
+ in.close();
+ } catch (IOException ex ) {
+ ErrorViewer.showError(ex);
+ throw new RuntimeException("FileUtil : readAllLines() error, " + ex);
+ }
+ return list;
+ }
+
/**
* Download url into file.
*
diff --git a/src/main/java/forge/util/LineReader.java b/src/main/java/forge/util/LineReader.java
new file mode 100644
index 00000000000..f6eafa1d2e6
--- /dev/null
+++ b/src/main/java/forge/util/LineReader.java
@@ -0,0 +1,145 @@
+package forge.util;
+
+/**
+ * TODO: Write javadoc for this type.
+ *
+ */
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Represents the lines found in an {@link InputStream}. The lines are read
+ * one at a time using {@link BufferedReader#readLine()} and may be streamed
+ * through an iterator or returned all at once.
+ *
+ * This class does not handle any concurrency issues.
+ *
+ *
The stream is closed automatically when the for loop is done :)
+ *
+ *
{@code
+ * for(String line : new LineReader(stream))
+ * // ...
+ * }
+ *
+ * An {@link IllegalStateException} will be thrown if any {@link IOException}s
+ * occur when reading or closing the stream.
+ *
+ * @author Torleif Berger
+ * @license http://creativecommons.org/licenses/by/3.0/
+ * @see http://www.geekality.net/?p=1614
+ */
+public class LineReader implements Iterable, Closeable
+{
+ private BufferedReader reader;
+
+ public LineReader(InputStream stream) { this(stream, null); }
+ public LineReader(InputStream stream, Charset charset)
+ {
+ reader = new BufferedReader(new InputStreamReader(stream, charset));
+ }
+
+ /**
+ * Closes the underlying stream.
+ */
+ @Override
+ public void close() throws IOException
+ {
+ reader.close();
+ }
+
+ /**
+ * Makes sure the underlying stream is closed.
+ */
+ @Override
+ protected void finalize() throws Throwable
+ {
+ close();
+ }
+
+
+ /**
+ * Returns an iterator over the lines remaining to be read.
+ *
+ * The underlying stream is closed automatically once {@link Iterator#hasNext()}
+ * returns false. This means that the stream should be closed after using a for loop.
+ *
+ * @return This iterator.
+ */
+ @Override
+ public Iterator iterator()
+ {
+ return new LineIterator();
+ }
+
+ /**
+ * Returns all lines remaining to be read and closes the stream.
+ *
+ * @return The lines read from the stream.
+ */
+ public Collection readLines()
+ {
+ Collection lines = new ArrayList();
+ for(String line : this)
+ {
+ lines.add(line);
+ }
+ return lines;
+ }
+
+ private class LineIterator implements Iterator
+ {
+ private String nextLine;
+
+ public String bufferNext()
+ {
+ try
+ {
+ return nextLine = reader.readLine();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("I/O error while reading stream.", e);
+ }
+ }
+
+
+ public boolean hasNext()
+ {
+ boolean hasNext = nextLine != null || bufferNext() != null;
+
+ if ( ! hasNext)
+ try
+ {
+ reader.close();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("I/O error when closing stream.", e);
+ }
+
+ return hasNext;
+ }
+
+ public String next()
+ {
+ if ( ! hasNext())
+ throw new NoSuchElementException();
+
+ String result = nextLine;
+ nextLine = null;
+ return result;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/forge/util/StorageReaderFile.java b/src/main/java/forge/util/StorageReaderFile.java
index 9d8a4ce096c..c6665ede748 100644
--- a/src/main/java/forge/util/StorageReaderFile.java
+++ b/src/main/java/forge/util/StorageReaderFile.java
@@ -18,7 +18,6 @@
package forge.util;
import java.io.File;
-import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
@@ -55,9 +54,8 @@ public abstract class StorageReaderFile implements IItemReader {
@Override
public Map readAll() {
final Map result = new TreeMap();
- final ArrayList fData = FileUtil.readFile(this.file);
- for (final String s : fData) {
+ for (final String s : FileUtil.readFile(this.file)) {
if (!this.lineContainsObject(s)) {
continue;
}