1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752 |
- /* ====================================================================
- 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.filesystem;
-
- import static org.apache.poi.POIDataSamples.writeOutAndReadBack;
- import static org.hamcrest.CoreMatchers.hasItem;
- import static org.hamcrest.MatcherAssert.assertThat;
- import static org.hamcrest.core.IsEqual.equalTo;
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import static org.junit.jupiter.api.Assertions.assertFalse;
- import static org.junit.jupiter.api.Assertions.assertNotNull;
- import static org.junit.jupiter.api.Assertions.assertNull;
- import static org.junit.jupiter.api.Assertions.assertThrows;
- import static org.junit.jupiter.api.Assertions.assertTrue;
- import static org.junit.jupiter.api.Assertions.fail;
- import static org.junit.jupiter.api.Assumptions.assumeTrue;
-
- import java.io.ByteArrayInputStream;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.nio.ByteBuffer;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.List;
- import java.util.NoSuchElementException;
- import java.util.function.Function;
-
- import org.apache.commons.collections4.CollectionUtils;
- import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
- import org.apache.poi.POIDataSamples;
- import org.apache.poi.hpsf.DocumentSummaryInformation;
- import org.apache.poi.hpsf.NoPropertySetStreamException;
- import org.apache.poi.hpsf.PropertySet;
- import org.apache.poi.hpsf.PropertySetFactory;
- import org.apache.poi.hpsf.SummaryInformation;
- import org.apache.poi.poifs.common.POIFSConstants;
- import org.apache.poi.poifs.property.DirectoryProperty;
- import org.apache.poi.poifs.property.Property;
- import org.apache.poi.poifs.property.PropertyTable;
- import org.apache.poi.poifs.property.RootProperty;
- import org.apache.poi.poifs.storage.BATBlock;
- import org.apache.poi.poifs.storage.HeaderBlock;
- import org.apache.poi.util.IOUtils;
- import org.apache.poi.util.TempFile;
- import org.junit.jupiter.api.Disabled;
- import org.junit.jupiter.api.Test;
- import org.junit.jupiter.params.ParameterizedTest;
- import org.junit.jupiter.params.provider.Arguments;
- import org.junit.jupiter.params.provider.MethodSource;
-
- /**
- * Tests {@link POIFSStream}
- */
- final class TestPOIFSStream {
- private static final POIDataSamples _inst = POIDataSamples.getPOIFSInstance();
-
- /**
- * Read a single block stream
- */
- @Test
- void testReadTinyStream() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi"))) {
-
- // 98 is actually the last block in a two block stream...
- POIFSStream stream = new POIFSStream(fs, 98);
- Iterator<ByteBuffer> i = stream.getBlockIterator();
- assertTrue(i.hasNext());
- ByteBuffer b = i.next();
- assertFalse(i.hasNext());
-
- // Check the contents
- assertEquals((byte) 0x81, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x82, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- }
- }
-
- /**
- * Read a stream with only two blocks in it
- */
- @Test
- void testReadShortStream() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi"))) {
-
- // 97 -> 98 -> end
- POIFSStream stream = new POIFSStream(fs, 97);
- Iterator<ByteBuffer> i = stream.getBlockIterator();
- assertTrue(i.hasNext());
- ByteBuffer b97 = i.next();
- assertTrue(i.hasNext());
- ByteBuffer b98 = i.next();
- assertFalse(i.hasNext());
-
- // Check the contents of the 1st block
- assertEquals((byte) 0x01, b97.get());
- assertEquals((byte) 0x00, b97.get());
- assertEquals((byte) 0x00, b97.get());
- assertEquals((byte) 0x00, b97.get());
- assertEquals((byte) 0x02, b97.get());
- assertEquals((byte) 0x00, b97.get());
- assertEquals((byte) 0x00, b97.get());
- assertEquals((byte) 0x00, b97.get());
-
- // Check the contents of the 2nd block
- assertEquals((byte) 0x81, b98.get());
- assertEquals((byte) 0x00, b98.get());
- assertEquals((byte) 0x00, b98.get());
- assertEquals((byte) 0x00, b98.get());
- assertEquals((byte) 0x82, b98.get());
- assertEquals((byte) 0x00, b98.get());
- assertEquals((byte) 0x00, b98.get());
- assertEquals((byte) 0x00, b98.get());
- }
- }
-
- /**
- * Read a stream with many blocks
- */
- @Test
- void testReadLongerStream() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi"))) {
-
- ByteBuffer b0 = null;
- ByteBuffer b1 = null;
- ByteBuffer b22 = null;
-
- // The stream at 0 has 23 blocks in it
- POIFSStream stream = new POIFSStream(fs, 0);
- Iterator<ByteBuffer> i = stream.getBlockIterator();
- int count = 0;
- while (i.hasNext()) {
- ByteBuffer b = i.next();
- if (count == 0) {
- b0 = b;
- }
- if (count == 1) {
- b1 = b;
- }
- if (count == 22) {
- b22 = b;
- }
-
- count++;
- }
- assertEquals(23, count);
-
- // Check the contents
- // 1st block is at 0
- assertNotNull(b0);
- assertEquals((byte) 0x9e, b0.get());
- assertEquals((byte) 0x75, b0.get());
- assertEquals((byte) 0x97, b0.get());
- assertEquals((byte) 0xf6, b0.get());
-
- // 2nd block is at 1
- assertNotNull(b1);
- assertEquals((byte) 0x86, b1.get());
- assertEquals((byte) 0x09, b1.get());
- assertEquals((byte) 0x22, b1.get());
- assertEquals((byte) 0xfb, b1.get());
-
- // last block is at 89
- assertNotNull(b22);
- assertEquals((byte) 0xfe, b22.get());
- assertEquals((byte) 0xff, b22.get());
- assertEquals((byte) 0x00, b22.get());
- assertEquals((byte) 0x00, b22.get());
- assertEquals((byte) 0x05, b22.get());
- assertEquals((byte) 0x01, b22.get());
- assertEquals((byte) 0x02, b22.get());
- assertEquals((byte) 0x00, b22.get());
- }
- }
-
- /**
- * Read a stream with several blocks in a 4096 byte block file
- */
- @Test
- void testReadStream4096() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize4096.zvi"))) {
- // 0 -> 1 -> 2 -> end
- POIFSStream stream = new POIFSStream(fs, 0);
- Iterator<ByteBuffer> i = stream.getBlockIterator();
- assertTrue(i.hasNext());
- ByteBuffer b0 = i.next();
- assertTrue(i.hasNext());
- ByteBuffer b1 = i.next();
- assertTrue(i.hasNext());
- ByteBuffer b2 = i.next();
- assertFalse(i.hasNext());
-
- // Check the contents of the 1st block
- assertEquals((byte) 0x9E, b0.get());
- assertEquals((byte) 0x75, b0.get());
- assertEquals((byte) 0x97, b0.get());
- assertEquals((byte) 0xF6, b0.get());
- assertEquals((byte) 0xFF, b0.get());
- assertEquals((byte) 0x21, b0.get());
- assertEquals((byte) 0xD2, b0.get());
- assertEquals((byte) 0x11, b0.get());
-
- // Check the contents of the 2nd block
- assertEquals((byte) 0x00, b1.get());
- assertEquals((byte) 0x00, b1.get());
- assertEquals((byte) 0x03, b1.get());
- assertEquals((byte) 0x00, b1.get());
- assertEquals((byte) 0x00, b1.get());
- assertEquals((byte) 0x00, b1.get());
- assertEquals((byte) 0x00, b1.get());
- assertEquals((byte) 0x00, b1.get());
-
- // Check the contents of the 3rd block
- assertEquals((byte) 0x6D, b2.get());
- assertEquals((byte) 0x00, b2.get());
- assertEquals((byte) 0x00, b2.get());
- assertEquals((byte) 0x00, b2.get());
- assertEquals((byte) 0x03, b2.get());
- assertEquals((byte) 0x00, b2.get());
- assertEquals((byte) 0x46, b2.get());
- assertEquals((byte) 0x00, b2.get());
- }
- }
-
- /**
- * Craft a nasty file with a loop, and ensure we don't get stuck
- */
- @Test
- void testReadFailsOnLoop() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi"))) {
- // Hack the FAT so that it goes 0->1->2->0
- fs.setNextBlock(0, 1);
- fs.setNextBlock(1, 2);
- fs.setNextBlock(2, 0);
-
- // Now try to read
- POIFSStream stream = new POIFSStream(fs, 0);
- Iterator<ByteBuffer> i = stream.getBlockIterator();
- assertTrue(i.hasNext());
-
- // 1st read works
- i.next();
- assertTrue(i.hasNext());
-
- // 2nd read works
- i.next();
- assertTrue(i.hasNext());
-
- // 3rd read works
- i.next();
- assertTrue(i.hasNext());
-
- // 4th read blows up as it loops back to 0
- assertThrows(RuntimeException.class, i::next, "Loop should have been detected but wasn't!");
- assertTrue(i.hasNext());
- }
- }
-
- /**
- * Tests that we can load some streams that are
- * stored in the mini stream.
- */
- @Test
- void testReadMiniStreams() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"))) {
- POIFSMiniStore ministore = fs.getMiniStore();
-
- // 178 -> 179 -> 180 -> end
- POIFSStream stream = new POIFSStream(ministore, 178);
- Iterator<ByteBuffer> i = stream.getBlockIterator();
- assertTrue(i.hasNext());
- ByteBuffer b178 = i.next();
- assertTrue(i.hasNext());
- ByteBuffer b179 = i.next();
- assertTrue(i.hasNext());
- ByteBuffer b180 = i.next();
- assertFalse(i.hasNext());
-
- // Check the contents of the 1st block
- assertEquals((byte) 0xfe, b178.get());
- assertEquals((byte) 0xff, b178.get());
- assertEquals((byte) 0x00, b178.get());
- assertEquals((byte) 0x00, b178.get());
- assertEquals((byte) 0x05, b178.get());
- assertEquals((byte) 0x01, b178.get());
- assertEquals((byte) 0x02, b178.get());
- assertEquals((byte) 0x00, b178.get());
-
- // And the 2nd
- assertEquals((byte) 0x6c, b179.get());
- assertEquals((byte) 0x00, b179.get());
- assertEquals((byte) 0x00, b179.get());
- assertEquals((byte) 0x00, b179.get());
- assertEquals((byte) 0x28, b179.get());
- assertEquals((byte) 0x00, b179.get());
- assertEquals((byte) 0x00, b179.get());
- assertEquals((byte) 0x00, b179.get());
-
- // And the 3rd
- assertEquals((byte) 0x30, b180.get());
- assertEquals((byte) 0x00, b180.get());
- assertEquals((byte) 0x00, b180.get());
- assertEquals((byte) 0x00, b180.get());
- assertEquals((byte) 0x00, b180.get());
- assertEquals((byte) 0x00, b180.get());
- assertEquals((byte) 0x00, b180.get());
- assertEquals((byte) 0x80, b180.get());
- }
- }
-
- /**
- * Writing the same amount of data as before
- */
- @Test
- void testReplaceStream() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"))) {
-
- byte[] data = new byte[512];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i % 256);
- }
-
- // 98 is actually the last block in a two block stream...
- POIFSStream stream = new POIFSStream(fs, 98);
- stream.updateContents(data);
-
- // Check the reading of blocks
- Iterator<ByteBuffer> it = stream.getBlockIterator();
- assertTrue(it.hasNext());
- ByteBuffer b = it.next();
- assertFalse(it.hasNext());
-
- // Now check the contents
- data = new byte[512];
- b.get(data);
- for (int i = 0; i < data.length; i++) {
- byte exp = (byte) (i % 256);
- assertEquals(exp, data[i]);
- }
- }
- }
-
- /**
- * Writes less data than before, some blocks will need
- * to be freed
- */
- @Test
- void testReplaceStreamWithLess() throws Exception {
- try (InputStream is = _inst.openResourceAsStream("BlockSize512.zvi");
- POIFSFileSystem fs = new POIFSFileSystem(is)) {
-
- byte[] data = new byte[512];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i % 256);
- }
-
- // 97 -> 98 -> end
- assertEquals(98, fs.getNextBlock(97));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
-
- // Create a 2 block stream, will become a 1 block one
- POIFSStream stream = new POIFSStream(fs, 97);
- stream.updateContents(data);
-
- // 97 should now be the end, and 98 free
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(97));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(98));
-
- // Check the reading of blocks
- Iterator<ByteBuffer> it = stream.getBlockIterator();
- assertTrue(it.hasNext());
- ByteBuffer b = it.next();
- assertFalse(it.hasNext());
-
- // Now check the contents
- data = new byte[512];
- b.get(data);
- for (int i = 0; i < data.length; i++) {
- byte exp = (byte) (i % 256);
- assertEquals(exp, data[i]);
- }
- }
- }
-
- /**
- * Writes more data than before, new blocks will be needed
- */
- @Test
- void testReplaceStreamWithMore() throws Exception {
- try (InputStream is = _inst.openResourceAsStream("BlockSize512.zvi");
- POIFSFileSystem fs = new POIFSFileSystem(is)) {
-
- byte[] data = new byte[512 * 3];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i % 256);
- }
-
- // 97 -> 98 -> end
- assertEquals(98, fs.getNextBlock(97));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
-
- // 100 is our first free one
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100));
-
- // Create a 2 block stream, will become a 3 block one
- POIFSStream stream = new POIFSStream(fs, 97);
- stream.updateContents(data);
-
- // 97 -> 98 -> 100 -> end
- assertEquals(98, fs.getNextBlock(97));
- assertEquals(100, fs.getNextBlock(98));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100));
-
- // Check the reading of blocks
- Iterator<ByteBuffer> it = stream.getBlockIterator();
- int count = 0;
- while (it.hasNext()) {
- ByteBuffer b = it.next();
- data = new byte[512];
- b.get(data);
- for (int i = 0; i < data.length; i++) {
- byte exp = (byte) (i % 256);
- assertEquals(exp, data[i]);
- }
- count++;
- }
- assertEquals(3, count);
- }
- }
-
- /**
- * Writes to a new stream in the file
- */
- @Test
- void testWriteNewStream() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"))) {
-
- // 100 is our first free one
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(101));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(102));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(103));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(104));
-
-
- // Add a single block one
- byte[] data = new byte[512];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i % 256);
- }
-
- POIFSStream stream = new POIFSStream(fs);
- stream.updateContents(data);
-
- // Check it was allocated properly
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(101));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(102));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(103));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(104));
-
- // And check the contents
- Iterator<ByteBuffer> it = stream.getBlockIterator();
- int count = 0;
- while (it.hasNext()) {
- ByteBuffer b = it.next();
- data = new byte[512];
- b.get(data);
- for (int i = 0; i < data.length; i++) {
- byte exp = (byte) (i % 256);
- assertEquals(exp, data[i]);
- }
- count++;
- }
- assertEquals(1, count);
-
-
- // And a multi block one
- data = new byte[512 * 3];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i % 256);
- }
-
- stream = new POIFSStream(fs);
- stream.updateContents(data);
-
- // Check it was allocated properly
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100));
- assertEquals(102, fs.getNextBlock(101));
- assertEquals(103, fs.getNextBlock(102));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(103));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(104));
-
- // And check the contents
- it = stream.getBlockIterator();
- count = 0;
- while (it.hasNext()) {
- ByteBuffer b = it.next();
- data = new byte[512];
- b.get(data);
- for (int i = 0; i < data.length; i++) {
- byte exp = (byte) (i % 256);
- assertEquals(exp, data[i]);
- }
- count++;
- }
- assertEquals(3, count);
-
- // Free it
- stream.free();
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(101));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(102));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(103));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(104));
- }
- }
-
- /**
- * Writes to a new stream in the file, where we've not enough
- * free blocks so new FAT segments will need to be allocated
- * to support this
- */
- @Test
- void testWriteNewStreamExtraFATs() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"))) {
-
- // Allocate almost all the blocks
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(127));
- for (int i = 100; i < 127; i++) {
- fs.setNextBlock(i, POIFSConstants.END_OF_CHAIN);
- }
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(127));
- assertTrue(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
-
-
- // Write a 3 block stream
- byte[] data = new byte[512 * 3];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i % 256);
- }
- POIFSStream stream = new POIFSStream(fs);
- stream.updateContents(data);
-
- // Check we got another BAT
- assertFalse(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
- assertTrue(fs.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
-
- // the BAT will be in the first spot of the new block
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(126));
- assertEquals(129, fs.getNextBlock(127));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(128));
- assertEquals(130, fs.getNextBlock(129));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(130));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(131));
- }
- }
-
- /**
- * Replaces data in an existing stream, with a bit
- * more data than before, in a 4096 byte block file
- */
- @Test
- void testWriteStream4096() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"))) {
-
- // 0 -> 1 -> 2 -> end
- assertEquals(1, fs.getNextBlock(0));
- assertEquals(2, fs.getNextBlock(1));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
- assertEquals(4, fs.getNextBlock(3));
-
- // First free one is at 15
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(14));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(15));
-
-
- // Write a 5 block file
- byte[] data = new byte[4096 * 5];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i % 256);
- }
- POIFSStream stream = new POIFSStream(fs, 0);
- stream.updateContents(data);
-
-
- // Check it
- assertEquals(1, fs.getNextBlock(0));
- assertEquals(2, fs.getNextBlock(1));
- assertEquals(15, fs.getNextBlock(2)); // Jumps
- assertEquals(4, fs.getNextBlock(3)); // Next stream
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(14));
- assertEquals(16, fs.getNextBlock(15)); // Continues
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(16)); // Ends
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(17)); // Free
-
- // Check the contents too
- Iterator<ByteBuffer> it = stream.getBlockIterator();
- int count = 0;
- while (it.hasNext()) {
- ByteBuffer b = it.next();
- data = new byte[512];
- b.get(data);
- for (int i = 0; i < data.length; i++) {
- byte exp = (byte) (i % 256);
- assertEquals(exp, data[i]);
- }
- count++;
- }
- assertEquals(5, count);
- }
- }
-
- /**
- * Tests that we can write into the mini stream
- */
- @Test
- void testWriteMiniStreams() throws Exception {
- try (InputStream is = _inst.openResourceAsStream("BlockSize512.zvi");
- POIFSFileSystem fs = new POIFSFileSystem(is)) {
-
- POIFSMiniStore ministore = fs.getMiniStore();
-
- // 178 -> 179 -> 180 -> end
- assertEquals(179, ministore.getNextBlock(178));
- assertEquals(180, ministore.getNextBlock(179));
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180));
-
-
- // Try writing 3 full blocks worth
- byte[] data = new byte[64 * 3];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) i;
- }
- POIFSStream stream = new POIFSStream(ministore, 178);
- stream.updateContents(data);
-
- // Check
- assertEquals(179, ministore.getNextBlock(178));
- assertEquals(180, ministore.getNextBlock(179));
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180));
-
- stream = new POIFSStream(ministore, 178);
- Iterator<ByteBuffer> it = stream.getBlockIterator();
- ByteBuffer b178 = it.next();
- ByteBuffer b179 = it.next();
- ByteBuffer b180 = it.next();
- assertFalse(it.hasNext());
-
- assertEquals((byte) 0x00, b178.get());
- assertEquals((byte) 0x01, b178.get());
- assertEquals((byte) 0x40, b179.get());
- assertEquals((byte) 0x41, b179.get());
- assertEquals((byte) 0x80, b180.get());
- assertEquals((byte) 0x81, b180.get());
-
-
- // Try writing just into 3 blocks worth
- data = new byte[64 * 2 + 12];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i + 4);
- }
- stream = new POIFSStream(ministore, 178);
- stream.updateContents(data);
-
- // Check
- assertEquals(179, ministore.getNextBlock(178));
- assertEquals(180, ministore.getNextBlock(179));
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180));
-
- stream = new POIFSStream(ministore, 178);
- it = stream.getBlockIterator();
- b178 = it.next();
- b179 = it.next();
- b180 = it.next();
- assertFalse(it.hasNext());
-
- assertEquals((byte) 0x04, b178.get(0));
- assertEquals((byte) 0x05, b178.get(1));
- assertEquals((byte) 0x44, b179.get(0));
- assertEquals((byte) 0x45, b179.get(1));
- assertEquals((byte) 0x84, b180.get(0));
- assertEquals((byte) 0x85, b180.get(1));
-
-
- // Try writing 1, should truncate
- data = new byte[12];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i + 9);
- }
- stream = new POIFSStream(ministore, 178);
- stream.updateContents(data);
-
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(178));
- assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(179));
- assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(180));
-
- stream = new POIFSStream(ministore, 178);
- it = stream.getBlockIterator();
- b178 = it.next();
- assertFalse(it.hasNext());
-
- assertEquals((byte) 0x09, b178.get(0));
- assertEquals((byte) 0x0a, b178.get(1));
-
-
- // Try writing 5, should extend
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(178));
- assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(179));
- assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(180));
- assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(181));
- assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(182));
- assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(183));
-
- data = new byte[64 * 4 + 12];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i + 3);
- }
- stream = new POIFSStream(ministore, 178);
- stream.updateContents(data);
-
- assertEquals(179, ministore.getNextBlock(178));
- assertEquals(180, ministore.getNextBlock(179));
- assertEquals(181, ministore.getNextBlock(180));
- assertEquals(182, ministore.getNextBlock(181));
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(182));
-
- stream = new POIFSStream(ministore, 178);
- it = stream.getBlockIterator();
- b178 = it.next();
- b179 = it.next();
- b180 = it.next();
- ByteBuffer b181 = it.next();
- ByteBuffer b182 = it.next();
- assertFalse(it.hasNext());
-
- assertEquals((byte) 0x03, b178.get(0));
- assertEquals((byte) 0x04, b178.get(1));
- assertEquals((byte) 0x43, b179.get(0));
- assertEquals((byte) 0x44, b179.get(1));
- assertEquals((byte) 0x83, b180.get(0));
- assertEquals((byte) 0x84, b180.get(1));
- assertEquals((byte) 0xc3, b181.get(0));
- assertEquals((byte) 0xc4, b181.get(1));
- assertEquals((byte) 0x03, b182.get(0));
- assertEquals((byte) 0x04, b182.get(1));
-
-
- // Write lots, so it needs another big block
- ministore.getBlockAt(183);
- assertThrows(NoSuchElementException.class, () -> ministore.getBlockAt(184), "Block 184 should be off the end of the list");
-
- data = new byte[64 * 6 + 12];
- for (int i = 0; i < data.length; i++) {
- data[i] = (byte) (i + 1);
- }
- stream = new POIFSStream(ministore, 178);
- stream.updateContents(data);
-
- // Should have added 2 more blocks to the chain
- assertEquals(179, ministore.getNextBlock(178));
- assertEquals(180, ministore.getNextBlock(179));
- assertEquals(181, ministore.getNextBlock(180));
- assertEquals(182, ministore.getNextBlock(181));
- assertEquals(183, ministore.getNextBlock(182));
- assertEquals(184, ministore.getNextBlock(183));
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(184));
- assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(185));
-
- // Block 184 should exist
- ministore.getBlockAt(183);
- ministore.getBlockAt(184);
- ministore.getBlockAt(185);
-
- // Check contents
- stream = new POIFSStream(ministore, 178);
- it = stream.getBlockIterator();
- b178 = it.next();
- b179 = it.next();
- b180 = it.next();
- b181 = it.next();
- b182 = it.next();
- ByteBuffer b183 = it.next();
- ByteBuffer b184 = it.next();
- assertFalse(it.hasNext());
-
- assertEquals((byte) 0x01, b178.get(0));
- assertEquals((byte) 0x02, b178.get(1));
- assertEquals((byte) 0x41, b179.get(0));
- assertEquals((byte) 0x42, b179.get(1));
- assertEquals((byte) 0x81, b180.get(0));
- assertEquals((byte) 0x82, b180.get(1));
- assertEquals((byte) 0xc1, b181.get(0));
- assertEquals((byte) 0xc2, b181.get(1));
- assertEquals((byte) 0x01, b182.get(0));
- assertEquals((byte) 0x02, b182.get(1));
- assertEquals((byte) 0x41, b183.get(0));
- assertEquals((byte) 0x42, b183.get(1));
- assertEquals((byte) 0x81, b184.get(0));
- assertEquals((byte) 0x82, b184.get(1));
-
- }
- }
-
- /**
- * Craft a nasty file with a loop, and ensure we don't get stuck
- */
- @Test
- void testWriteFailsOnLoop() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi"))) {
-
- // Hack the FAT so that it goes 0->1->2->0
- fs.setNextBlock(0, 1);
- fs.setNextBlock(1, 2);
- fs.setNextBlock(2, 0);
-
- // Try to write a large amount, should fail on the write
- POIFSStream stream1 = new POIFSStream(fs, 0);
- assertThrows(IllegalStateException.class,
- () -> stream1.updateContents(new byte[512 * 4]), "Loop should have been detected but wasn't!");
-
- // Now reset, and try on a small bit
- // Should fail during the freeing set
- fs.setNextBlock(0, 1);
- fs.setNextBlock(1, 2);
- fs.setNextBlock(2, 0);
-
- POIFSStream stream2 = new POIFSStream(fs, 0);
- assertThrows(IllegalStateException.class,
- () -> stream2.updateContents(new byte[512]), "Loop should have been detected but wasn't!");
- }
- }
-
- /**
- * Tests adding a new stream, writing and reading it.
- */
- @Test
- void testReadWriteNewStream() throws Exception {
- try (POIFSFileSystem fs = new POIFSFileSystem()) {
- POIFSStream stream = new POIFSStream(fs);
-
- // Check our filesystem has Properties then BAT
- assertEquals(2, fs.getFreeBlock());
- BATBlock bat = fs.getBATBlockAndIndex(0).getBlock();
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(2));
-
- // Check the stream as-is
- assertEquals(POIFSConstants.END_OF_CHAIN, stream.getStartBlock());
- assertThrows(IllegalStateException.class, stream::getBlockIterator,
- "Shouldn't be able to get an iterator before writing");
-
- // Write in two blocks
- byte[] data = new byte[512 + 20];
- for (int i = 0; i < 512; i++) {
- data[i] = (byte) (i % 256);
- }
- for (int i = 512; i < data.length; i++) {
- data[i] = (byte) (i % 256 + 100);
- }
- stream.updateContents(data);
-
- // Check now
- assertEquals(4, fs.getFreeBlock());
- bat = fs.getBATBlockAndIndex(0).getBlock();
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(3, bat.getValueAt(2));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(4));
-
-
- Iterator<ByteBuffer> it = stream.getBlockIterator();
- assertTrue(it.hasNext());
- ByteBuffer b = it.next();
-
- byte[] read = new byte[512];
- b.get(read);
- for (int i = 0; i < read.length; i++) {
- assertEquals(data[i], read[i], "Wrong value at " + i);
- }
-
- assertTrue(it.hasNext());
- b = it.next();
-
- read = new byte[512];
- b.get(read);
- for (int i = 0; i < 20; i++) {
- assertEquals(data[i + 512], read[i]);
- }
- for (int i = 20; i < read.length; i++) {
- assertEquals(0, read[i]);
- }
-
- assertFalse(it.hasNext());
- }
- }
-
- /**
- * Writes a stream, then replaces it
- */
- @Test
- void testWriteThenReplace() throws Exception {
- try (POIFSFileSystem fs1 = new POIFSFileSystem()) {
-
- // Starts empty, other that Properties and BAT
- BATBlock bat = fs1.getBATBlockAndIndex(0).getBlock();
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(2));
-
- // Write something that uses a main stream
- byte[] main4106 = new byte[4106];
- main4106[0] = -10;
- main4106[4105] = -11;
- fs1.getRoot().createDocument("Normal", new ByteArrayInputStream(main4106));
-
- // Should have used 9 blocks
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(3, bat.getValueAt(2));
- assertEquals(4, bat.getValueAt(3));
- assertEquals(5, bat.getValueAt(4));
- assertEquals(6, bat.getValueAt(5));
- assertEquals(7, bat.getValueAt(6));
- assertEquals(8, bat.getValueAt(7));
- assertEquals(9, bat.getValueAt(8));
- assertEquals(10, bat.getValueAt(9));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(10));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11));
-
- DocumentEntry normal = (DocumentEntry) fs1.getRoot().getEntry("Normal");
- assertEquals(4106, normal.getSize());
- assertEquals(4106, ((DocumentNode) normal).getProperty().getSize());
-
-
- // Replace with one still big enough for a main stream, but one block smaller
- byte[] main4096 = new byte[4096];
- main4096[0] = -10;
- main4096[4095] = -11;
-
- try (DocumentOutputStream nout = new DocumentOutputStream(normal)) {
- nout.write(main4096);
- }
-
- // Will have dropped to 8
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(3, bat.getValueAt(2));
- assertEquals(4, bat.getValueAt(3));
- assertEquals(5, bat.getValueAt(4));
- assertEquals(6, bat.getValueAt(5));
- assertEquals(7, bat.getValueAt(6));
- assertEquals(8, bat.getValueAt(7));
- assertEquals(9, bat.getValueAt(8));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(9));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(10));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11));
-
- normal = (DocumentEntry) fs1.getRoot().getEntry("Normal");
- assertEquals(4096, normal.getSize());
- assertEquals(4096, ((DocumentNode) normal).getProperty().getSize());
-
-
- // Write and check
- try (POIFSFileSystem fs2 = writeOutAndReadBack(fs1)) {
- bat = fs2.getBATBlockAndIndex(0).getBlock();
-
- // No change after write
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); // Properties
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(3, bat.getValueAt(2));
- assertEquals(4, bat.getValueAt(3));
- assertEquals(5, bat.getValueAt(4));
- assertEquals(6, bat.getValueAt(5));
- assertEquals(7, bat.getValueAt(6));
- assertEquals(8, bat.getValueAt(7));
- assertEquals(9, bat.getValueAt(8));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(9)); // End of Normal
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(10));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11));
-
- normal = (DocumentEntry) fs2.getRoot().getEntry("Normal");
- assertEquals(4096, normal.getSize());
- assertEquals(4096, ((DocumentNode) normal).getProperty().getSize());
-
-
- // Make longer, take 1 block at the end
- normal = (DocumentEntry) fs2.getRoot().getEntry("Normal");
- try (DocumentOutputStream nout = new DocumentOutputStream(normal)) {
- nout.write(main4106);
- }
-
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(3, bat.getValueAt(2));
- assertEquals(4, bat.getValueAt(3));
- assertEquals(5, bat.getValueAt(4));
- assertEquals(6, bat.getValueAt(5));
- assertEquals(7, bat.getValueAt(6));
- assertEquals(8, bat.getValueAt(7));
- assertEquals(9, bat.getValueAt(8));
- assertEquals(10, bat.getValueAt(9));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(10)); // Normal
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(12));
-
- normal = (DocumentEntry) fs2.getRoot().getEntry("Normal");
- assertEquals(4106, normal.getSize());
- assertEquals(4106, ((DocumentNode) normal).getProperty().getSize());
-
-
- // Make it small, will trigger the SBAT stream and free lots up
- byte[] mini = new byte[]{42, 0, 1, 2, 3, 4, 42};
- normal = (DocumentEntry) fs2.getRoot().getEntry("Normal");
- try (DocumentOutputStream nout = new DocumentOutputStream(normal)) {
- nout.write(mini);
- }
-
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(2)); // SBAT
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3)); // Mini Stream
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(4));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(5));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(6));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(7));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(8));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(9));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(10));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(12));
-
- normal = (DocumentEntry) fs2.getRoot().getEntry("Normal");
- assertEquals(7, normal.getSize());
- assertEquals(7, ((DocumentNode) normal).getProperty().getSize());
-
-
- // Finally back to big again
- try (DocumentOutputStream nout = new DocumentOutputStream(normal)) {
- nout.write(main4096);
- }
-
- // Will keep the mini stream, now empty
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(2)); // SBAT
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3)); // Mini Stream
- assertEquals(5, bat.getValueAt(4));
- assertEquals(6, bat.getValueAt(5));
- assertEquals(7, bat.getValueAt(6));
- assertEquals(8, bat.getValueAt(7));
- assertEquals(9, bat.getValueAt(8));
- assertEquals(10, bat.getValueAt(9));
- assertEquals(11, bat.getValueAt(10));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(11));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(12));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(13));
-
- normal = (DocumentEntry) fs2.getRoot().getEntry("Normal");
- assertEquals(4096, normal.getSize());
- assertEquals(4096, ((DocumentNode) normal).getProperty().getSize());
-
-
- // Save, re-load, re-check
- try (POIFSFileSystem fs3 = writeOutAndReadBack(fs2)) {
- bat = fs3.getBATBlockAndIndex(0).getBlock();
-
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(2)); // SBAT
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3)); // Mini Stream
- assertEquals(5, bat.getValueAt(4));
- assertEquals(6, bat.getValueAt(5));
- assertEquals(7, bat.getValueAt(6));
- assertEquals(8, bat.getValueAt(7));
- assertEquals(9, bat.getValueAt(8));
- assertEquals(10, bat.getValueAt(9));
- assertEquals(11, bat.getValueAt(10));
- assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(11));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(12));
- assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(13));
-
- normal = (DocumentEntry) fs3.getRoot().getEntry("Normal");
- assertEquals(4096, normal.getSize());
- assertEquals(4096, ((DocumentNode) normal).getProperty().getSize());
- }
- }
- }
- }
-
-
- /**
- * Returns test files with 512 byte and 4k block sizes, loaded
- * both from InputStreams and Files
- */
- public static Collection<Arguments> get512and4kFileAndInput() {
- return CollectionUtils.union(get512FileAndInput(), get4kFileAndInput());
- }
-
- public static List<Arguments> get512FileAndInput() {
- return Arrays.asList(
- Arguments.of("BlockSize512.zvi", (Function<String,POIFSFileSystem>)TestPOIFSStream::openAsFile),
- Arguments.of("BlockSize512.zvi", (Function<String,POIFSFileSystem>)TestPOIFSStream::openAsStream)
- );
- }
-
- public static List<Arguments> get4kFileAndInput() {
- return Arrays.asList(
- Arguments.of("BlockSize4096.zvi", (Function<String,POIFSFileSystem>)TestPOIFSStream::openAsFile),
- Arguments.of("BlockSize4096.zvi", (Function<String,POIFSFileSystem>)TestPOIFSStream::openAsStream)
- );
- }
-
- private static POIFSFileSystem openAsFile(String fileName) {
- try {
- return new POIFSFileSystem(_inst.getFile(fileName));
- } catch (IOException e) {
- fail(e);
- return null;
- }
- }
-
- private static POIFSFileSystem openAsStream(String fileName) {
- try {
- return new POIFSFileSystem(_inst.openResourceAsStream(fileName));
- } catch (IOException e) {
- fail(e);
- return null;
- }
- }
-
-
- private static void assertBATCount(POIFSFileSystem fs, int expectedBAT, int expectedXBAT) throws IOException {
- int foundBAT = 0;
- int foundXBAT = 0;
- int sz = (int) (fs.size() / fs.getBigBlockSize());
- for (int i = 0; i < sz; i++) {
- if (fs.getNextBlock(i) == POIFSConstants.FAT_SECTOR_BLOCK) {
- foundBAT++;
- }
- if (fs.getNextBlock(i) == POIFSConstants.DIFAT_SECTOR_BLOCK) {
- foundXBAT++;
- }
- }
- assertEquals(expectedBAT, foundBAT, "Wrong number of BATs");
- assertEquals(expectedXBAT, foundXBAT, "Wrong number of XBATs with " + expectedBAT + " BATs");
- }
-
- private void assertContentsMatches(byte[] expected, DocumentEntry doc) throws IOException {
- DocumentInputStream inp = new DocumentInputStream(doc);
- byte[] contents = new byte[doc.getSize()];
- assertEquals(doc.getSize(), inp.read(contents));
- inp.close();
-
- if (expected != null) {
- assertThat(expected, equalTo(contents));
- }
- }
-
- private static HeaderBlock writeOutAndReadHeader(POIFSFileSystem fs) throws IOException {
- UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream();
- fs.writeFilesystem(baos);
- return new HeaderBlock(baos.toInputStream());
- }
-
- private static POIFSFileSystem writeOutFileAndReadBack(POIFSFileSystem original) throws IOException {
- final File file = TempFile.createTempFile("TestPOIFS", ".ole2");
- try (OutputStream fout = new FileOutputStream(file)) {
- original.writeFilesystem(fout);
- }
- return new POIFSFileSystem(file, false);
- }
-
- @ParameterizedTest()
- @MethodSource("get512FileAndInput")
- void basicOpen512(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- // With a simple 512 block file
- try (POIFSFileSystem fs = opener.apply(file)) {
- assertEquals(512, fs.getBigBlockSize());
- }
- }
-
- @ParameterizedTest()
- @MethodSource("get4kFileAndInput")
- void basicOpen4k(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- // Now with a simple 4096 block file
- try (POIFSFileSystem fs = opener.apply(file)) {
- assertEquals(4096, fs.getBigBlockSize());
- }
- }
-
- @ParameterizedTest()
- @MethodSource("get512FileAndInput")
- void propertiesAndFatOnRead512(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- // With a simple 512 block file
- try (POIFSFileSystem fs = opener.apply(file)) {
- // Check the FAT was properly processed:
- // Verify we only got one block
- fs.getBATBlockAndIndex(0);
- fs.getBATBlockAndIndex(1);
- assertThrows(IndexOutOfBoundsException.class, () -> fs.getBATBlockAndIndex(140),
- "Should only be one BAT, but a 2nd was found");
-
- // Verify a few next offsets
- // 97 -> 98 -> END
- assertEquals(98, fs.getNextBlock(97));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
-
-
- // Check the properties
- PropertyTable props = fs._get_property_table();
- assertEquals(90, props.getStartBlock());
- assertEquals(7, props.countBlocks());
-
- // Root property tells us about the Mini Stream
- RootProperty root = props.getRoot();
- assertEquals("Root Entry", root.getName());
- assertEquals(11564, root.getSize());
- assertEquals(0, root.getStartBlock());
-
- // Check its children too
- Property prop;
- Iterator<Property> pi = root.getChildren();
- prop = pi.next();
- assertEquals("Thumbnail", prop.getName());
- prop = pi.next();
- assertEquals("\u0005DocumentSummaryInformation", prop.getName());
- prop = pi.next();
- assertEquals("\u0005SummaryInformation", prop.getName());
- prop = pi.next();
- assertEquals("Image", prop.getName());
- prop = pi.next();
- assertEquals("Tags", prop.getName());
- assertFalse(pi.hasNext());
-
-
- // Check the SBAT (Small Blocks FAT) was properly processed
- POIFSMiniStore ministore = fs.getMiniStore();
-
- // Verify we only got two SBAT blocks
- ministore.getBATBlockAndIndex(0);
- ministore.getBATBlockAndIndex(128);
- assertThrows(IndexOutOfBoundsException.class, () -> ministore.getBATBlockAndIndex(256),
- "Should only be two SBATs, but a 3rd was found");
-
- // Verify a few offsets: 0->50 is a stream
- for (int i = 0; i < 50; i++) {
- assertEquals(i + 1, ministore.getNextBlock(i));
- }
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50));
- }
- }
-
- @ParameterizedTest()
- @MethodSource("get4kFileAndInput")
- void propertiesAndFatOnRead4k(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- // Now with a simple 4096 block file
- try (POIFSFileSystem fs = opener.apply(file)) {
- // Check the FAT was properly processed
- // Verify we only got one block
- fs.getBATBlockAndIndex(0);
- fs.getBATBlockAndIndex(1);
- assertThrows(IndexOutOfBoundsException.class, () -> fs.getBATBlockAndIndex(1040),
- "Should only be one BAT, but a 2nd was found");
-
- // Verify a few next offsets
- // 0 -> 1 -> 2 -> END
- assertEquals(1, fs.getNextBlock(0));
- assertEquals(2, fs.getNextBlock(1));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
-
-
- // Check the properties
- PropertyTable props = fs._get_property_table();
- assertEquals(12, props.getStartBlock());
- assertEquals(1, props.countBlocks());
-
- // Root property tells us about the Mini Stream
- RootProperty root = props.getRoot();
- assertEquals("Root Entry", root.getName());
- assertEquals(11564, root.getSize());
- assertEquals(0, root.getStartBlock());
-
- // Check its children too
- Property prop;
- Iterator<Property> pi = root.getChildren();
- prop = pi.next();
- assertEquals("Thumbnail", prop.getName());
- prop = pi.next();
- assertEquals("\u0005DocumentSummaryInformation", prop.getName());
- prop = pi.next();
- assertEquals("\u0005SummaryInformation", prop.getName());
- prop = pi.next();
- assertEquals("Image", prop.getName());
- prop = pi.next();
- assertEquals("Tags", prop.getName());
- assertFalse(pi.hasNext());
-
-
- // Check the SBAT (Small Blocks FAT) was properly processed
- POIFSMiniStore ministore = fs.getMiniStore();
-
- // Verify we only got one SBAT block
- ministore.getBATBlockAndIndex(0);
- ministore.getBATBlockAndIndex(128);
- ministore.getBATBlockAndIndex(1023);
- assertThrows(IndexOutOfBoundsException.class, () -> ministore.getBATBlockAndIndex(1024),
- "Should only be one SBAT, but a 2nd was found");
-
- // Verify a few offsets: 0->50 is a stream
- for (int i = 0; i < 50; i++) {
- assertEquals(i + 1, ministore.getNextBlock(i));
- }
- assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50));
- }
- }
-
- /**
- * Check that for a given block, we can correctly figure
- * out what the next one is
- */
- @ParameterizedTest()
- @MethodSource("get512FileAndInput")
- void nextBlock512(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- try (POIFSFileSystem fs = opener.apply(file)) {
- // 0 -> 21 are simple
- for (int i = 0; i < 21; i++) {
- assertEquals(i + 1, fs.getNextBlock(i));
- }
- // 21 jumps to 89, then ends
- assertEquals(89, fs.getNextBlock(21));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(89));
-
- // 22 -> 88 simple sequential stream
- for (int i = 22; i < 88; i++) {
- assertEquals(i + 1, fs.getNextBlock(i));
- }
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(88));
-
- // 90 -> 96 is another stream
- for (int i = 90; i < 96; i++) {
- assertEquals(i + 1, fs.getNextBlock(i));
- }
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(96));
-
- // 97+98 is another
- assertEquals(98, fs.getNextBlock(97));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
-
- // 99 is our FAT block
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
-
- // 100 onwards is free
- for (int i = 100; i < fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) {
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(i));
- }
- }
- }
-
- @ParameterizedTest()
- @MethodSource("get4kFileAndInput")
- void nextBlock4k(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- // Quick check on 4096 byte blocks too
- try (POIFSFileSystem fs = opener.apply(file)) {
- // 0 -> 1 -> 2 -> end
- assertEquals(1, fs.getNextBlock(0));
- assertEquals(2, fs.getNextBlock(1));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
-
- // 4 -> 11 then end
- for (int i = 4; i < 11; i++) {
- assertEquals(i + 1, fs.getNextBlock(i));
- }
- assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(11));
- }
- }
-
- /**
- * Check we get the right data back for each block
- */
- @ParameterizedTest()
- @MethodSource("get512FileAndInput")
- void getBlock512(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- try (POIFSFileSystem fs = opener.apply(file)) {
- // The 0th block is the first data block
- ByteBuffer b = fs.getBlockAt(0);
- assertEquals((byte) 0x9e, b.get());
- assertEquals((byte) 0x75, b.get());
- assertEquals((byte) 0x97, b.get());
- assertEquals((byte) 0xf6, b.get());
-
- // And the next block
- b = fs.getBlockAt(1);
- assertEquals((byte) 0x86, b.get());
- assertEquals((byte) 0x09, b.get());
- assertEquals((byte) 0x22, b.get());
- assertEquals((byte) 0xfb, b.get());
-
- // Check the final block too
- b = fs.getBlockAt(99);
- assertEquals((byte) 0x01, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x02, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- }
- }
-
- @ParameterizedTest()
- @MethodSource("get4kFileAndInput")
- void getBlock4k(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- // Quick check on 4096 byte blocks too
- try (POIFSFileSystem fs = opener.apply(file)) {
- // The 0th block is the first data block
- ByteBuffer b = fs.getBlockAt(0);
- assertEquals((byte) 0x9e, b.get());
- assertEquals((byte) 0x75, b.get());
- assertEquals((byte) 0x97, b.get());
- assertEquals((byte) 0xf6, b.get());
-
- // And the next block
- b = fs.getBlockAt(1);
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x03, b.get());
- assertEquals((byte) 0x00, b.get());
-
- // The 14th block is the FAT
- b = fs.getBlockAt(14);
- assertEquals((byte) 0x01, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x02, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- assertEquals((byte) 0x00, b.get());
- }
- }
-
- /**
- * Ask for free blocks where there are some already
- * to be had from the FAT
- */
- @Test
- void getFreeBlockWithSpare() throws IOException {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi"))) {
- // Our first BAT block has spares
- assertTrue(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
-
- // First free one is 100
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(101));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(102));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(103));
-
- // Ask, will get 100
- assertEquals(100, fs.getFreeBlock());
-
- // Ask again, will still get 100 as not written to
- assertEquals(100, fs.getFreeBlock());
-
- // Allocate it, then ask again
- fs.setNextBlock(100, POIFSConstants.END_OF_CHAIN);
- assertEquals(101, fs.getFreeBlock());
- }
- }
-
- /**
- * Ask for free blocks where no free ones exist, and so the
- * file needs to be extended and another BAT/XBAT added
- */
- @Test
- void getFreeBlockWithNoneSpare() throws IOException {
- try (POIFSFileSystem fs1 = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"))) {
- int free;
-
- // We have one BAT at block 99
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(99));
- assertBATCount(fs1, 1, 0);
-
- // We've spare ones from 100 to 128
- for (int i = 100; i < 128; i++) {
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(i));
- }
-
- // Check our BAT knows it's free
- assertTrue(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
-
- // Allocate all the spare ones
- for (int i = 100; i < 128; i++) {
- fs1.setNextBlock(i, POIFSConstants.END_OF_CHAIN);
- }
-
- // BAT is now full, but there's only the one
- assertFalse(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
- assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(128), "Should only be one BAT");
- assertBATCount(fs1, 1, 0);
-
-
- // Now ask for a free one, will need to extend the file
- assertEquals(129, fs1.getFreeBlock());
-
- assertFalse(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
- assertTrue(fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(128));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(129));
-
- // We now have 2 BATs, but no XBATs
- assertBATCount(fs1, 2, 0);
-
-
- // Fill up to hold 109 BAT blocks
- for (int i = 0; i < 109; i++) {
- fs1.getFreeBlock();
- int startOffset = i * 128;
- while (fs1.getBATBlockAndIndex(startOffset).getBlock().hasFreeSectors()) {
- free = fs1.getFreeBlock();
- fs1.setNextBlock(free, POIFSConstants.END_OF_CHAIN);
- }
- }
-
- assertFalse(fs1.getBATBlockAndIndex(109 * 128 - 1).getBlock().hasFreeSectors());
- assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(109 * 128), "Should only be 109 BATs");
-
- // We now have 109 BATs, but no XBATs
- assertBATCount(fs1, 109, 0);
-
-
- // Ask for it to be written out, and check the header
- HeaderBlock header = writeOutAndReadHeader(fs1);
- assertEquals(109, header.getBATCount());
- assertEquals(0, header.getXBATCount());
-
-
- // Ask for another, will get our first XBAT
- free = fs1.getFreeBlock();
- assertTrue(free > 0, "Had: " + free);
-
- assertFalse(fs1.getBATBlockAndIndex(109 * 128 - 1).getBlock().hasFreeSectors());
- assertTrue(fs1.getBATBlockAndIndex(110 * 128 - 1).getBlock().hasFreeSectors());
- assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(110 * 128), "Should only be 110 BATs");
- assertBATCount(fs1, 110, 1);
-
- header = writeOutAndReadHeader(fs1);
- assertEquals(110, header.getBATCount());
- assertEquals(1, header.getXBATCount());
-
-
- // Fill the XBAT, which means filling 127 BATs
- for (int i = 109; i < 109 + 127; i++) {
- fs1.getFreeBlock();
- int startOffset = i * 128;
- while (fs1.getBATBlockAndIndex(startOffset).getBlock().hasFreeSectors()) {
- free = fs1.getFreeBlock();
- fs1.setNextBlock(free, POIFSConstants.END_OF_CHAIN);
- }
- assertBATCount(fs1, i + 1, 1);
- }
-
- // Should now have 109+127 = 236 BATs
- assertFalse(fs1.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors());
- assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(236 * 128), "Should only be 236 BATs");
- assertBATCount(fs1, 236, 1);
-
-
- // Ask for another, will get our 2nd XBAT
- free = fs1.getFreeBlock();
- assertTrue(free > 0, "Had: " + free);
-
- assertFalse(fs1.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors());
- assertTrue(fs1.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors());
- assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(237 * 128), "Should only be 237 BATs");
-
- // Check the counts now
- assertBATCount(fs1, 237, 2);
-
- // Check the header
- header = writeOutAndReadHeader(fs1);
- assertNotNull(header);
-
- // Now, write it out, and read it back in again fully
- try (POIFSFileSystem fs2 = writeOutAndReadBack(fs1)) {
-
- // Check that it is seen correctly
- assertBATCount(fs2, 237, 2);
-
- assertFalse(fs2.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors());
- assertTrue(fs2.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors());
- assertThrows(IndexOutOfBoundsException.class, () -> fs2.getBATBlockAndIndex(237 * 128), "Should only be 237 BATs");
- }
- }
- }
-
- /**
- * Test that we can correctly get the list of directory
- * entries, and the details on the files in them
- */
- @ParameterizedTest
- @MethodSource("get512and4kFileAndInput")
- void listEntries(String file, Function<String,POIFSFileSystem> opener) throws IOException {
- try (POIFSFileSystem fs = opener.apply(file)) {
- DirectoryEntry root = fs.getRoot();
- assertEquals(5, root.getEntryCount());
-
- // Check by the names
- Entry thumbnail = root.getEntry("Thumbnail");
- Entry dsi = root.getEntry("\u0005DocumentSummaryInformation");
- Entry si = root.getEntry("\u0005SummaryInformation");
- Entry image = root.getEntry("Image");
- Entry tags = root.getEntry("Tags");
-
- assertFalse(thumbnail.isDirectoryEntry());
- assertFalse(dsi.isDirectoryEntry());
- assertFalse(si.isDirectoryEntry());
- assertTrue(image.isDirectoryEntry());
- assertFalse(tags.isDirectoryEntry());
-
- // Check via the iterator
- Iterator<Entry> it = root.getEntries();
- assertEquals(thumbnail.getName(), it.next().getName());
- assertEquals(dsi.getName(), it.next().getName());
- assertEquals(si.getName(), it.next().getName());
- assertEquals(image.getName(), it.next().getName());
- assertEquals(tags.getName(), it.next().getName());
-
- // Look inside another
- DirectoryEntry imageD = (DirectoryEntry) image;
- assertEquals(7, imageD.getEntryCount());
- }
- }
-
- /**
- * Tests that we can get the correct contents for
- * a document in the filesystem
- */
- @ParameterizedTest
- @MethodSource("get512and4kFileAndInput")
- void getDocumentEntry(String file, Function<String,POIFSFileSystem> opener)
- throws IOException, NoPropertySetStreamException {
- try (POIFSFileSystem fs = opener.apply(file)) {
- DirectoryEntry root = fs.getRoot();
- Entry si = root.getEntry("\u0005SummaryInformation");
-
- assertTrue(si.isDocumentEntry());
- DocumentNode doc = (DocumentNode) si;
-
- // Check we can read it
- assertContentsMatches(null, doc);
-
- // Now try to build the property set
- try (DocumentInputStream inp = new DocumentInputStream(doc)) {
- PropertySet ps = PropertySetFactory.create(inp);
- SummaryInformation inf = (SummaryInformation) ps;
-
- // Check some bits in it
- assertNull(inf.getApplicationName());
- assertNull(inf.getAuthor());
- assertNull(inf.getSubject());
- assertEquals(131333, inf.getOSVersion());
- }
-
-
- // Try the other summary information
- si = root.getEntry("\u0005DocumentSummaryInformation");
- assertTrue(si.isDocumentEntry());
- doc = (DocumentNode) si;
- assertContentsMatches(null, doc);
-
- try (DocumentInputStream inp = new DocumentInputStream(doc)) {
- PropertySet ps = PropertySetFactory.create(inp);
- DocumentSummaryInformation dinf = (DocumentSummaryInformation) ps;
- assertEquals(131333, dinf.getOSVersion());
- }
- }
- }
-
- /**
- * Read a file, write it and read it again.
- * Then, alter+add some streams, write and read
- */
- @ParameterizedTest
- @MethodSource("get512and4kFileAndInput")
- void readWriteRead(String file, Function<String,POIFSFileSystem> opener) throws IOException, NoPropertySetStreamException {
- SummaryInformation sinf;
- DocumentSummaryInformation dinf;
- DirectoryEntry root, testDir;
-
- try (POIFSFileSystem fs1 = opener.apply(file)) {
- // Check we can find the entries we expect
- root = fs1.getRoot();
- assertEquals(5, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Tags"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
- // Write out, re-load
- try (POIFSFileSystem fs2 = writeOutAndReadBack(fs1)) {
- // Check they're still there
- root = fs2.getRoot();
- assertEquals(5, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Tags"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
-
- // Check the contents of them - parse the summary block and check
- sinf = (SummaryInformation) PropertySetFactory.create(new DocumentInputStream(
- (DocumentEntry) root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME)));
- assertEquals(131333, sinf.getOSVersion());
-
- dinf = (DocumentSummaryInformation) PropertySetFactory.create(new DocumentInputStream(
- (DocumentEntry) root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME)));
- assertEquals(131333, dinf.getOSVersion());
-
-
- // Add a test mini stream
- testDir = root.createDirectory("Testing 123");
- testDir.createDirectory("Testing 456");
- testDir.createDirectory("Testing 789");
- byte[] mini = new byte[]{42, 0, 1, 2, 3, 4, 42};
- testDir.createDocument("Mini", new ByteArrayInputStream(mini));
-
-
- // Write out, re-load
- try (POIFSFileSystem fs3 = writeOutAndReadBack(fs2)) {
-
- root = fs3.getRoot();
- testDir = (DirectoryEntry) root.getEntry("Testing 123");
- assertEquals(6, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Tags"));
- assertThat(root.getEntryNames(), hasItem("Testing 123"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
-
- // Check old and new are there
- sinf = (SummaryInformation) PropertySetFactory.create(new DocumentInputStream(
- (DocumentEntry) root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME)));
- assertEquals(131333, sinf.getOSVersion());
-
- dinf = (DocumentSummaryInformation) PropertySetFactory.create(new DocumentInputStream(
- (DocumentEntry) root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME)));
- assertEquals(131333, dinf.getOSVersion());
-
- assertContentsMatches(mini, (DocumentEntry) testDir.getEntry("Mini"));
-
-
- // Write out and read once more, just to be sure
- try (POIFSFileSystem fs4 = writeOutAndReadBack(fs3)) {
-
- root = fs4.getRoot();
- testDir = (DirectoryEntry) root.getEntry("Testing 123");
- assertEquals(6, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Tags"));
- assertThat(root.getEntryNames(), hasItem("Testing 123"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
- sinf = (SummaryInformation) PropertySetFactory.create(new DocumentInputStream(
- (DocumentEntry) root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME)));
- assertEquals(131333, sinf.getOSVersion());
-
- dinf = (DocumentSummaryInformation) PropertySetFactory.create(new DocumentInputStream(
- (DocumentEntry) root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME)));
- assertEquals(131333, dinf.getOSVersion());
-
- assertContentsMatches(mini, (DocumentEntry) testDir.getEntry("Mini"));
-
-
- // Add a full stream, delete a full stream
- byte[] main4096 = new byte[4096];
- main4096[0] = -10;
- main4096[4095] = -11;
- testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096));
-
- root.getEntry("Tags").delete();
-
-
- // Write out, re-load
- try (POIFSFileSystem fs5 = writeOutAndReadBack(fs4)) {
-
- // Check it's all there
- root = fs5.getRoot();
- testDir = (DirectoryEntry) root.getEntry("Testing 123");
- assertEquals(5, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Testing 123"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
-
- // Check old and new are there
- sinf = (SummaryInformation) PropertySetFactory.create(new DocumentInputStream(
- (DocumentEntry) root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME)));
- assertEquals(131333, sinf.getOSVersion());
-
- dinf = (DocumentSummaryInformation) PropertySetFactory.create(new DocumentInputStream(
- (DocumentEntry) root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME)));
- assertEquals(131333, dinf.getOSVersion());
-
- assertContentsMatches(mini, (DocumentEntry) testDir.getEntry("Mini"));
- assertContentsMatches(main4096, (DocumentEntry) testDir.getEntry("Normal4096"));
-
-
- // Delete a directory, and add one more
- testDir.getEntry("Testing 456").delete();
- testDir.createDirectory("Testing ABC");
-
-
- // Save
- try (POIFSFileSystem fs6 = writeOutAndReadBack(fs5)) {
-
- // Check
- root = fs6.getRoot();
- testDir = (DirectoryEntry) root.getEntry("Testing 123");
-
- assertEquals(5, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Testing 123"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
- assertEquals(4, testDir.getEntryCount());
- assertThat(testDir.getEntryNames(), hasItem("Mini"));
- assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
- assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
- assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
-
-
- // Add another mini stream
- byte[] mini2 = new byte[]{-42, 0, -1, -2, -3, -4, -42};
- testDir.createDocument("Mini2", new ByteArrayInputStream(mini2));
-
- // Save, load, check
- try (POIFSFileSystem fs7 = writeOutAndReadBack(fs6)) {
-
- root = fs7.getRoot();
- testDir = (DirectoryEntry) root.getEntry("Testing 123");
-
- assertEquals(5, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Testing 123"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
- assertEquals(5, testDir.getEntryCount());
- assertThat(testDir.getEntryNames(), hasItem("Mini"));
- assertThat(testDir.getEntryNames(), hasItem("Mini2"));
- assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
- assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
- assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
-
- assertContentsMatches(mini, (DocumentEntry) testDir.getEntry("Mini"));
- assertContentsMatches(mini2, (DocumentEntry) testDir.getEntry("Mini2"));
- assertContentsMatches(main4096, (DocumentEntry) testDir.getEntry("Normal4096"));
-
-
- // Delete a mini stream, add one more
- testDir.getEntry("Mini").delete();
-
- byte[] mini3 = new byte[]{42, 0, 42, 0, 42, 0, 42};
- testDir.createDocument("Mini3", new ByteArrayInputStream(mini3));
-
-
- // Save, load, check
- try (POIFSFileSystem fs8 = writeOutAndReadBack(fs7)) {
-
- root = fs8.getRoot();
- testDir = (DirectoryEntry) root.getEntry("Testing 123");
-
- assertEquals(5, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Testing 123"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
- assertEquals(5, testDir.getEntryCount());
- assertThat(testDir.getEntryNames(), hasItem("Mini2"));
- assertThat(testDir.getEntryNames(), hasItem("Mini3"));
- assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
- assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
- assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
-
- assertContentsMatches(mini2, (DocumentEntry) testDir.getEntry("Mini2"));
- assertContentsMatches(mini3, (DocumentEntry) testDir.getEntry("Mini3"));
- assertContentsMatches(main4096, (DocumentEntry) testDir.getEntry("Normal4096"));
-
-
- // Change some existing streams
- POIFSDocument mini2Doc = new POIFSDocument((DocumentNode) testDir.getEntry("Mini2"));
- mini2Doc.replaceContents(new ByteArrayInputStream(mini));
-
- byte[] main4106 = new byte[4106];
- main4106[0] = 41;
- main4106[4105] = 42;
- POIFSDocument mainDoc = new POIFSDocument((DocumentNode) testDir.getEntry("Normal4096"));
- mainDoc.replaceContents(new ByteArrayInputStream(main4106));
-
-
- // Re-check
- try (POIFSFileSystem fs9 = writeOutAndReadBack(fs8)) {
-
- root = fs9.getRoot();
- testDir = (DirectoryEntry) root.getEntry("Testing 123");
-
- assertEquals(5, root.getEntryCount());
- assertThat(root.getEntryNames(), hasItem("Thumbnail"));
- assertThat(root.getEntryNames(), hasItem("Image"));
- assertThat(root.getEntryNames(), hasItem("Testing 123"));
- assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
- assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
-
- assertEquals(5, testDir.getEntryCount());
- assertThat(testDir.getEntryNames(), hasItem("Mini2"));
- assertThat(testDir.getEntryNames(), hasItem("Mini3"));
- assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
- assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
- assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
-
- assertContentsMatches(mini, (DocumentEntry) testDir.getEntry("Mini2"));
- assertContentsMatches(mini3, (DocumentEntry) testDir.getEntry("Mini3"));
- assertContentsMatches(main4106, (DocumentEntry) testDir.getEntry("Normal4096"));
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * Create a new file, write it and read it again
- * Then, add some streams, write and read
- */
- @Test
- void createWriteRead() throws IOException {
- try (POIFSFileSystem fs1 = new POIFSFileSystem()) {
- // Initially has Properties + BAT but not SBAT
- assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(1));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(2));
-
- // Check that the SBAT is empty
- assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getRoot().getProperty().getStartBlock());
-
- // Check that properties table was given block 0
- assertEquals(0, fs1._get_property_table().getStartBlock());
-
- // Write and read it
- try (POIFSFileSystem fs2 = writeOutAndReadBack(fs1)) {
-
- // No change, SBAT remains empty
- assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs2.getNextBlock(1));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs2.getNextBlock(2));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs2.getNextBlock(3));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getRoot().getProperty().getStartBlock());
- assertEquals(0, fs2._get_property_table().getStartBlock());
- }
- }
-
- // Check the same but with saving to a file
- try (POIFSFileSystem fs3 = new POIFSFileSystem();
- POIFSFileSystem fs4 = writeOutFileAndReadBack(fs3)) {
-
- // Same, no change, SBAT remains empty
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs4.getNextBlock(1));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(2));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(3));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getRoot().getProperty().getStartBlock());
- assertEquals(0, fs4._get_property_table().getStartBlock());
-
-
- // Put everything within a new directory
- DirectoryEntry testDir = fs4.createDirectory("Test Directory");
-
- // Add a new Normal Stream (Normal Streams minimum 4096 bytes)
- byte[] main4096 = new byte[4096];
- main4096[0] = -10;
- main4096[4095] = -11;
- testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096));
-
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs4.getNextBlock(1));
- assertEquals(3, fs4.getNextBlock(2));
- assertEquals(4, fs4.getNextBlock(3));
- assertEquals(5, fs4.getNextBlock(4));
- assertEquals(6, fs4.getNextBlock(5));
- assertEquals(7, fs4.getNextBlock(6));
- assertEquals(8, fs4.getNextBlock(7));
- assertEquals(9, fs4.getNextBlock(8));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(9));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(10));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(11));
- // SBAT still unused
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getRoot().getProperty().getStartBlock());
-
-
- // Add a bigger Normal Stream
- byte[] main5124 = new byte[5124];
- main5124[0] = -22;
- main5124[5123] = -33;
- testDir.createDocument("Normal5124", new ByteArrayInputStream(main5124));
-
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs4.getNextBlock(1));
- assertEquals(3, fs4.getNextBlock(2));
- assertEquals(4, fs4.getNextBlock(3));
- assertEquals(5, fs4.getNextBlock(4));
- assertEquals(6, fs4.getNextBlock(5));
- assertEquals(7, fs4.getNextBlock(6));
- assertEquals(8, fs4.getNextBlock(7));
- assertEquals(9, fs4.getNextBlock(8));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(9));
-
- assertEquals(11, fs4.getNextBlock(10));
- assertEquals(12, fs4.getNextBlock(11));
- assertEquals(13, fs4.getNextBlock(12));
- assertEquals(14, fs4.getNextBlock(13));
- assertEquals(15, fs4.getNextBlock(14));
- assertEquals(16, fs4.getNextBlock(15));
- assertEquals(17, fs4.getNextBlock(16));
- assertEquals(18, fs4.getNextBlock(17));
- assertEquals(19, fs4.getNextBlock(18));
- assertEquals(20, fs4.getNextBlock(19));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(20));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(21));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(22));
-
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getRoot().getProperty().getStartBlock());
-
-
- // Now Add a mini stream
- byte[] mini = new byte[]{42, 0, 1, 2, 3, 4, 42};
- testDir.createDocument("Mini", new ByteArrayInputStream(mini));
-
- // Mini stream will get one block for fat + one block for data
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs4.getNextBlock(1));
- assertEquals(3, fs4.getNextBlock(2));
- assertEquals(4, fs4.getNextBlock(3));
- assertEquals(5, fs4.getNextBlock(4));
- assertEquals(6, fs4.getNextBlock(5));
- assertEquals(7, fs4.getNextBlock(6));
- assertEquals(8, fs4.getNextBlock(7));
- assertEquals(9, fs4.getNextBlock(8));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(9));
-
- assertEquals(11, fs4.getNextBlock(10));
- assertEquals(12, fs4.getNextBlock(11));
- assertEquals(13, fs4.getNextBlock(12));
- assertEquals(14, fs4.getNextBlock(13));
- assertEquals(15, fs4.getNextBlock(14));
- assertEquals(16, fs4.getNextBlock(15));
- assertEquals(17, fs4.getNextBlock(16));
- assertEquals(18, fs4.getNextBlock(17));
- assertEquals(19, fs4.getNextBlock(18));
- assertEquals(20, fs4.getNextBlock(19));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(20));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(21));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(22));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(23));
-
- // Check the mini stream location was set
- // (21 is mini fat, 22 is first mini stream block)
- assertEquals(22, fs4.getRoot().getProperty().getStartBlock());
-
-
- // Write and read back
- try (POIFSFileSystem fs5 = writeOutAndReadBack(fs4)) {
- HeaderBlock header = writeOutAndReadHeader(fs5);
-
- // Check the header has the right points in it
- assertEquals(1, header.getBATCount());
- assertEquals(1, header.getBATArray()[0]);
- assertEquals(2, header.getPropertyCount());
- assertEquals(0, header.getPropertyStart());
- assertEquals(1, header.getSBATCount());
- assertEquals(21, header.getSBATStart());
- assertEquals(22, fs5._get_property_table().getRoot().getStartBlock());
-
- // Block use should be almost the same, except the properties
- // stream will have grown out to cover 2 blocks
- // Check the block use is all unchanged
- assertEquals(23, fs5.getNextBlock(0)); // Properties now extends over 2 blocks
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs5.getNextBlock(1));
-
- assertEquals(3, fs5.getNextBlock(2));
- assertEquals(4, fs5.getNextBlock(3));
- assertEquals(5, fs5.getNextBlock(4));
- assertEquals(6, fs5.getNextBlock(5));
- assertEquals(7, fs5.getNextBlock(6));
- assertEquals(8, fs5.getNextBlock(7));
- assertEquals(9, fs5.getNextBlock(8));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(9)); // End of normal4096
-
- assertEquals(11, fs5.getNextBlock(10));
- assertEquals(12, fs5.getNextBlock(11));
- assertEquals(13, fs5.getNextBlock(12));
- assertEquals(14, fs5.getNextBlock(13));
- assertEquals(15, fs5.getNextBlock(14));
- assertEquals(16, fs5.getNextBlock(15));
- assertEquals(17, fs5.getNextBlock(16));
- assertEquals(18, fs5.getNextBlock(17));
- assertEquals(19, fs5.getNextBlock(18));
- assertEquals(20, fs5.getNextBlock(19));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(20)); // End of normal5124
-
- assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(21)); // Mini Stream FAT
- assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(22)); // Mini Stream data
- assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(23)); // Properties #2
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs5.getNextBlock(24));
-
-
- // Check some data
- assertEquals(1, fs5.getRoot().getEntryCount());
- testDir = (DirectoryEntry) fs5.getRoot().getEntry("Test Directory");
- assertEquals(3, testDir.getEntryCount());
-
- DocumentEntry miniDoc = (DocumentEntry) testDir.getEntry("Mini");
- assertContentsMatches(mini, miniDoc);
-
- DocumentEntry normDoc = (DocumentEntry) testDir.getEntry("Normal4096");
- assertContentsMatches(main4096, normDoc);
-
- normDoc = (DocumentEntry) testDir.getEntry("Normal5124");
- assertContentsMatches(main5124, normDoc);
-
-
- // Delete a couple of streams
- miniDoc.delete();
- normDoc.delete();
-
-
- // Check - will have un-used sectors now
- try (POIFSFileSystem fs6 = writeOutAndReadBack(fs5)) {
-
- assertEquals(POIFSConstants.END_OF_CHAIN, fs6.getNextBlock(0)); // Props back in 1 block
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs6.getNextBlock(1));
-
- assertEquals(3, fs6.getNextBlock(2));
- assertEquals(4, fs6.getNextBlock(3));
- assertEquals(5, fs6.getNextBlock(4));
- assertEquals(6, fs6.getNextBlock(5));
- assertEquals(7, fs6.getNextBlock(6));
- assertEquals(8, fs6.getNextBlock(7));
- assertEquals(9, fs6.getNextBlock(8));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs6.getNextBlock(9)); // End of normal4096
-
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(10));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(11));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(12));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(13));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(14));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(15));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(16));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(17));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(18));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(19));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(20));
-
- assertEquals(POIFSConstants.END_OF_CHAIN, fs6.getNextBlock(21)); // Mini Stream FAT
- assertEquals(POIFSConstants.END_OF_CHAIN, fs6.getNextBlock(22)); // Mini Stream data
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(23)); // Properties gone
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(24));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(25));
- }
- }
- }
-
- }
-
- @Test
- void addBeforeWrite() throws IOException {
- try (POIFSFileSystem fs1 = new POIFSFileSystem()) {
-
- // Initially has Properties + BAT but nothing else
- assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(1));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(2));
-
- HeaderBlock hdr = writeOutAndReadHeader(fs1);
- // No mini stream, and no xbats
- // Will have fat then properties stream
- assertEquals(1, hdr.getBATCount());
- assertEquals(1, hdr.getBATArray()[0]);
- assertEquals(1, hdr.getPropertyCount());
- assertEquals(0, hdr.getPropertyStart());
- assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getSBATStart());
- assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getXBATIndex());
- assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE * 3, fs1.size());
- }
-
- // Get a clean filesystem to start with
- try (POIFSFileSystem fs1 = new POIFSFileSystem()) {
-
- // Put our test files in a non-standard place
- DirectoryEntry parentDir = fs1.createDirectory("Parent Directory");
- DirectoryEntry testDir = parentDir.createDirectory("Test Directory");
-
-
- // Add to the mini stream
- byte[] mini = new byte[]{42, 0, 1, 2, 3, 4, 42};
- testDir.createDocument("Mini", new ByteArrayInputStream(mini));
-
- // Add to the main stream
- byte[] main4096 = new byte[4096];
- main4096[0] = -10;
- main4096[4095] = -11;
- testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096));
-
-
- // Check the mini stream was added, then the main stream
- assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(0));
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(1));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(2)); // Mini Fat
- assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(3)); // Mini Stream
- assertEquals(5, fs1.getNextBlock(4)); // Main Stream
- assertEquals(6, fs1.getNextBlock(5));
- assertEquals(7, fs1.getNextBlock(6));
- assertEquals(8, fs1.getNextBlock(7));
- assertEquals(9, fs1.getNextBlock(8));
- assertEquals(10, fs1.getNextBlock(9));
- assertEquals(11, fs1.getNextBlock(10));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(11));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(12));
- assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE * 13, fs1.size());
-
-
- // Check that we can read the right data pre-write
- DocumentEntry miniDoc = (DocumentEntry) testDir.getEntry("Mini");
- assertContentsMatches(mini, miniDoc);
-
- DocumentEntry normDoc = (DocumentEntry) testDir.getEntry("Normal4096");
- assertContentsMatches(main4096, normDoc);
-
-
- // Write, read, check
- HeaderBlock hdr = writeOutAndReadHeader(fs1);
- try (POIFSFileSystem fs2 = writeOutAndReadBack(fs1)) {
- // Check the header details - will have the sbat near the start,
- // then the properties at the end
- assertEquals(1, hdr.getBATCount());
- assertEquals(1, hdr.getBATArray()[0]);
- assertEquals(2, hdr.getSBATStart());
- assertEquals(2, hdr.getPropertyCount());
- assertEquals(0, hdr.getPropertyStart());
- assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getXBATIndex());
-
- // Check the block allocation is unchanged, other than
- // the properties stream going in at the end
- assertEquals(12, fs2.getNextBlock(0)); // Properties
- assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs2.getNextBlock(1));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(2));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(3));
- assertEquals(5, fs2.getNextBlock(4));
- assertEquals(6, fs2.getNextBlock(5));
- assertEquals(7, fs2.getNextBlock(6));
- assertEquals(8, fs2.getNextBlock(7));
- assertEquals(9, fs2.getNextBlock(8));
- assertEquals(10, fs2.getNextBlock(9));
- assertEquals(11, fs2.getNextBlock(10));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(11));
- assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(12));
- assertEquals(POIFSConstants.UNUSED_BLOCK, fs2.getNextBlock(13));
- assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE * 14, fs2.size());
-
-
- // Check the data
- DirectoryEntry fsRoot = fs2.getRoot();
- assertEquals(1, fsRoot.getEntryCount());
-
- parentDir = (DirectoryEntry) fsRoot.getEntry("Parent Directory");
- assertEquals(1, parentDir.getEntryCount());
-
- testDir = (DirectoryEntry) parentDir.getEntry("Test Directory");
- assertEquals(2, testDir.getEntryCount());
-
- miniDoc = (DocumentEntry) testDir.getEntry("Mini");
- assertContentsMatches(mini, miniDoc);
-
- normDoc = (DocumentEntry) testDir.getEntry("Normal4096");
- assertContentsMatches(main4096, normDoc);
-
-
- // Add one more stream to each, then save and re-load
- byte[] mini2 = new byte[]{-42, 0, -1, -2, -3, -4, -42};
- testDir.createDocument("Mini2", new ByteArrayInputStream(mini2));
-
- // Add to the main stream
- byte[] main4106 = new byte[4106];
- main4106[0] = 41;
- main4106[4105] = 42;
- testDir.createDocument("Normal4106", new ByteArrayInputStream(main4106));
-
- // Recheck the data in all 4 streams
- try (POIFSFileSystem fs3 = writeOutAndReadBack(fs2)) {
- fsRoot = fs3.getRoot();
- assertEquals(1, fsRoot.getEntryCount());
-
- parentDir = (DirectoryEntry) fsRoot.getEntry("Parent Directory");
- assertEquals(1, parentDir.getEntryCount());
-
- testDir = (DirectoryEntry) parentDir.getEntry("Test Directory");
- assertEquals(4, testDir.getEntryCount());
-
- miniDoc = (DocumentEntry) testDir.getEntry("Mini");
- assertContentsMatches(mini, miniDoc);
-
- miniDoc = (DocumentEntry) testDir.getEntry("Mini2");
- assertContentsMatches(mini2, miniDoc);
-
- normDoc = (DocumentEntry) testDir.getEntry("Normal4106");
- assertContentsMatches(main4106, normDoc);
- }
- }
- }
- }
-
- @Test
- void readZeroLengthEntries() throws IOException {
- try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("only-zero-byte-streams.ole2"))) {
- DirectoryNode testDir = fs.getRoot();
- assertEquals(3, testDir.getEntryCount());
-
- DocumentEntry entry = (DocumentEntry) testDir.getEntry("test-zero-1");
- assertNotNull(entry);
- assertEquals(0, entry.getSize());
-
- entry = (DocumentEntry) testDir.getEntry("test-zero-2");
- assertNotNull(entry);
- assertEquals(0, entry.getSize());
-
- entry = (DocumentEntry) testDir.getEntry("test-zero-3");
- assertNotNull(entry);
- assertEquals(0, entry.getSize());
-
- // Check properties, all have zero length, no blocks
- PropertyTable props = fs._get_property_table();
- assertEquals(POIFSConstants.END_OF_CHAIN, props.getRoot().getStartBlock());
- for (Property prop : props.getRoot()) {
- assertEquals("test-zero-", prop.getName().substring(0, 10));
- assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock());
- }
- }
- }
-
- @Test
- void writeZeroLengthEntries() throws IOException {
- try (POIFSFileSystem fs1 = new POIFSFileSystem()) {
- DirectoryNode testDir = fs1.getRoot();
- DocumentEntry miniDoc;
- DocumentEntry normDoc;
- DocumentEntry emptyDoc;
-
- // Add mini and normal sized entries to start
- byte[] mini2 = new byte[]{-42, 0, -1, -2, -3, -4, -42};
- testDir.createDocument("Mini2", new ByteArrayInputStream(mini2));
-
- // Add to the main stream
- byte[] main4106 = new byte[4106];
- main4106[0] = 41;
- main4106[4105] = 42;
- testDir.createDocument("Normal4106", new ByteArrayInputStream(main4106));
-
- // Now add some empty ones
- byte[] empty = new byte[0];
- testDir.createDocument("empty-1", new ByteArrayInputStream(empty));
- testDir.createDocument("empty-2", new ByteArrayInputStream(empty));
- testDir.createDocument("empty-3", new ByteArrayInputStream(empty));
-
- // Check
- miniDoc = (DocumentEntry) testDir.getEntry("Mini2");
- assertContentsMatches(mini2, miniDoc);
-
- normDoc = (DocumentEntry) testDir.getEntry("Normal4106");
- assertContentsMatches(main4106, normDoc);
-
- emptyDoc = (DocumentEntry) testDir.getEntry("empty-1");
- assertContentsMatches(empty, emptyDoc);
-
- emptyDoc = (DocumentEntry) testDir.getEntry("empty-2");
- assertContentsMatches(empty, emptyDoc);
-
- emptyDoc = (DocumentEntry) testDir.getEntry("empty-3");
- assertContentsMatches(empty, emptyDoc);
-
- // Look at the properties entry, and check the empty ones
- // have zero size and no start block
- PropertyTable props = fs1._get_property_table();
- Iterator<Property> propsIt = props.getRoot().getChildren();
-
- Property prop = propsIt.next();
- assertEquals("Mini2", prop.getName());
- assertEquals(0, prop.getStartBlock());
- assertEquals(7, prop.getSize());
-
- prop = propsIt.next();
- assertEquals("Normal4106", prop.getName());
- assertEquals(4, prop.getStartBlock()); // BAT, Props, SBAT, MIni
- assertEquals(4106, prop.getSize());
-
- prop = propsIt.next();
- assertEquals("empty-1", prop.getName());
- assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock());
- assertEquals(0, prop.getSize());
-
- prop = propsIt.next();
- assertEquals("empty-2", prop.getName());
- assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock());
- assertEquals(0, prop.getSize());
-
- prop = propsIt.next();
- assertEquals("empty-3", prop.getName());
- assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock());
- assertEquals(0, prop.getSize());
-
-
- // Save and re-check
- try (POIFSFileSystem fs2 = writeOutAndReadBack(fs1)) {
- testDir = fs2.getRoot();
-
- miniDoc = (DocumentEntry) testDir.getEntry("Mini2");
- assertContentsMatches(mini2, miniDoc);
-
- normDoc = (DocumentEntry) testDir.getEntry("Normal4106");
- assertContentsMatches(main4106, normDoc);
-
- emptyDoc = (DocumentEntry) testDir.getEntry("empty-1");
- assertContentsMatches(empty, emptyDoc);
-
- emptyDoc = (DocumentEntry) testDir.getEntry("empty-2");
- assertContentsMatches(empty, emptyDoc);
-
- emptyDoc = (DocumentEntry) testDir.getEntry("empty-3");
- assertContentsMatches(empty, emptyDoc);
-
- // Check that a mini-stream was assigned, with one block used
- assertEquals(3, testDir.getProperty().getStartBlock());
- assertEquals(64, testDir.getProperty().getSize());
- }
- }
- }
-
- /**
- * Test that we can read a file with POIFS, create a new POIFS instance,
- * write it out, read it with POIFS, and see the original data
- */
- @Test
- void POIFSReadCopyWritePOIFSRead() throws IOException {
- File testFile = POIDataSamples.getSpreadSheetInstance().getFile("Simple.xls");
- try (POIFSFileSystem src = new POIFSFileSystem(testFile);
- POIFSFileSystem nfs = new POIFSFileSystem()) {
- byte[] wbDataExp = IOUtils.toByteArray(src.createDocumentInputStream("Workbook"));
- EntryUtils.copyNodes(src.getRoot(), nfs.getRoot());
-
- try (POIFSFileSystem pfs = writeOutFileAndReadBack(nfs)) {
- byte[] wbDataAct = IOUtils.toByteArray(pfs.createDocumentInputStream("Workbook"));
- assertThat(wbDataExp, equalTo(wbDataAct));
- }
- }
- }
-
- /**
- * Ensure that you can recursively delete directories and their
- * contents
- */
- @Test
- void RecursiveDelete() throws IOException {
- File testFile = POIDataSamples.getSpreadSheetInstance().getFile("SimpleMacro.xls");
- try (POIFSFileSystem src = new POIFSFileSystem(testFile)) {
- // Starts out with 5 entries:
- // _VBA_PROJECT_CUR
- // SummaryInformation <(0x05)SummaryInformation>
- // DocumentSummaryInformation <(0x05)DocumentSummaryInformation>
- // Workbook
- // CompObj <(0x01)CompObj>
- assertEquals(5, _countChildren(src._get_property_table().getRoot()));
- assertEquals(5, src.getRoot().getEntryCount());
-
- // Grab the VBA project root
- DirectoryEntry vbaProj = (DirectoryEntry) src.getRoot().getEntry("_VBA_PROJECT_CUR");
- assertEquals(3, vbaProj.getEntryCount());
- // Can't delete yet, has stuff
- assertFalse(vbaProj.delete());
- // Recursively delete
- _recursiveDeletee(vbaProj);
-
- // Entries gone
- assertEquals(4, _countChildren(src._get_property_table().getRoot()));
- assertEquals(4, src.getRoot().getEntryCount());
- }
- }
-
- private void _recursiveDeletee(Entry entry) throws IOException {
- if (entry.isDocumentEntry()) {
- assertTrue(entry.delete());
- return;
- }
-
- DirectoryEntry dir = (DirectoryEntry) entry;
- String[] names = dir.getEntryNames().toArray(new String[dir.getEntryCount()]);
- for (String name : names) {
- Entry ce = dir.getEntry(name);
- _recursiveDeletee(ce);
- }
- assertTrue(dir.delete());
- }
-
- @SuppressWarnings("unused")
- private int _countChildren(DirectoryProperty p) {
- int count = 0;
- for (Property cp : p) {
- count++;
- }
- return count;
- }
-
- /**
- * To ensure we can create a file >2gb in size, as well as to
- * extend existing files past the 2gb boundary.
- * <p>
- * Note that to run this test, you will require 2.5+gb of free
- * space on your TMP/TEMP partition/disk
- * <p>
- * Note that to run this test, you need to be able to mmap 2.5+gb
- * files, which may need bigger kernel.shmmax and vm.max_map_count
- * settings on Linux.
- * <p>
- * TODO Fix this to work...
- */
- @Test
- @Disabled("Work in progress test for #60670")
- void creationAndExtensionPast2GB() throws Exception {
- File big = TempFile.createTempFile("poi-test-", ".ole2");
- assumeTrue(big.getFreeSpace() > 2.5 * 1024 * 1024 * 1024,
- "2.5gb of free space is required on your tmp/temp partition/disk to run large file tests");
- System.out.println("Slow, memory heavy test in progress....");
-
- int s100mb = 100 * 1024 * 1024;
- int s512mb = 512 * 1024 * 1024;
- long s2gb = 2L * 1024 * 1024 * 1024;
- DocumentEntry entry;
-
- // Create a just-sub 2gb file
- try (POIFSFileSystem fs = POIFSFileSystem.create(big)) {
- for (int i = 0; i < 19; i++) {
- fs.createDocument(new DummyDataInputStream(s100mb), "Entry" + i);
- }
- fs.writeFilesystem();
- }
-
- // Extend it past the 2gb mark
- try (POIFSFileSystem fs = new POIFSFileSystem(big, false)) {
- for (int i = 0; i < 19; i++) {
- entry = (DocumentEntry) fs.getRoot().getEntry("Entry" + i);
- assertNotNull(entry);
- assertEquals(s100mb, entry.getSize());
- }
-
- fs.createDocument(new DummyDataInputStream(s512mb), "Bigger");
- fs.writeFilesystem();
- }
-
- // Check it still works
- try (POIFSFileSystem fs = new POIFSFileSystem(big, false)) {
- for (int i = 0; i < 19; i++) {
- entry = (DocumentEntry) fs.getRoot().getEntry("Entry" + i);
- assertNotNull(entry);
- assertEquals(s100mb, entry.getSize());
- }
- entry = (DocumentEntry) fs.getRoot().getEntry("Bigger");
- assertNotNull(entry);
- assertEquals(s512mb, entry.getSize());
- }
- // Tidy
- assertTrue(big.delete());
-
-
- // Create a >2gb file
- try (POIFSFileSystem fs = POIFSFileSystem.create(big)) {
- for (int i = 0; i < 4; i++) {
- fs.createDocument(new DummyDataInputStream(s512mb), "Entry" + i);
- }
- fs.writeFilesystem();
- }
-
- // Read it
- try (POIFSFileSystem fs = new POIFSFileSystem(big, false)) {
- for (int i = 0; i < 4; i++) {
- entry = (DocumentEntry) fs.getRoot().getEntry("Entry" + i);
- assertNotNull(entry);
- assertEquals(s512mb, entry.getSize());
- }
-
- // Extend it
- fs.createDocument(new DummyDataInputStream(s512mb), "Entry4");
- fs.writeFilesystem();
- }
-
- // Check it worked
- try (POIFSFileSystem fs = new POIFSFileSystem(big, false)) {
- for (int i = 0; i < 5; i++) {
- entry = (DocumentEntry) fs.getRoot().getEntry("Entry" + i);
- assertNotNull(entry);
- assertEquals(s512mb, entry.getSize());
- }
- }
- // Tidy
- assertTrue(big.delete());
-
- // Create a file with a 2gb entry
- try (POIFSFileSystem fs = POIFSFileSystem.create(big)) {
- fs.createDocument(new DummyDataInputStream(s100mb), "Small");
- // TODO Check we get a helpful error about the max size
- fs.createDocument(new DummyDataInputStream(s2gb), "Big");
- }
- }
-
- private static final class DummyDataInputStream extends InputStream {
- private final long maxSize;
- private long size;
-
- private DummyDataInputStream(long maxSize) {
- this.maxSize = maxSize;
- this.size = 0;
- }
-
- @Override
- public int read() {
- if (size >= maxSize) return -1;
- size++;
- return (int) (size % 128);
- }
-
- @Override
- public int read(byte[] b) {
- return read(b, 0, b.length);
- }
-
- @Override
- public int read(byte[] b, int offset, int len) {
- if (size >= maxSize) return -1;
- int sz = (int) Math.min(len, maxSize - size);
- for (int i = 0; i < sz; i++) {
- b[i + offset] = (byte) ((size + i) % 128);
- }
- size += sz;
- return sz;
- }
- }
-
- @Disabled("Takes a long time to run")
- @Test
- void performance() throws Exception {
- int iterations = 200;//1_000;
-
- long start = System.currentTimeMillis();
-
- for (int i = 0; i < iterations; i++) {
-
- try (InputStream inputStream = POIDataSamples.getHSMFInstance().openResourceAsStream("lots-of-recipients.msg");
- POIFSFileSystem srcFileSystem = new POIFSFileSystem(inputStream);
- POIFSFileSystem destFileSystem = new POIFSFileSystem()) {
-
- copyAllEntries(srcFileSystem.getRoot(), destFileSystem.getRoot());
-
- File file = File.createTempFile("npoi", ".dat");
- try (OutputStream outputStream = new FileOutputStream(file)) {
- destFileSystem.writeFilesystem(outputStream);
- }
-
- assertTrue(file.delete());
- if (i % 10 == 0) System.out.print(".");
- }
- }
-
- System.out.println("NPOI took: " + (System.currentTimeMillis() - start));
- }
-
- private static void copyAllEntries(DirectoryEntry srcDirectory, DirectoryEntry destDirectory) throws IOException {
- Iterator<Entry> iterator = srcDirectory.getEntries();
-
- while (iterator.hasNext()) {
- Entry entry = iterator.next();
-
- if (entry.isDirectoryEntry()) {
- DirectoryEntry childDest = destDirectory.createDirectory(entry.getName());
- copyAllEntries((DirectoryEntry) entry, childDest);
-
- } else {
- DocumentEntry srcEntry = (DocumentEntry) entry;
-
- try (InputStream inputStream = new DocumentInputStream(srcEntry)) {
- destDirectory.createDocument(entry.getName(), inputStream);
- }
- }
- }
- }
- }
|