From d1de25b3d965e9e08cc56687ee093e8107f6f30c Mon Sep 17 00:00:00 2001 From: Kethen Date: Wed, 23 Aug 2017 05:01:29 +0800 Subject: [PATCH 1/3] allowing in memory bplist by supporting inputstream as input --- .../bplist/converter/ConvertToXml.java | 17 +++++ .../bplist/parser/ElementParser.java | 64 +++++++++++++++++++ .../bplist/BinaryPListParserTest.java | 48 +++++++++++++- 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/main/java/nl/pvanassen/bplist/converter/ConvertToXml.java b/src/main/java/nl/pvanassen/bplist/converter/ConvertToXml.java index 247714b..151e455 100644 --- a/src/main/java/nl/pvanassen/bplist/converter/ConvertToXml.java +++ b/src/main/java/nl/pvanassen/bplist/converter/ConvertToXml.java @@ -133,6 +133,23 @@ public XMLElement convertToXml(File file) throws IOException { return root; } + /** + * Parses a binary PList from input stream and turns it into a XMLElement. The XMLElement + * is equivalent with a XML PList file parsed using NanoXML. + * + * @param is bplist input stream to parse + * @return Returns the parsed XMLElement. + * @throws IOException If the file is not found + */ + public XMLElement convertToXml(InputStream is) throws IOException { + // Convert the object table to XML and return it + XMLElement root = new XMLElement(new HashMap(), false, false); + root.setName("plist"); + root.setAttribute("version", "1.0"); + convertObjectTableToXML(root, parser.parseObjectTable(is).get(0)); + return root; + } + /** * Parses a binary PList file and turns it into a XMLElement. The XMLElement * is equivalent with a XML PList file parsed using NanoXML. diff --git a/src/main/java/nl/pvanassen/bplist/parser/ElementParser.java b/src/main/java/nl/pvanassen/bplist/parser/ElementParser.java index c79b268..d34c7ed 100644 --- a/src/main/java/nl/pvanassen/bplist/parser/ElementParser.java +++ b/src/main/java/nl/pvanassen/bplist/parser/ElementParser.java @@ -4,6 +4,7 @@ import java.math.BigInteger; import java.util.*; + import org.apache.commons.io.IOUtils; import org.slf4j.*; @@ -79,6 +80,69 @@ private List> parseObjectTable(RandomAccessFile raf) throws IOE return parseObjectTable(new DataInputStream(stream), refCount); } + /** + * Parse object table with an input stream. This method will not close + * the input stream for you. + * + * @param is + * Input stream + * @return List of objects parsed + * @throws IOException + * In case of an error + */ + public List> parseObjectTable(InputStream is) throws IOException{ + // mimic using a raf but with a InputStream so that we can read from memory if wanted + // supports only input streams that allows reset() + //byte[] intBuffer = new byte[4]; + //byte[] longBuffer = new byte[8]; + //was going to extend RandomAccessFile but realise I can't initialize it without a real file + //assume that everything happens here were in memory or some other InputStream that has no File + byte[] readBuffer = new byte[1024]; + int length = 0; + int readSize; + is.reset(); + while((readSize = is.read(readBuffer, 0, 1024)) != -1){ + length += readSize; + } + // read bpli and st00 from header + is.reset(); + readSize = is.read(readBuffer, 0, 8); + if(readSize != 8){ + throw new IOException("parseHeader: File too small to be a bplist."); + } + int bpli = ((readBuffer[0] & 0xFF) << 24) | ((readBuffer[1] & 0xFF) << 16) | ((readBuffer[2] & 0xFF) << 8) | (readBuffer[3] & 0xFF); + int st00 = ((readBuffer[4] & 0xFF) << 24) | ((readBuffer[5] & 0xFF) << 16) | ((readBuffer[6] & 0xFF) << 8) | (readBuffer[7] & 0xFF); + if ((bpli != 0x62706c69) || (st00 != 0x73743030)) { + throw new IOException("parseHeader: File does not start with 'bplist00' magic."); + } + // read refCount and topLevelOffset from trailer + is.reset(); + is.skip(length - 32); + readSize = is.read(readBuffer, 0, 16); + if(readSize != 16){ + throw new IOException("parseHeader: File too small to be a bplist."); + } + int refCount = ((readBuffer[12] & 0xFF) << 24) | ((readBuffer[13] & 0xFF) << 16) | ((readBuffer[14] & 0xFF) << 8) | (readBuffer[15] & 0xFF); + readSize = is.read(readBuffer, 0, 16); + if(readSize != 16){ + throw new IOException("parseHeader: File too small to be a bplist."); + } + int topLevelOffset = ((readBuffer[12] & 0xFF) << 24) | ((readBuffer[13] & 0xFF) << 16) | ((readBuffer[14] & 0xFF) << 8) | (readBuffer[15] & 0xFF); + + is.reset(); + is.skip(8); + // read all to memory + byte[] buf = new byte[topLevelOffset - 8]; + readSize = is.read(buf, 0, topLevelOffset - 8); + if(readSize != (topLevelOffset - 8)){ + throw new IOException("parseHeader: File too small to be a bplist."); + } + ByteArrayInputStream stream = new ByteArrayInputStream(buf); + + return parseObjectTable(new DataInputStream(stream), refCount); + + } + /** * Object Formats (marker byte followed by additional info in some cases) *
    diff --git a/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java b/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java index af7db49..a191edd 100644 --- a/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java +++ b/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java @@ -1,6 +1,9 @@ package nl.pvanassen.bplist; import java.io.IOException; +import java.io.FileInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; import java.util.List; import nl.pvanassen.bplist.converter.ConvertToXml; @@ -20,12 +23,28 @@ private void test(String baseName) throws IOException { assertNotNull(xmlElement); assertEquals(FileHelper.getContent(baseName + ".result"), xmlElement.getChildren().get(0).toString()); } + + private void testInputStreamMode(String baseName) throws IOException { + //List> elements = elementParser.parseObjectTable(new FileInputStream(FileHelper.getFile(baseName + ".bplist"))); + byte[] copyBuffer = new Byte[1024]; + int copySize = 0; + FileInputStream testFile = new FileInputStream(FileHelper.getFile(baseName + ".bplist")); + ByteArrayOutputStream memory = new ByteArrayOutputStream(); + while((copySize = testFile.read(copyBuffer, 0, 1024)) != 0){ + memory.write(copyBuffer, 0, copySize); + } + testFile.close(); + ByteArrayInputStream memoryStream = new ByteArrayInputStream(memory.toByteArray()); + XMLElement xmlElement = convetToXml.convertToXml(memoryStream); + assertNotNull(xmlElement); + assertEquals(FileHelper.getContent(baseName + ".result"), xmlElement.getChildren().get(0).toString()); + } @Test public void testAirplay() throws IOException { test("airplay"); } - + @Test public void testITunesSmall() throws IOException { test("iTunes-small"); @@ -48,5 +67,32 @@ public void testUID() throws IOException { public void testUTF16() throws IOException { test("utf16"); } + + @Test + public void testInputStreamModeAirPlay() throws IOException { + testInputStream("airplay"); + } + + @Test + public void testInputStreamModeITunesSmall() throws IOException { + testInputStreamMode("iTunes-small"); + } + @Test + public void testInputStreamModeSample1() throws IOException { + testInputStreamMode("sample1"); + } + + @Test + public void testInputStreamModeSample2() throws IOException { + testInputStreamMode("sample2"); + } + @Test + public void testInputStreamModeUID() throws IOException { + testInputStreamMode("uid"); + } + @Test + public void testInputStreamModeUTF16() throws IOException { + testInputStreamMode("utf16"); + } } From b5c7cae52be8145b5e94e28044ca97f71ae91794 Mon Sep 17 00:00:00 2001 From: Kethen Date: Wed, 23 Aug 2017 05:09:10 +0800 Subject: [PATCH 2/3] type in test case --- src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java b/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java index a191edd..37b3274 100644 --- a/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java +++ b/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java @@ -26,7 +26,7 @@ private void test(String baseName) throws IOException { private void testInputStreamMode(String baseName) throws IOException { //List> elements = elementParser.parseObjectTable(new FileInputStream(FileHelper.getFile(baseName + ".bplist"))); - byte[] copyBuffer = new Byte[1024]; + byte[] copyBuffer = new byte[1024]; int copySize = 0; FileInputStream testFile = new FileInputStream(FileHelper.getFile(baseName + ".bplist")); ByteArrayOutputStream memory = new ByteArrayOutputStream(); @@ -70,7 +70,7 @@ public void testUTF16() throws IOException { @Test public void testInputStreamModeAirPlay() throws IOException { - testInputStream("airplay"); + testInputStreamMode("airplay"); } @Test From 356e2707f434a18e0a737192e812a7863980bfd8 Mon Sep 17 00:00:00 2001 From: Kethen Date: Wed, 23 Aug 2017 05:14:12 +0800 Subject: [PATCH 3/3] type in test case --- src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java b/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java index 37b3274..736b1c2 100644 --- a/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java +++ b/src/test/java/nl/pvanassen/bplist/BinaryPListParserTest.java @@ -30,7 +30,7 @@ private void testInputStreamMode(String baseName) throws IOException { int copySize = 0; FileInputStream testFile = new FileInputStream(FileHelper.getFile(baseName + ".bplist")); ByteArrayOutputStream memory = new ByteArrayOutputStream(); - while((copySize = testFile.read(copyBuffer, 0, 1024)) != 0){ + while((copySize = testFile.read(copyBuffer, 0, 1024)) != -1){ memory.write(copyBuffer, 0, copySize); } testFile.close();