X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fserial%2FImporter.java;h=5d7d8d05ee30e298b802125abc63128c748ccb88;hb=1d20e650389b5aaaaa5de4213cefefade582da5d;hp=61093f754e158642e82a63ec27da598b17a6e929;hpb=8c8da42a501ff223ee1340ab71d03df481649e78;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/serial/Importer.java b/src/be/nikiroo/utils/serial/Importer.java index 61093f7..5d7d8d0 100644 --- a/src/be/nikiroo/utils/serial/Importer.java +++ b/src/be/nikiroo/utils/serial/Importer.java @@ -1,11 +1,14 @@ package be.nikiroo.utils.serial; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; -import java.util.Scanner; +import be.nikiroo.utils.IOUtils; +import be.nikiroo.utils.NextableInputStream; +import be.nikiroo.utils.NextableInputStreamStep; import be.nikiroo.utils.StringUtils; /** @@ -26,6 +29,9 @@ public class Importer { private String currentFieldName; + /** + * Create a new {@link Importer}. + */ public Importer() { map = new HashMap(); map.put("NULL", null); @@ -53,26 +59,46 @@ public class Importer { * because it is not compatible with this code * @throws ClassNotFoundException * if a class described in the serialised data cannot be found + * @throws IOException + * if the content cannot be read (for instance, corrupt data) + * @throws NullPointerException + * if the stream is empty */ - public Importer read(String data) throws NoSuchFieldException, - NoSuchMethodException, ClassNotFoundException { + public Importer read(InputStream in) throws NoSuchFieldException, + NoSuchMethodException, ClassNotFoundException, IOException, + NullPointerException { - try { - Scanner scan = new Scanner(data); - scan.useDelimiter("\n"); - while (scan.hasNext()) { - String line = scan.next(); + // TODO: fix NexInStream: next() MUST be called first time, too + // TODO: NexInStream: add getBytes() (size downloaded) + // TODO: public InputStrem open() (open/close do nothing) + // TODO: public boolean eof() + // TODO: public nextAll(): next, but disable separation of sub-streams + // TODO: close(alsoCloseIncludedField) - if (line.startsWith("ZIP:")) { - line = StringUtils.unzip64(line.substring("ZIP:".length())); - } - processLine(line); + NextableInputStream stream = new NextableInputStream(in, + new NextableInputStreamStep('\n')); + + if (in == null || stream.eof()) { + if (in == null) { + throw new NullPointerException("InputStream is null"); + } + throw new NullPointerException("InputStream is empty"); + } + while (stream.next()) { + boolean zip = stream.startsWiths("ZIP:"); + boolean b64 = stream.startsWiths("B64:"); + + if (zip || b64) { + InputStream decoded = StringUtils.unbase64(stream.open(), zip); + try { + read(decoded); + } finally { + decoded.close(); + } + } else { + processLine(stream); } - scan.close(); - } catch (IOException e) { - throw new NoSuchMethodException( - "Internal error when decoding ZIP content: input may be corrupt"); } return this; @@ -95,12 +121,15 @@ public class Importer { * because it is not compatible with this code * @throws ClassNotFoundException * if a class described in the serialised data cannot be found + * @throws IOException + * if the content cannot be read (for instance, corrupt data) */ - private boolean processLine(String line) throws NoSuchFieldException, - NoSuchMethodException, ClassNotFoundException { + private boolean processLine(InputStream in) throws NoSuchFieldException, + NoSuchMethodException, ClassNotFoundException, IOException { + // Defer to latest child if any if (child != null) { - if (child.processLine(line)) { + if (child.processLine(in)) { if (currentFieldName != null) { setField(currentFieldName, child.getValue()); currentFieldName = null; @@ -111,6 +140,9 @@ public class Importer { return false; } + // TODO use the stream, Luke + String line = IOUtils.readSmallStream(in); + if (line.equals("{")) { // START: new child if needed if (link != null) { child = new Importer(map); @@ -118,18 +150,34 @@ public class Importer { } else if (line.equals("}")) { // STOP: report self to parent return true; } else if (line.startsWith("REF ")) { // REF: create/link self - String ref = line.substring(4).split("@")[1]; + String[] tab = line.substring("REF ".length()).split("@"); + String type = tab[0]; + tab = tab[1].split(":"); + String ref = tab[0]; + link = map.containsKey(ref); if (link) { me = map.get(ref); } else { - me = SerialUtils.createObject(line.substring(4).split("@")[0]); + if (line.endsWith(":")) { + // construct + me = SerialUtils.createObject(type); + } else { + // direct value + int pos = line.indexOf(":"); + String encodedValue = line.substring(pos + 1); + me = SerialUtils.decode(encodedValue); + } map.put(ref, me); } - } else { // FIELD: new field + } else { // FIELD: new field *or* direct simple value if (line.endsWith(":")) { // field value is compound currentFieldName = line.substring(0, line.length() - 1); + } else if (line.startsWith(":") || !line.contains(":") + || line.startsWith("\"") || CustomSerializer.isCustom(line)) { + // not a field value but a direct value + me = SerialUtils.decode(line); } else { // field value is direct int pos = line.indexOf(":"); @@ -169,6 +217,37 @@ public class Importer { } } + /** + * Find the given needle in the data and return its position (or -1 if not + * found). + * + * @param data + * the data to look through + * @param offset + * the offset at wich to start searching + * @param needle + * the needle to find + * + * @return the position of the needle if found, -1 if not found + */ + private int find(byte[] data, int offset, byte[] needle) { + for (int i = offset; i + needle.length - 1 < data.length; i++) { + boolean same = true; + for (int j = 0; j < needle.length; j++) { + if (data[i + j] != needle[j]) { + same = false; + break; + } + } + + if (same) { + return i; + } + } + + return -1; + } + /** * Return the current deserialised value. *