You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TestNPOIFSFileSystem.java 59KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.poifs.filesystem;
  16. import static org.hamcrest.core.IsCollectionContaining.hasItem;
  17. import static org.hamcrest.core.IsEqual.equalTo;
  18. import static org.junit.Assert.assertEquals;
  19. import static org.junit.Assert.assertThat;
  20. import static org.junit.Assert.assertNotNull;
  21. import static org.junit.Assert.fail;
  22. import java.io.ByteArrayInputStream;
  23. import java.io.ByteArrayOutputStream;
  24. import java.io.File;
  25. import java.io.IOException;
  26. import java.nio.ByteBuffer;
  27. import java.util.Iterator;
  28. import org.apache.poi.POIDataSamples;
  29. import org.apache.poi.hpsf.DocumentSummaryInformation;
  30. import org.apache.poi.hpsf.PropertySet;
  31. import org.apache.poi.hpsf.PropertySetFactory;
  32. import org.apache.poi.hpsf.SummaryInformation;
  33. import org.apache.poi.poifs.common.POIFSConstants;
  34. import org.apache.poi.poifs.property.NPropertyTable;
  35. import org.apache.poi.poifs.property.Property;
  36. import org.apache.poi.poifs.property.RootProperty;
  37. import org.apache.poi.poifs.storage.HeaderBlock;
  38. import org.apache.poi.util.IOUtils;
  39. import org.junit.Ignore;
  40. import org.junit.Test;
  41. /**
  42. * Tests for the new NIO POIFSFileSystem implementation
  43. */
  44. public final class TestNPOIFSFileSystem {
  45. private static final POIDataSamples _inst = POIDataSamples.getPOIFSInstance();
  46. /**
  47. * Returns test files with 512 byte and 4k block sizes, loaded
  48. * both from InputStreams and Files
  49. */
  50. protected NPOIFSFileSystem[] get512and4kFileAndInput() throws Exception {
  51. NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
  52. NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
  53. NPOIFSFileSystem fsC = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
  54. NPOIFSFileSystem fsD = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
  55. return new NPOIFSFileSystem[] {fsA,fsB,fsC,fsD};
  56. }
  57. protected static void assertBATCount(NPOIFSFileSystem fs, int expectedBAT, int expectedXBAT) throws IOException {
  58. int foundBAT = 0;
  59. int foundXBAT = 0;
  60. int sz = (int)(fs.size() / fs.getBigBlockSize());
  61. for (int i=0; i<sz; i++) {
  62. if(fs.getNextBlock(i) == POIFSConstants.FAT_SECTOR_BLOCK) {
  63. foundBAT++;
  64. }
  65. if(fs.getNextBlock(i) == POIFSConstants.DIFAT_SECTOR_BLOCK) {
  66. foundXBAT++;
  67. }
  68. }
  69. assertEquals("Wrong number of BATs", expectedBAT, foundBAT);
  70. assertEquals("Wrong number of XBATs with " + expectedBAT + " BATs", expectedXBAT, foundXBAT);
  71. }
  72. protected void assertContentsMatches(byte[] expected, DocumentEntry doc) throws IOException {
  73. NDocumentInputStream inp = new NDocumentInputStream(doc);
  74. byte[] contents = new byte[doc.getSize()];
  75. assertEquals(doc.getSize(), inp.read(contents));
  76. inp.close();
  77. if (expected != null)
  78. assertThat(expected, equalTo(contents));
  79. }
  80. protected static HeaderBlock writeOutAndReadHeader(NPOIFSFileSystem fs) throws IOException {
  81. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  82. fs.writeFilesystem(baos);
  83. HeaderBlock header = new HeaderBlock(new ByteArrayInputStream(baos.toByteArray()));
  84. return header;
  85. }
  86. protected static NPOIFSFileSystem writeOutAndReadBack(NPOIFSFileSystem original) throws IOException {
  87. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  88. original.writeFilesystem(baos);
  89. original.close();
  90. return new NPOIFSFileSystem(new ByteArrayInputStream(baos.toByteArray()));
  91. }
  92. @Test
  93. public void basicOpen() throws Exception {
  94. NPOIFSFileSystem fsA, fsB;
  95. // With a simple 512 block file
  96. fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
  97. fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
  98. for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
  99. assertEquals(512, fs.getBigBlockSize());
  100. }
  101. fsA.close();
  102. fsB.close();
  103. // Now with a simple 4096 block file
  104. fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
  105. fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
  106. for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
  107. assertEquals(4096, fs.getBigBlockSize());
  108. }
  109. fsA.close();
  110. fsB.close();
  111. }
  112. @Test
  113. public void propertiesAndFatOnRead() throws Exception {
  114. NPOIFSFileSystem fsA, fsB;
  115. // With a simple 512 block file
  116. fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
  117. fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
  118. for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
  119. // Check the FAT was properly processed:
  120. // Verify we only got one block
  121. fs.getBATBlockAndIndex(0);
  122. fs.getBATBlockAndIndex(1);
  123. try {
  124. fs.getBATBlockAndIndex(140);
  125. fail("Should only be one BAT, but a 2nd was found");
  126. } catch(IndexOutOfBoundsException e) {}
  127. // Verify a few next offsets
  128. // 97 -> 98 -> END
  129. assertEquals(98, fs.getNextBlock(97));
  130. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
  131. // Check the properties
  132. NPropertyTable props = fs._get_property_table();
  133. assertEquals(90, props.getStartBlock());
  134. assertEquals(7, props.countBlocks());
  135. // Root property tells us about the Mini Stream
  136. RootProperty root = props.getRoot();
  137. assertEquals("Root Entry", root.getName());
  138. assertEquals(11564, root.getSize());
  139. assertEquals(0, root.getStartBlock());
  140. // Check its children too
  141. Property prop;
  142. Iterator<Property> pi = root.getChildren();
  143. prop = pi.next();
  144. assertEquals("Thumbnail", prop.getName());
  145. prop = pi.next();
  146. assertEquals("\u0005DocumentSummaryInformation", prop.getName());
  147. prop = pi.next();
  148. assertEquals("\u0005SummaryInformation", prop.getName());
  149. prop = pi.next();
  150. assertEquals("Image", prop.getName());
  151. prop = pi.next();
  152. assertEquals("Tags", prop.getName());
  153. assertEquals(false, pi.hasNext());
  154. // Check the SBAT (Small Blocks FAT) was properly processed
  155. NPOIFSMiniStore ministore = fs.getMiniStore();
  156. // Verify we only got two SBAT blocks
  157. ministore.getBATBlockAndIndex(0);
  158. ministore.getBATBlockAndIndex(128);
  159. try {
  160. ministore.getBATBlockAndIndex(256);
  161. fail("Should only be two SBATs, but a 3rd was found");
  162. } catch(IndexOutOfBoundsException e) {}
  163. // Verify a few offsets: 0->50 is a stream
  164. for(int i=0; i<50; i++) {
  165. assertEquals(i+1, ministore.getNextBlock(i));
  166. }
  167. assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50));
  168. fs.close();
  169. }
  170. // Now with a simple 4096 block file
  171. fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
  172. fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
  173. for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
  174. // Check the FAT was properly processed
  175. // Verify we only got one block
  176. fs.getBATBlockAndIndex(0);
  177. fs.getBATBlockAndIndex(1);
  178. try {
  179. fs.getBATBlockAndIndex(1040);
  180. fail("Should only be one BAT, but a 2nd was found");
  181. } catch(IndexOutOfBoundsException e) {}
  182. // Verify a few next offsets
  183. // 0 -> 1 -> 2 -> END
  184. assertEquals(1, fs.getNextBlock(0));
  185. assertEquals(2, fs.getNextBlock(1));
  186. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
  187. // Check the properties
  188. NPropertyTable props = fs._get_property_table();
  189. assertEquals(12, props.getStartBlock());
  190. assertEquals(1, props.countBlocks());
  191. // Root property tells us about the Mini Stream
  192. RootProperty root = props.getRoot();
  193. assertEquals("Root Entry", root.getName());
  194. assertEquals(11564, root.getSize());
  195. assertEquals(0, root.getStartBlock());
  196. // Check its children too
  197. Property prop;
  198. Iterator<Property> pi = root.getChildren();
  199. prop = pi.next();
  200. assertEquals("Thumbnail", prop.getName());
  201. prop = pi.next();
  202. assertEquals("\u0005DocumentSummaryInformation", prop.getName());
  203. prop = pi.next();
  204. assertEquals("\u0005SummaryInformation", prop.getName());
  205. prop = pi.next();
  206. assertEquals("Image", prop.getName());
  207. prop = pi.next();
  208. assertEquals("Tags", prop.getName());
  209. assertEquals(false, pi.hasNext());
  210. // Check the SBAT (Small Blocks FAT) was properly processed
  211. NPOIFSMiniStore ministore = fs.getMiniStore();
  212. // Verify we only got one SBAT block
  213. ministore.getBATBlockAndIndex(0);
  214. ministore.getBATBlockAndIndex(128);
  215. ministore.getBATBlockAndIndex(1023);
  216. try {
  217. ministore.getBATBlockAndIndex(1024);
  218. fail("Should only be one SBAT, but a 2nd was found");
  219. } catch(IndexOutOfBoundsException e) {}
  220. // Verify a few offsets: 0->50 is a stream
  221. for(int i=0; i<50; i++) {
  222. assertEquals(i+1, ministore.getNextBlock(i));
  223. }
  224. assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50));
  225. fs.close();
  226. }
  227. }
  228. /**
  229. * Check that for a given block, we can correctly figure
  230. * out what the next one is
  231. */
  232. @Test
  233. public void nextBlock() throws Exception {
  234. NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
  235. NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
  236. for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
  237. // 0 -> 21 are simple
  238. for(int i=0; i<21; i++) {
  239. assertEquals(i+1, fs.getNextBlock(i));
  240. }
  241. // 21 jumps to 89, then ends
  242. assertEquals(89, fs.getNextBlock(21));
  243. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(89));
  244. // 22 -> 88 simple sequential stream
  245. for(int i=22; i<88; i++) {
  246. assertEquals(i+1, fs.getNextBlock(i));
  247. }
  248. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(88));
  249. // 90 -> 96 is another stream
  250. for(int i=90; i<96; i++) {
  251. assertEquals(i+1, fs.getNextBlock(i));
  252. }
  253. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(96));
  254. // 97+98 is another
  255. assertEquals(98, fs.getNextBlock(97));
  256. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
  257. // 99 is our FAT block
  258. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
  259. // 100 onwards is free
  260. for(int i=100; i<fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) {
  261. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(i));
  262. }
  263. fs.close();
  264. }
  265. // Quick check on 4096 byte blocks too
  266. fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
  267. fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
  268. for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
  269. // 0 -> 1 -> 2 -> end
  270. assertEquals(1, fs.getNextBlock(0));
  271. assertEquals(2, fs.getNextBlock(1));
  272. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
  273. // 4 -> 11 then end
  274. for(int i=4; i<11; i++) {
  275. assertEquals(i+1, fs.getNextBlock(i));
  276. }
  277. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(11));
  278. fs.close();
  279. }
  280. }
  281. /**
  282. * Check we get the right data back for each block
  283. */
  284. @Test
  285. public void getBlock() throws Exception {
  286. NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
  287. NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
  288. for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
  289. ByteBuffer b;
  290. // The 0th block is the first data block
  291. b = fs.getBlockAt(0);
  292. assertEquals((byte)0x9e, b.get());
  293. assertEquals((byte)0x75, b.get());
  294. assertEquals((byte)0x97, b.get());
  295. assertEquals((byte)0xf6, b.get());
  296. // And the next block
  297. b = fs.getBlockAt(1);
  298. assertEquals((byte)0x86, b.get());
  299. assertEquals((byte)0x09, b.get());
  300. assertEquals((byte)0x22, b.get());
  301. assertEquals((byte)0xfb, b.get());
  302. // Check the final block too
  303. b = fs.getBlockAt(99);
  304. assertEquals((byte)0x01, b.get());
  305. assertEquals((byte)0x00, b.get());
  306. assertEquals((byte)0x00, b.get());
  307. assertEquals((byte)0x00, b.get());
  308. assertEquals((byte)0x02, b.get());
  309. assertEquals((byte)0x00, b.get());
  310. assertEquals((byte)0x00, b.get());
  311. assertEquals((byte)0x00, b.get());
  312. fs.close();
  313. }
  314. // Quick check on 4096 byte blocks too
  315. fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
  316. fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
  317. for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
  318. ByteBuffer b;
  319. // The 0th block is the first data block
  320. b = fs.getBlockAt(0);
  321. assertEquals((byte)0x9e, b.get());
  322. assertEquals((byte)0x75, b.get());
  323. assertEquals((byte)0x97, b.get());
  324. assertEquals((byte)0xf6, b.get());
  325. // And the next block
  326. b = fs.getBlockAt(1);
  327. assertEquals((byte)0x00, b.get());
  328. assertEquals((byte)0x00, b.get());
  329. assertEquals((byte)0x03, b.get());
  330. assertEquals((byte)0x00, b.get());
  331. // The 14th block is the FAT
  332. b = fs.getBlockAt(14);
  333. assertEquals((byte)0x01, b.get());
  334. assertEquals((byte)0x00, b.get());
  335. assertEquals((byte)0x00, b.get());
  336. assertEquals((byte)0x00, b.get());
  337. assertEquals((byte)0x02, b.get());
  338. assertEquals((byte)0x00, b.get());
  339. assertEquals((byte)0x00, b.get());
  340. assertEquals((byte)0x00, b.get());
  341. fs.close();
  342. }
  343. }
  344. /**
  345. * Ask for free blocks where there are some already
  346. * to be had from the FAT
  347. */
  348. @Test
  349. public void getFreeBlockWithSpare() throws Exception {
  350. NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
  351. // Our first BAT block has spares
  352. assertEquals(true, fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
  353. // First free one is 100
  354. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100));
  355. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(101));
  356. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(102));
  357. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(103));
  358. // Ask, will get 100
  359. assertEquals(100, fs.getFreeBlock());
  360. // Ask again, will still get 100 as not written to
  361. assertEquals(100, fs.getFreeBlock());
  362. // Allocate it, then ask again
  363. fs.setNextBlock(100, POIFSConstants.END_OF_CHAIN);
  364. assertEquals(101, fs.getFreeBlock());
  365. // All done
  366. fs.close();
  367. }
  368. /**
  369. * Ask for free blocks where no free ones exist, and so the
  370. * file needs to be extended and another BAT/XBAT added
  371. */
  372. @Test
  373. public void getFreeBlockWithNoneSpare() throws Exception {
  374. NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
  375. int free;
  376. // We have one BAT at block 99
  377. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
  378. assertBATCount(fs, 1, 0);
  379. // We've spare ones from 100 to 128
  380. for(int i=100; i<128; i++) {
  381. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(i));
  382. }
  383. // Check our BAT knows it's free
  384. assertEquals(true, fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
  385. // Allocate all the spare ones
  386. for(int i=100; i<128; i++) {
  387. fs.setNextBlock(i, POIFSConstants.END_OF_CHAIN);
  388. }
  389. // BAT is now full, but there's only the one
  390. assertEquals(false, fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
  391. try {
  392. assertEquals(false, fs.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
  393. fail("Should only be one BAT");
  394. } catch(IndexOutOfBoundsException e) {}
  395. assertBATCount(fs, 1, 0);
  396. // Now ask for a free one, will need to extend the file
  397. assertEquals(129, fs.getFreeBlock());
  398. assertEquals(false, fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
  399. assertEquals(true, fs.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
  400. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(128));
  401. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(129));
  402. // We now have 2 BATs, but no XBATs
  403. assertBATCount(fs, 2, 0);
  404. // Fill up to hold 109 BAT blocks
  405. for(int i=0; i<109; i++) {
  406. fs.getFreeBlock();
  407. int startOffset = i*128;
  408. while( fs.getBATBlockAndIndex(startOffset).getBlock().hasFreeSectors() ) {
  409. free = fs.getFreeBlock();
  410. fs.setNextBlock(free, POIFSConstants.END_OF_CHAIN);
  411. }
  412. }
  413. assertEquals(false, fs.getBATBlockAndIndex(109*128-1).getBlock().hasFreeSectors());
  414. try {
  415. assertEquals(false, fs.getBATBlockAndIndex(109*128).getBlock().hasFreeSectors());
  416. fail("Should only be 109 BATs");
  417. } catch(IndexOutOfBoundsException e) {}
  418. // We now have 109 BATs, but no XBATs
  419. assertBATCount(fs, 109, 0);
  420. // Ask for it to be written out, and check the header
  421. HeaderBlock header = writeOutAndReadHeader(fs);
  422. assertEquals(109, header.getBATCount());
  423. assertEquals(0, header.getXBATCount());
  424. // Ask for another, will get our first XBAT
  425. free = fs.getFreeBlock();
  426. assertEquals(false, fs.getBATBlockAndIndex(109*128-1).getBlock().hasFreeSectors());
  427. assertEquals(true, fs.getBATBlockAndIndex(110*128-1).getBlock().hasFreeSectors());
  428. try {
  429. assertEquals(false, fs.getBATBlockAndIndex(110*128).getBlock().hasFreeSectors());
  430. fail("Should only be 110 BATs");
  431. } catch(IndexOutOfBoundsException e) {}
  432. assertBATCount(fs, 110, 1);
  433. header = writeOutAndReadHeader(fs);
  434. assertEquals(110, header.getBATCount());
  435. assertEquals(1, header.getXBATCount());
  436. // Fill the XBAT, which means filling 127 BATs
  437. for(int i=109; i<109+127; i++) {
  438. fs.getFreeBlock();
  439. int startOffset = i*128;
  440. while( fs.getBATBlockAndIndex(startOffset).getBlock().hasFreeSectors() ) {
  441. free = fs.getFreeBlock();
  442. fs.setNextBlock(free, POIFSConstants.END_OF_CHAIN);
  443. }
  444. assertBATCount(fs, i+1, 1);
  445. }
  446. // Should now have 109+127 = 236 BATs
  447. assertEquals(false, fs.getBATBlockAndIndex(236*128-1).getBlock().hasFreeSectors());
  448. try {
  449. assertEquals(false, fs.getBATBlockAndIndex(236*128).getBlock().hasFreeSectors());
  450. fail("Should only be 236 BATs");
  451. } catch(IndexOutOfBoundsException e) {}
  452. assertBATCount(fs, 236, 1);
  453. // Ask for another, will get our 2nd XBAT
  454. free = fs.getFreeBlock();
  455. assertEquals(false, fs.getBATBlockAndIndex(236*128-1).getBlock().hasFreeSectors());
  456. assertEquals(true, fs.getBATBlockAndIndex(237*128-1).getBlock().hasFreeSectors());
  457. try {
  458. assertEquals(false, fs.getBATBlockAndIndex(237*128).getBlock().hasFreeSectors());
  459. fail("Should only be 237 BATs");
  460. } catch(IndexOutOfBoundsException e) {}
  461. // Check the counts now
  462. assertBATCount(fs, 237, 2);
  463. // Check the header
  464. header = writeOutAndReadHeader(fs);
  465. // Now, write it out, and read it back in again fully
  466. fs = writeOutAndReadBack(fs);
  467. // Check that it is seen correctly
  468. assertBATCount(fs, 237, 2);
  469. assertEquals(false, fs.getBATBlockAndIndex(236*128-1).getBlock().hasFreeSectors());
  470. assertEquals(true, fs.getBATBlockAndIndex(237*128-1).getBlock().hasFreeSectors());
  471. try {
  472. assertEquals(false, fs.getBATBlockAndIndex(237*128).getBlock().hasFreeSectors());
  473. fail("Should only be 237 BATs");
  474. } catch(IndexOutOfBoundsException e) {}
  475. // All done
  476. fs.close();
  477. }
  478. /**
  479. * Test that we can correctly get the list of directory
  480. * entries, and the details on the files in them
  481. */
  482. @Test
  483. public void listEntries() throws Exception {
  484. for(NPOIFSFileSystem fs : get512and4kFileAndInput()) {
  485. DirectoryEntry root = fs.getRoot();
  486. assertEquals(5, root.getEntryCount());
  487. // Check by the names
  488. Entry thumbnail = root.getEntry("Thumbnail");
  489. Entry dsi = root.getEntry("\u0005DocumentSummaryInformation");
  490. Entry si = root.getEntry("\u0005SummaryInformation");
  491. Entry image = root.getEntry("Image");
  492. Entry tags = root.getEntry("Tags");
  493. assertEquals(false, thumbnail.isDirectoryEntry());
  494. assertEquals(false, dsi.isDirectoryEntry());
  495. assertEquals(false, si.isDirectoryEntry());
  496. assertEquals(true, image.isDirectoryEntry());
  497. assertEquals(false, tags.isDirectoryEntry());
  498. // Check via the iterator
  499. Iterator<Entry> it = root.getEntries();
  500. assertEquals(thumbnail.getName(), it.next().getName());
  501. assertEquals(dsi.getName(), it.next().getName());
  502. assertEquals(si.getName(), it.next().getName());
  503. assertEquals(image.getName(), it.next().getName());
  504. assertEquals(tags.getName(), it.next().getName());
  505. // Look inside another
  506. DirectoryEntry imageD = (DirectoryEntry)image;
  507. assertEquals(7, imageD.getEntryCount());
  508. fs.close();
  509. }
  510. }
  511. /**
  512. * Tests that we can get the correct contents for
  513. * a document in the filesystem
  514. */
  515. @Test
  516. public void getDocumentEntry() throws Exception {
  517. for(NPOIFSFileSystem fs : get512and4kFileAndInput()) {
  518. DirectoryEntry root = fs.getRoot();
  519. Entry si = root.getEntry("\u0005SummaryInformation");
  520. assertEquals(true, si.isDocumentEntry());
  521. DocumentNode doc = (DocumentNode)si;
  522. // Check we can read it
  523. assertContentsMatches(null, doc);
  524. // Now try to build the property set
  525. DocumentInputStream inp = new NDocumentInputStream(doc);
  526. PropertySet ps = PropertySetFactory.create(inp);
  527. SummaryInformation inf = (SummaryInformation)ps;
  528. // Check some bits in it
  529. assertEquals(null, inf.getApplicationName());
  530. assertEquals(null, inf.getAuthor());
  531. assertEquals(null, inf.getSubject());
  532. assertEquals(131333, inf.getOSVersion());
  533. // Finish with this one
  534. inp.close();
  535. // Try the other summary information
  536. si = root.getEntry("\u0005DocumentSummaryInformation");
  537. assertEquals(true, si.isDocumentEntry());
  538. doc = (DocumentNode)si;
  539. assertContentsMatches(null, doc);
  540. inp = new NDocumentInputStream(doc);
  541. ps = PropertySetFactory.create(inp);
  542. DocumentSummaryInformation dinf = (DocumentSummaryInformation)ps;
  543. assertEquals(131333, dinf.getOSVersion());
  544. fs.close();
  545. }
  546. }
  547. /**
  548. * Read a file, write it and read it again.
  549. * Then, alter+add some streams, write and read
  550. */
  551. @Test
  552. public void readWriteRead() throws Exception {
  553. SummaryInformation sinf = null;
  554. DocumentSummaryInformation dinf = null;
  555. DirectoryEntry root = null, testDir = null;
  556. for(NPOIFSFileSystem fs : get512and4kFileAndInput()) {
  557. // Check we can find the entries we expect
  558. root = fs.getRoot();
  559. assertEquals(5, root.getEntryCount());
  560. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  561. assertThat(root.getEntryNames(), hasItem("Image"));
  562. assertThat(root.getEntryNames(), hasItem("Tags"));
  563. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  564. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  565. // Write out, re-load
  566. fs = writeOutAndReadBack(fs);
  567. // Check they're still there
  568. root = fs.getRoot();
  569. assertEquals(5, root.getEntryCount());
  570. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  571. assertThat(root.getEntryNames(), hasItem("Image"));
  572. assertThat(root.getEntryNames(), hasItem("Tags"));
  573. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  574. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  575. // Check the contents of them - parse the summary block and check
  576. sinf = (SummaryInformation)PropertySetFactory.create(new NDocumentInputStream(
  577. (DocumentEntry)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME)));
  578. assertEquals(131333, sinf.getOSVersion());
  579. dinf = (DocumentSummaryInformation)PropertySetFactory.create(new NDocumentInputStream(
  580. (DocumentEntry)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME)));
  581. assertEquals(131333, dinf.getOSVersion());
  582. // Add a test mini stream
  583. testDir = root.createDirectory("Testing 123");
  584. testDir.createDirectory("Testing 456");
  585. testDir.createDirectory("Testing 789");
  586. byte[] mini = new byte[] { 42, 0, 1, 2, 3, 4, 42 };
  587. testDir.createDocument("Mini", new ByteArrayInputStream(mini));
  588. // Write out, re-load
  589. fs = writeOutAndReadBack(fs);
  590. root = fs.getRoot();
  591. testDir = (DirectoryEntry)root.getEntry("Testing 123");
  592. assertEquals(6, root.getEntryCount());
  593. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  594. assertThat(root.getEntryNames(), hasItem("Image"));
  595. assertThat(root.getEntryNames(), hasItem("Tags"));
  596. assertThat(root.getEntryNames(), hasItem("Testing 123"));
  597. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  598. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  599. // Check old and new are there
  600. sinf = (SummaryInformation)PropertySetFactory.create(new NDocumentInputStream(
  601. (DocumentEntry)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME)));
  602. assertEquals(131333, sinf.getOSVersion());
  603. dinf = (DocumentSummaryInformation)PropertySetFactory.create(new NDocumentInputStream(
  604. (DocumentEntry)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME)));
  605. assertEquals(131333, dinf.getOSVersion());
  606. assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini"));
  607. // Write out and read once more, just to be sure
  608. fs = writeOutAndReadBack(fs);
  609. root = fs.getRoot();
  610. testDir = (DirectoryEntry)root.getEntry("Testing 123");
  611. assertEquals(6, root.getEntryCount());
  612. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  613. assertThat(root.getEntryNames(), hasItem("Image"));
  614. assertThat(root.getEntryNames(), hasItem("Tags"));
  615. assertThat(root.getEntryNames(), hasItem("Testing 123"));
  616. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  617. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  618. sinf = (SummaryInformation)PropertySetFactory.create(new NDocumentInputStream(
  619. (DocumentEntry)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME)));
  620. assertEquals(131333, sinf.getOSVersion());
  621. dinf = (DocumentSummaryInformation)PropertySetFactory.create(new NDocumentInputStream(
  622. (DocumentEntry)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME)));
  623. assertEquals(131333, dinf.getOSVersion());
  624. assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini"));
  625. // Add a full stream, delete a full stream
  626. byte[] main4096 = new byte[4096];
  627. main4096[0] = -10;
  628. main4096[4095] = -11;
  629. testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096));
  630. root.getEntry("Tags").delete();
  631. // Write out, re-load
  632. fs = writeOutAndReadBack(fs);
  633. // Check it's all there
  634. root = fs.getRoot();
  635. testDir = (DirectoryEntry)root.getEntry("Testing 123");
  636. assertEquals(5, root.getEntryCount());
  637. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  638. assertThat(root.getEntryNames(), hasItem("Image"));
  639. assertThat(root.getEntryNames(), hasItem("Testing 123"));
  640. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  641. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  642. // Check old and new are there
  643. sinf = (SummaryInformation)PropertySetFactory.create(new NDocumentInputStream(
  644. (DocumentEntry)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME)));
  645. assertEquals(131333, sinf.getOSVersion());
  646. dinf = (DocumentSummaryInformation)PropertySetFactory.create(new NDocumentInputStream(
  647. (DocumentEntry)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME)));
  648. assertEquals(131333, dinf.getOSVersion());
  649. assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini"));
  650. assertContentsMatches(main4096, (DocumentEntry)testDir.getEntry("Normal4096"));
  651. // Delete a directory, and add one more
  652. testDir.getEntry("Testing 456").delete();
  653. testDir.createDirectory("Testing ABC");
  654. // Save
  655. fs = writeOutAndReadBack(fs);
  656. // Check
  657. root = fs.getRoot();
  658. testDir = (DirectoryEntry)root.getEntry("Testing 123");
  659. assertEquals(5, root.getEntryCount());
  660. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  661. assertThat(root.getEntryNames(), hasItem("Image"));
  662. assertThat(root.getEntryNames(), hasItem("Testing 123"));
  663. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  664. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  665. assertEquals(4, testDir.getEntryCount());
  666. assertThat(testDir.getEntryNames(), hasItem("Mini"));
  667. assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
  668. assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
  669. assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
  670. // Add another mini stream
  671. byte[] mini2 = new byte[] { -42, 0, -1, -2, -3, -4, -42 };
  672. testDir.createDocument("Mini2", new ByteArrayInputStream(mini2));
  673. // Save, load, check
  674. fs = writeOutAndReadBack(fs);
  675. root = fs.getRoot();
  676. testDir = (DirectoryEntry)root.getEntry("Testing 123");
  677. assertEquals(5, root.getEntryCount());
  678. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  679. assertThat(root.getEntryNames(), hasItem("Image"));
  680. assertThat(root.getEntryNames(), hasItem("Testing 123"));
  681. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  682. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  683. assertEquals(5, testDir.getEntryCount());
  684. assertThat(testDir.getEntryNames(), hasItem("Mini"));
  685. assertThat(testDir.getEntryNames(), hasItem("Mini2"));
  686. assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
  687. assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
  688. assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
  689. assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini"));
  690. assertContentsMatches(mini2, (DocumentEntry)testDir.getEntry("Mini2"));
  691. assertContentsMatches(main4096, (DocumentEntry)testDir.getEntry("Normal4096"));
  692. // Delete a mini stream, add one more
  693. testDir.getEntry("Mini").delete();
  694. byte[] mini3 = new byte[] { 42, 0, 42, 0, 42, 0, 42 };
  695. testDir.createDocument("Mini3", new ByteArrayInputStream(mini3));
  696. // Save, load, check
  697. fs = writeOutAndReadBack(fs);
  698. root = fs.getRoot();
  699. testDir = (DirectoryEntry)root.getEntry("Testing 123");
  700. assertEquals(5, root.getEntryCount());
  701. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  702. assertThat(root.getEntryNames(), hasItem("Image"));
  703. assertThat(root.getEntryNames(), hasItem("Testing 123"));
  704. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  705. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  706. assertEquals(5, testDir.getEntryCount());
  707. assertThat(testDir.getEntryNames(), hasItem("Mini2"));
  708. assertThat(testDir.getEntryNames(), hasItem("Mini3"));
  709. assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
  710. assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
  711. assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
  712. assertContentsMatches(mini2, (DocumentEntry)testDir.getEntry("Mini2"));
  713. assertContentsMatches(mini3, (DocumentEntry)testDir.getEntry("Mini3"));
  714. assertContentsMatches(main4096, (DocumentEntry)testDir.getEntry("Normal4096"));
  715. // Change some existing streams
  716. NPOIFSDocument mini2Doc = new NPOIFSDocument((DocumentNode)testDir.getEntry("Mini2"));
  717. mini2Doc.replaceContents(new ByteArrayInputStream(mini));
  718. byte[] main4106 = new byte[4106];
  719. main4106[0] = 41;
  720. main4106[4105] = 42;
  721. NPOIFSDocument mainDoc = new NPOIFSDocument((DocumentNode)testDir.getEntry("Normal4096"));
  722. mainDoc.replaceContents(new ByteArrayInputStream(main4106));
  723. // Re-check
  724. fs = writeOutAndReadBack(fs);
  725. root = fs.getRoot();
  726. testDir = (DirectoryEntry)root.getEntry("Testing 123");
  727. assertEquals(5, root.getEntryCount());
  728. assertThat(root.getEntryNames(), hasItem("Thumbnail"));
  729. assertThat(root.getEntryNames(), hasItem("Image"));
  730. assertThat(root.getEntryNames(), hasItem("Testing 123"));
  731. assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
  732. assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
  733. assertEquals(5, testDir.getEntryCount());
  734. assertThat(testDir.getEntryNames(), hasItem("Mini2"));
  735. assertThat(testDir.getEntryNames(), hasItem("Mini3"));
  736. assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
  737. assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
  738. assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
  739. assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini2"));
  740. assertContentsMatches(mini3, (DocumentEntry)testDir.getEntry("Mini3"));
  741. assertContentsMatches(main4106, (DocumentEntry)testDir.getEntry("Normal4096"));
  742. // All done
  743. fs.close();
  744. }
  745. }
  746. /**
  747. * Create a new file, write it and read it again
  748. * Then, add some streams, write and read
  749. */
  750. @Test
  751. @SuppressWarnings("resource")
  752. public void createWriteRead() throws Exception {
  753. NPOIFSFileSystem fs = new NPOIFSFileSystem();
  754. DocumentEntry miniDoc;
  755. DocumentEntry normDoc;
  756. // Initially has a BAT but not SBAT
  757. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  758. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  759. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(2));
  760. // Check that the SBAT is empty
  761. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getRoot().getProperty().getStartBlock());
  762. // Check that no properties table has been written yet
  763. assertEquals(POIFSConstants.END_OF_CHAIN, fs._get_property_table().getStartBlock());
  764. // Write and read it
  765. fs = writeOutAndReadBack(fs);
  766. // Property table entries have been added to the blocks
  767. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  768. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  769. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
  770. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(3));
  771. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getRoot().getProperty().getStartBlock());
  772. assertEquals(2, fs._get_property_table().getStartBlock());
  773. // Put everything within a new directory
  774. DirectoryEntry testDir = fs.createDirectory("Test Directory");
  775. // Add a new Normal Stream (Normal Streams minimum 4096 bytes)
  776. byte[] main4096 = new byte[4096];
  777. main4096[0] = -10;
  778. main4096[4095] = -11;
  779. testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096));
  780. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  781. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  782. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
  783. assertEquals(4, fs.getNextBlock(3));
  784. assertEquals(5, fs.getNextBlock(4));
  785. assertEquals(6, fs.getNextBlock(5));
  786. assertEquals(7, fs.getNextBlock(6));
  787. assertEquals(8, fs.getNextBlock(7));
  788. assertEquals(9, fs.getNextBlock(8));
  789. assertEquals(10, fs.getNextBlock(9));
  790. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(10));
  791. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(11));
  792. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getRoot().getProperty().getStartBlock());
  793. // Add a bigger Normal Stream
  794. byte[] main5124 = new byte[5124];
  795. main5124[0] = -22;
  796. main5124[5123] = -33;
  797. testDir.createDocument("Normal5124", new ByteArrayInputStream(main5124));
  798. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  799. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  800. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
  801. assertEquals(4, fs.getNextBlock(3));
  802. assertEquals(5, fs.getNextBlock(4));
  803. assertEquals(6, fs.getNextBlock(5));
  804. assertEquals(7, fs.getNextBlock(6));
  805. assertEquals(8, fs.getNextBlock(7));
  806. assertEquals(9, fs.getNextBlock(8));
  807. assertEquals(10, fs.getNextBlock(9));
  808. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(10));
  809. assertEquals(12, fs.getNextBlock(11));
  810. assertEquals(13, fs.getNextBlock(12));
  811. assertEquals(14, fs.getNextBlock(13));
  812. assertEquals(15, fs.getNextBlock(14));
  813. assertEquals(16, fs.getNextBlock(15));
  814. assertEquals(17, fs.getNextBlock(16));
  815. assertEquals(18, fs.getNextBlock(17));
  816. assertEquals(19, fs.getNextBlock(18));
  817. assertEquals(20, fs.getNextBlock(19));
  818. assertEquals(21, fs.getNextBlock(20));
  819. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(21));
  820. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(22));
  821. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getRoot().getProperty().getStartBlock());
  822. // Now Add a mini stream
  823. byte[] mini = new byte[] { 42, 0, 1, 2, 3, 4, 42 };
  824. testDir.createDocument("Mini", new ByteArrayInputStream(mini));
  825. // Mini stream will get one block for fat + one block for data
  826. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  827. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  828. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
  829. assertEquals(4, fs.getNextBlock(3));
  830. assertEquals(5, fs.getNextBlock(4));
  831. assertEquals(6, fs.getNextBlock(5));
  832. assertEquals(7, fs.getNextBlock(6));
  833. assertEquals(8, fs.getNextBlock(7));
  834. assertEquals(9, fs.getNextBlock(8));
  835. assertEquals(10, fs.getNextBlock(9));
  836. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(10));
  837. assertEquals(12, fs.getNextBlock(11));
  838. assertEquals(13, fs.getNextBlock(12));
  839. assertEquals(14, fs.getNextBlock(13));
  840. assertEquals(15, fs.getNextBlock(14));
  841. assertEquals(16, fs.getNextBlock(15));
  842. assertEquals(17, fs.getNextBlock(16));
  843. assertEquals(18, fs.getNextBlock(17));
  844. assertEquals(19, fs.getNextBlock(18));
  845. assertEquals(20, fs.getNextBlock(19));
  846. assertEquals(21, fs.getNextBlock(20));
  847. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(21));
  848. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(22));
  849. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(23));
  850. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(24));
  851. // Check the mini stream location was set
  852. // (22 is mini fat, 23 is first mini stream block)
  853. assertEquals(23, fs.getRoot().getProperty().getStartBlock());
  854. // Write and read back
  855. fs = writeOutAndReadBack(fs);
  856. HeaderBlock header = writeOutAndReadHeader(fs);
  857. // Check the header has the right points in it
  858. assertEquals(1, header.getBATCount());
  859. assertEquals(0, header.getBATArray()[0]);
  860. assertEquals(2, header.getPropertyStart());
  861. assertEquals(1, header.getSBATCount());
  862. assertEquals(22, header.getSBATStart());
  863. assertEquals(23, fs._get_property_table().getRoot().getStartBlock());
  864. // Block use should be almost the same, except the properties
  865. // stream will have grown out to cover 2 blocks
  866. // Check the block use is all unchanged
  867. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  868. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  869. assertEquals(24, fs.getNextBlock(2)); // Properties now extends over 2 blocks
  870. assertEquals(4, fs.getNextBlock(3));
  871. assertEquals(5, fs.getNextBlock(4));
  872. assertEquals(6, fs.getNextBlock(5));
  873. assertEquals(7, fs.getNextBlock(6));
  874. assertEquals(8, fs.getNextBlock(7));
  875. assertEquals(9, fs.getNextBlock(8));
  876. assertEquals(10, fs.getNextBlock(9));
  877. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(10)); // End of normal4096
  878. assertEquals(12, fs.getNextBlock(11));
  879. assertEquals(13, fs.getNextBlock(12));
  880. assertEquals(14, fs.getNextBlock(13));
  881. assertEquals(15, fs.getNextBlock(14));
  882. assertEquals(16, fs.getNextBlock(15));
  883. assertEquals(17, fs.getNextBlock(16));
  884. assertEquals(18, fs.getNextBlock(17));
  885. assertEquals(19, fs.getNextBlock(18));
  886. assertEquals(20, fs.getNextBlock(19));
  887. assertEquals(21, fs.getNextBlock(20));
  888. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(21)); // End of normal5124
  889. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(22)); // Mini Stream FAT
  890. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(23)); // Mini Stream data
  891. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(24)); // Properties #2
  892. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(25));
  893. // Check some data
  894. assertEquals(1, fs.getRoot().getEntryCount());
  895. testDir = (DirectoryEntry)fs.getRoot().getEntry("Test Directory");
  896. assertEquals(3, testDir.getEntryCount());
  897. miniDoc = (DocumentEntry)testDir.getEntry("Mini");
  898. assertContentsMatches(mini, miniDoc);
  899. normDoc = (DocumentEntry)testDir.getEntry("Normal4096");
  900. assertContentsMatches(main4096, normDoc);
  901. normDoc = (DocumentEntry)testDir.getEntry("Normal5124");
  902. assertContentsMatches(main5124, normDoc);
  903. // Delete a couple of streams
  904. miniDoc.delete();
  905. normDoc.delete();
  906. // Check - will have un-used sectors now
  907. fs = writeOutAndReadBack(fs);
  908. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  909. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  910. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); // Props back in 1 block
  911. assertEquals(4, fs.getNextBlock(3));
  912. assertEquals(5, fs.getNextBlock(4));
  913. assertEquals(6, fs.getNextBlock(5));
  914. assertEquals(7, fs.getNextBlock(6));
  915. assertEquals(8, fs.getNextBlock(7));
  916. assertEquals(9, fs.getNextBlock(8));
  917. assertEquals(10, fs.getNextBlock(9));
  918. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(10)); // End of normal4096
  919. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(11));
  920. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(12));
  921. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(13));
  922. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(14));
  923. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(15));
  924. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(16));
  925. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(17));
  926. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(18));
  927. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(19));
  928. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(20));
  929. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(21));
  930. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(22)); // Mini Stream FAT
  931. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(23)); // Mini Stream data
  932. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(24)); // Properties gone
  933. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(25));
  934. // All done
  935. fs.close();
  936. }
  937. @Test
  938. public void addBeforeWrite() throws Exception {
  939. NPOIFSFileSystem fs = new NPOIFSFileSystem();
  940. DocumentEntry miniDoc;
  941. DocumentEntry normDoc;
  942. HeaderBlock hdr;
  943. // Initially has BAT + Properties but nothing else
  944. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  945. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  946. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(2));
  947. hdr = writeOutAndReadHeader(fs);
  948. // No mini stream, and no xbats
  949. // Will have fat then properties stream
  950. assertEquals(1, hdr.getBATCount());
  951. assertEquals(0, hdr.getBATArray()[0]);
  952. assertEquals(2, hdr.getPropertyStart());
  953. assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getSBATStart());
  954. assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getXBATIndex());
  955. assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE*4, fs.size());
  956. // Get a clean filesystem to start with
  957. fs = new NPOIFSFileSystem();
  958. // Put our test files in a non-standard place
  959. DirectoryEntry parentDir = fs.createDirectory("Parent Directory");
  960. DirectoryEntry testDir = parentDir.createDirectory("Test Directory");
  961. // Add to the mini stream
  962. byte[] mini = new byte[] { 42, 0, 1, 2, 3, 4, 42 };
  963. testDir.createDocument("Mini", new ByteArrayInputStream(mini));
  964. // Add to the main stream
  965. byte[] main4096 = new byte[4096];
  966. main4096[0] = -10;
  967. main4096[4095] = -11;
  968. testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096));
  969. // Check the mini stream was added, then the main stream
  970. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  971. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  972. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); // Mini Fat
  973. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(3)); // Mini Stream
  974. assertEquals(5, fs.getNextBlock(4)); // Main Stream
  975. assertEquals(6, fs.getNextBlock(5));
  976. assertEquals(7, fs.getNextBlock(6));
  977. assertEquals(8, fs.getNextBlock(7));
  978. assertEquals(9, fs.getNextBlock(8));
  979. assertEquals(10, fs.getNextBlock(9));
  980. assertEquals(11, fs.getNextBlock(10));
  981. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(11));
  982. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(12));
  983. assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE*13, fs.size());
  984. // Check that we can read the right data pre-write
  985. miniDoc = (DocumentEntry)testDir.getEntry("Mini");
  986. assertContentsMatches(mini, miniDoc);
  987. normDoc = (DocumentEntry)testDir.getEntry("Normal4096");
  988. assertContentsMatches(main4096, normDoc);
  989. // Write, read, check
  990. hdr = writeOutAndReadHeader(fs);
  991. fs = writeOutAndReadBack(fs);
  992. // Check the header details - will have the sbat near the start,
  993. // then the properties at the end
  994. assertEquals(1, hdr.getBATCount());
  995. assertEquals(0, hdr.getBATArray()[0]);
  996. assertEquals(2, hdr.getSBATStart());
  997. assertEquals(12, hdr.getPropertyStart());
  998. assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getXBATIndex());
  999. // Check the block allocation is unchanged, other than
  1000. // the properties stream going in at the end
  1001. assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(0));
  1002. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(1));
  1003. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
  1004. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(3));
  1005. assertEquals(5, fs.getNextBlock(4));
  1006. assertEquals(6, fs.getNextBlock(5));
  1007. assertEquals(7, fs.getNextBlock(6));
  1008. assertEquals(8, fs.getNextBlock(7));
  1009. assertEquals(9, fs.getNextBlock(8));
  1010. assertEquals(10, fs.getNextBlock(9));
  1011. assertEquals(11, fs.getNextBlock(10));
  1012. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(11));
  1013. assertEquals(13, fs.getNextBlock(12));
  1014. assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(13));
  1015. assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(14));
  1016. assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE*15, fs.size());
  1017. // Check the data
  1018. DirectoryEntry fsRoot = fs.getRoot();
  1019. assertEquals(1, fsRoot.getEntryCount());
  1020. parentDir = (DirectoryEntry)fsRoot.getEntry("Parent Directory");
  1021. assertEquals(1, parentDir.getEntryCount());
  1022. testDir = (DirectoryEntry)parentDir.getEntry("Test Directory");
  1023. assertEquals(2, testDir.getEntryCount());
  1024. miniDoc = (DocumentEntry)testDir.getEntry("Mini");
  1025. assertContentsMatches(mini, miniDoc);
  1026. normDoc = (DocumentEntry)testDir.getEntry("Normal4096");
  1027. assertContentsMatches(main4096, normDoc);
  1028. // Add one more stream to each, then save and re-load
  1029. byte[] mini2 = new byte[] { -42, 0, -1, -2, -3, -4, -42 };
  1030. testDir.createDocument("Mini2", new ByteArrayInputStream(mini2));
  1031. // Add to the main stream
  1032. byte[] main4106 = new byte[4106];
  1033. main4106[0] = 41;
  1034. main4106[4105] = 42;
  1035. testDir.createDocument("Normal4106", new ByteArrayInputStream(main4106));
  1036. // Recheck the data in all 4 streams
  1037. fs = writeOutAndReadBack(fs);
  1038. fsRoot = fs.getRoot();
  1039. assertEquals(1, fsRoot.getEntryCount());
  1040. parentDir = (DirectoryEntry)fsRoot.getEntry("Parent Directory");
  1041. assertEquals(1, parentDir.getEntryCount());
  1042. testDir = (DirectoryEntry)parentDir.getEntry("Test Directory");
  1043. assertEquals(4, testDir.getEntryCount());
  1044. miniDoc = (DocumentEntry)testDir.getEntry("Mini");
  1045. assertContentsMatches(mini, miniDoc);
  1046. miniDoc = (DocumentEntry)testDir.getEntry("Mini2");
  1047. assertContentsMatches(mini2, miniDoc);
  1048. normDoc = (DocumentEntry)testDir.getEntry("Normal4106");
  1049. assertContentsMatches(main4106, normDoc);
  1050. }
  1051. @Test
  1052. public void readZeroLengthEntries() throws Exception {
  1053. NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("only-zero-byte-streams.ole2"));
  1054. DirectoryNode testDir = fs.getRoot();
  1055. assertEquals(3, testDir.getEntryCount());
  1056. DocumentEntry entry;
  1057. entry = (DocumentEntry)testDir.getEntry("test-zero-1");
  1058. assertNotNull(entry);
  1059. assertEquals(0, entry.getSize());
  1060. entry = (DocumentEntry)testDir.getEntry("test-zero-2");
  1061. assertNotNull(entry);
  1062. assertEquals(0, entry.getSize());
  1063. entry = (DocumentEntry)testDir.getEntry("test-zero-3");
  1064. assertNotNull(entry);
  1065. assertEquals(0, entry.getSize());
  1066. // Check properties, all have zero length, no blocks
  1067. NPropertyTable props = fs._get_property_table();
  1068. assertEquals(POIFSConstants.END_OF_CHAIN, props.getRoot().getStartBlock());
  1069. for (Property prop : props.getRoot()) {
  1070. assertEquals("test-zero-", prop.getName().substring(0, 10));
  1071. assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock());
  1072. }
  1073. }
  1074. // TODO Should these have a mini-sbat entry or not?
  1075. // TODO Is the reading of zero-length properties exactly correct?
  1076. @Test
  1077. public void writeZeroLengthEntries() throws Exception {
  1078. NPOIFSFileSystem fs = new NPOIFSFileSystem();
  1079. DirectoryNode testDir = fs.getRoot();
  1080. DocumentEntry miniDoc;
  1081. DocumentEntry normDoc;
  1082. DocumentEntry emptyDoc;
  1083. // Add mini and normal sized entries to start
  1084. byte[] mini2 = new byte[] { -42, 0, -1, -2, -3, -4, -42 };
  1085. testDir.createDocument("Mini2", new ByteArrayInputStream(mini2));
  1086. // Add to the main stream
  1087. byte[] main4106 = new byte[4106];
  1088. main4106[0] = 41;
  1089. main4106[4105] = 42;
  1090. testDir.createDocument("Normal4106", new ByteArrayInputStream(main4106));
  1091. // Now add some empty ones
  1092. byte[] empty = new byte[0];
  1093. testDir.createDocument("empty-1", new ByteArrayInputStream(empty));
  1094. testDir.createDocument("empty-2", new ByteArrayInputStream(empty));
  1095. testDir.createDocument("empty-3", new ByteArrayInputStream(empty));
  1096. // Check
  1097. miniDoc = (DocumentEntry)testDir.getEntry("Mini2");
  1098. assertContentsMatches(mini2, miniDoc);
  1099. normDoc = (DocumentEntry)testDir.getEntry("Normal4106");
  1100. assertContentsMatches(main4106, normDoc);
  1101. emptyDoc = (DocumentEntry)testDir.getEntry("empty-1");
  1102. assertContentsMatches(empty, emptyDoc);
  1103. emptyDoc = (DocumentEntry)testDir.getEntry("empty-2");
  1104. assertContentsMatches(empty, emptyDoc);
  1105. emptyDoc = (DocumentEntry)testDir.getEntry("empty-3");
  1106. assertContentsMatches(empty, emptyDoc);
  1107. // Save and re-check
  1108. fs = writeOutAndReadBack(fs);
  1109. testDir = fs.getRoot();
  1110. miniDoc = (DocumentEntry)testDir.getEntry("Mini2");
  1111. assertContentsMatches(mini2, miniDoc);
  1112. normDoc = (DocumentEntry)testDir.getEntry("Normal4106");
  1113. assertContentsMatches(main4106, normDoc);
  1114. emptyDoc = (DocumentEntry)testDir.getEntry("empty-1");
  1115. assertContentsMatches(empty, emptyDoc);
  1116. emptyDoc = (DocumentEntry)testDir.getEntry("empty-2");
  1117. assertContentsMatches(empty, emptyDoc);
  1118. emptyDoc = (DocumentEntry)testDir.getEntry("empty-3");
  1119. assertContentsMatches(empty, emptyDoc);
  1120. }
  1121. /**
  1122. * Test that we can read a file with NPOIFS, create a new NPOIFS instance,
  1123. * write it out, read it with POIFS, and see the original data
  1124. */
  1125. @Test
  1126. public void NPOIFSReadCopyWritePOIFSRead() throws Exception {
  1127. File testFile = POIDataSamples.getSpreadSheetInstance().getFile("Simple.xls");
  1128. NPOIFSFileSystem src = new NPOIFSFileSystem(testFile);
  1129. byte wbDataExp[] = IOUtils.toByteArray(src.createDocumentInputStream("Workbook"));
  1130. NPOIFSFileSystem nfs = new NPOIFSFileSystem();
  1131. EntryUtils.copyNodes(src.getRoot(), nfs.getRoot());
  1132. src.close();
  1133. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  1134. nfs.writeFilesystem(bos);
  1135. nfs.close();
  1136. POIFSFileSystem pfs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
  1137. byte wbDataAct[] = IOUtils.toByteArray(pfs.createDocumentInputStream("Workbook"));
  1138. assertThat(wbDataExp, equalTo(wbDataAct));
  1139. }
  1140. }