blob: e6ce6610f5ec587ac6a1f708fb6b813c99e44e62 [file] [log] [blame]
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.poifs.property;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.POIFSStream;
import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.poifs.storage.RawDataUtil;
import org.junit.jupiter.api.Test;
/**
* Class to test PropertyTable functionality
*/
final class TestPropertyTable {
private static void confirmBlockEncoding(String expectedDataStr, PropertyTable table) throws IOException {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] expectedData = RawDataUtil.decompress(expectedDataStr);
POIFSStream stream = new POIFSStream(null) {
@Override
public OutputStream getOutputStream() {
return bos;
}
};
table.write(stream);
assertArrayEquals(expectedData, bos.toByteArray());
}
/**
* Test PropertyTable
* <p>
* Running individual tests of the PropertyTable methods, which is the
* traditional way to write unit tests (at least for me), seems somewhat
* useless in this case. Of greater relevance: if one follows the normal
* steps of creating a PropertyTable, and then checking the output, does it
* make sense? In other words, more of an integration test.
* <p>
* So, the test consists of creating a PropertyTable instance, adding three
* DocumentProperty instances to it, and then getting the output (including
* the preWrite phase first), and comparing it against a real property table
* extracted from a file known to be acceptable to Excel.
*/
@Test
void testWriterPropertyTable() throws IOException {
// create the PropertyTable
HeaderBlock headerBlock = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
PropertyTable table = new PropertyTable(headerBlock);
// create three DocumentProperty instances and add them to the
// PropertyTable
DocumentProperty workbook = new DocumentProperty("Workbook", 0x00046777);
workbook.setStartBlock(0);
DocumentProperty summary1 = new DocumentProperty(SummaryInformation.DEFAULT_STREAM_NAME, 0x00001000);
summary1.setStartBlock(0x00000234);
DocumentProperty summary2 = new DocumentProperty(DocumentSummaryInformation.DEFAULT_STREAM_NAME, 0x00001000);
summary2.setStartBlock(0x0000023C);
table.addProperty(workbook);
RootProperty root = table.getRoot();
root.addChild(workbook);
table.addProperty(summary1);
root = table.getRoot();
root.addChild(summary1);
table.addProperty(summary2);
root = table.getRoot();
root.addChild(summary2);
table.preWrite();
final String testblock =
"H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FTETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJgfJ0FjDN" +
"yhDMUMqQC4SJYL97AkMhDewmkEgJQyaQnYfHHA2g/YxAmhmIibXfBBRQAgxQ+12ANiSD3ZAKjgHS3GNBhv9tkOwHAFGXmbcAAgAA";
confirmBlockEncoding(testblock, table);
table.removeProperty(summary1);
root = table.getRoot();
root.deleteChild(summary1);
table.preWrite();
final String testblock2 =
"H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FTETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJ" +
"gfJ0FjDNyuACtDeZoZQhlyEVHALBYHYuQyI4LDyBYmlgN4JEShgygew8JHMsgPYzAmlS7LcBBZQAhA0Ae5Y5UIABAAA=";
// (N)POIFS only returns 384 bytes here, instead of 512
confirmBlockEncoding(testblock2, table);
table.addProperty(summary1);
root = table.getRoot();
root.addChild(summary1);
table.preWrite();
final String testblock3 =
"H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FzETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJgfJ0FjDNyu" +
"ACtDeZoZQhlyEVHALBYHYuQyI4LDyBYmlgN4JEShgygew8JHMsyLDfhglICDBA7SfNPnSgAbSfEUiDjCTWfhMk+wEk2TJjAAIAAA==";
confirmBlockEncoding(testblock3, table);
}
@Test
void testReadingConstructor() throws IOException {
// first, we need the raw data blocks
String raw_data_array =
"H4sIAAAAAAAAAO2Z608TQRDA5wqVlreIyFMP5AMaMUAMMcYvQIVoUAivxI9HOeCkpaS9GvjmX67OzO61S1930zOpJJ2muUd" +
"u9zfv3V4PoIAfH2z4BNd4LMIdSGQCktYfLVbEMf34/dWnzjPgggM55H9G/jnqUoQ83vHBw/Pr0LkWwKrwn4o0V7INx6iDDT" +
"vI9eBMrMdrSDB/GM/pKOVncPYynKIHXGQH3vCQeKF1OcOrLGtCOtXKmuanhfxefdyCS5w/x5bvI72ILJczwUEN3MrdPD7l4" +
"8fFJ01Z1/w+Ad+6x3eQRswcfqr+tjEyLvO38c4tc204Ye+U8SqQD5r/SMBPGPxjtOwU7Qv4Nuyy96+ghOcO+5984OB1iT1z" +
"wf4o6fEfNT+QKHxTwu1vFJWqvNf8pMD+HsN+le0Oz03556FlWc5Jdad19AHeaX6vgN8LkvhvoS5FjhA9V9udAn5KwCdf6fY" +
"Dezi7jxmgLKZYHyHLgZ+sEXnEYbtLTeZ6o/kDAj7l6rw+30RuiTPO5Qyz4QvfIT+cVyq/eQ96q/k9Aj7ZHjX+9RXX2P4hAT" +
"9l8PeQcsk5ZnMuFLkPq+tDPGZ13wvzf7+Anzb439A26gCKWEBftKr2egn6/6CA32/wD9m/Lkd+g7PcYU8UMBeb+dwUG/mzm" +
"h2VPwCN/X+Ax3OjDlzsu37IXIvIfybkDxr8r2jvLUY8z3GgmFOPu6t0Ho890VyWtP/HIbr/h8CMv8t5TrarLhfe8xrxnwj4" +
"wwa/8Zqr8vA7V0IuEj8h4I+AaT/1lzJnXsA94Tr0Iu3CAv6YgD/Kdiup339lOBvIHyVNb159ik/zPRbwSdfA/ur+M8NVmGU" +
"9bgT7z4Q1BbL8p1xJ6/MjzLwTrPz2978Ja1LIp1qp5l+RmWqVU50nr/3vt/R8lT8h5JsS8DzuuMHaH7bq3OePCPn0OyGs/0" +
"SVaeTbQj75K6nPq/nXep/TTGaRPyfkU78O9j9busIoB3yu+erqEx59tf7MCPmm1O9/jtD2m0hrHwnZPy3kU73U17+MG8g48" +
"l8K+VNgrv9l7v+X3HMv2uLPC/nTBn+DmarWbV4N8iIdJpH/QsifMfjbbLcby//PhfxZuO//U+OXt1TGkL8o5M+B6f9drDdZ" +
"zZlC9i8I+aaofQ/F4ErMJhmN+fs3rgT7ni6/PX7teKnEHZ/q8Pj4+vfAzuZ+jPFzsLTxanV9eS/rL6+trKzafsE2LkPHP3T" +
"/Pezx8evH6rj+Kd0H/sVRzp+MaX8Sfjh5t9Tm+M7nrwVhNd56fNz+063/OOPj2t9p+R3zS+9d2hnXlf9DLN27g/+E6L0E/T" +
"/Rp/t5WseX3hnTe9uhmnh35WHLX544XEIAIAAA";
// Fake up a header
HeaderBlock header_block = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
header_block.setPropertyStart(0);
List<ByteBuffer> data_blocks = new ArrayList<>();
try (InputStream is = new ByteArrayInputStream(RawDataUtil.decompress(raw_data_array))) {
byte[] buf = new byte[header_block.getBigBlockSize().getBigBlockSize()];
for (int readBytes; (readBytes = is.read(buf)) != -1; ) {
data_blocks.add(ByteBuffer.wrap(buf.clone(), 0, readBytes));
}
}
// get property table from the document
PropertyTable table = new PropertyTable(header_block, data_blocks);
assertEquals(30 * 64, table.getRoot().getSize());
int count = 0;
Property lastChild = null;
for (Property p : table.getRoot()) {
assertNotNull(p);
lastChild = p;
++count;
}
assertNotNull(lastChild, "no children found");
assertEquals(1, count);
assertTrue(lastChild.isDirectory());
count = 0;
for (Property p : (DirectoryProperty) lastChild) {
assertNotNull(p);
++count;
}
assertEquals(35, count);
}
}