/** * Re-orders a slide, to a new position. * * @param oldSlideNumber The old slide number (1 based) * @param newSlideNumber The new slide number (1 based) */ public void reorderSlide(int oldSlideNumber, int newSlideNumber) { // Ensure these numbers are valid if (oldSlideNumber < 1 || newSlideNumber < 1) { throw new IllegalArgumentException("Old and new slide numbers must be greater than 0"); } if (oldSlideNumber > _slides.size() || newSlideNumber > _slides.size()) { throw new IllegalArgumentException( "Old and new slide numbers must not exceed the number of slides (" + _slides.size() + ")"); } // The order of slides is defined by the order of slide atom sets in the // SlideListWithText container. SlideListWithText slwt = _documentRecord.getSlideSlideListWithText(); SlideAtomsSet[] sas = slwt.getSlideAtomsSets(); SlideAtomsSet tmp = sas[oldSlideNumber - 1]; sas[oldSlideNumber - 1] = sas[newSlideNumber - 1]; sas[newSlideNumber - 1] = tmp; Collections.swap(_slides, oldSlideNumber - 1, newSlideNumber - 1); _slides.get(newSlideNumber - 1).setSlideNumber(newSlideNumber); _slides.get(oldSlideNumber - 1).setSlideNumber(oldSlideNumber); ArrayList<Record> lst = new ArrayList<Record>(); for (SlideAtomsSet s : sas) { lst.add(s.getSlidePersistAtom()); lst.addAll(Arrays.asList(s.getSlideRecords())); } Record[] r = lst.toArray(new Record[lst.size()]); slwt.setChildRecord(r); }
public static void main(String[] args) throws Exception { if (args.length < 1) { System.err.println("Need to give a filename"); System.exit(1); } HSLFSlideShow ss = new HSLFSlideShow(args[0]); // Find the documents, and then their SLWT Record[] records = ss.getRecords(); for (int i = 0; i < records.length; i++) { if (records[i] instanceof Document) { Record docRecord = records[i]; Record[] docChildren = docRecord.getChildRecords(); for (int j = 0; j < docChildren.length; j++) { if (docChildren[j] instanceof SlideListWithText) { System.out.println("Found SLWT at pos " + j + " in the Document at " + i); System.out.println(" Has " + docChildren[j].getChildRecords().length + " children"); // Grab the SlideAtomSet's, which contain // a SlidePersistAtom and then a bunch of text // + related records SlideListWithText slwt = (SlideListWithText) docChildren[j]; SlideListWithText.SlideAtomsSet[] thisSets = slwt.getSlideAtomsSets(); System.out.println(" Has " + thisSets.length + " AtomSets in it"); // Loop over the sets, showing what they contain for (int k = 0; k < thisSets.length; k++) { SlidePersistAtom spa = thisSets[k].getSlidePersistAtom(); System.out.println(" " + k + " has slide id " + spa.getSlideIdentifier()); System.out.println(" " + k + " has ref id " + spa.getRefID()); // Loop over the records, printing the text Record[] slwtc = thisSets[k].getSlideRecords(); for (int l = 0; l < slwtc.length; l++) { String text = null; if (slwtc[l] instanceof TextBytesAtom) { TextBytesAtom tba = (TextBytesAtom) slwtc[l]; text = tba.getText(); } if (slwtc[l] instanceof TextCharsAtom) { TextCharsAtom tca = (TextCharsAtom) slwtc[l]; text = tca.getText(); } if (text != null) { text = text.replace('\r', '\n'); System.out.println(" ''" + text + "''"); } } } } } } } }
/** * Removes the slide at the given index (0-based). * * <p>Shifts any subsequent slides to the left (subtracts one from their slide numbers). * * @param index the index of the slide to remove (0-based) * @return the slide that was removed from the slide show. */ public HSLFSlide removeSlide(int index) { int lastSlideIdx = _slides.size() - 1; if (index < 0 || index > lastSlideIdx) { throw new IllegalArgumentException( "Slide index (" + index + ") is out of range (0.." + lastSlideIdx + ")"); } SlideListWithText slwt = _documentRecord.getSlideSlideListWithText(); SlideAtomsSet[] sas = slwt.getSlideAtomsSets(); List<Record> records = new ArrayList<Record>(); List<SlideAtomsSet> sa = new ArrayList<SlideAtomsSet>(Arrays.asList(sas)); HSLFSlide removedSlide = _slides.remove(index); _notes.remove(removedSlide.getNotes()); sa.remove(index); int i = 0; for (HSLFSlide s : _slides) s.setSlideNumber(i++); for (SlideAtomsSet s : sa) { records.add(s.getSlidePersistAtom()); records.addAll(Arrays.asList(s.getSlideRecords())); } if (sa.isEmpty()) { _documentRecord.removeSlideListWithText(slwt); } else { slwt.setSlideAtomsSets(sa.toArray(new SlideAtomsSet[sa.size()])); slwt.setChildRecord(records.toArray(new Record[records.size()])); } // if the removed slide had notes - remove references to them too int notesId = (removedSlide != null) ? removedSlide.getSlideRecord().getSlideAtom().getNotesID() : 0; if (notesId != 0) { SlideListWithText nslwt = _documentRecord.getNotesSlideListWithText(); records = new ArrayList<Record>(); ArrayList<SlideAtomsSet> na = new ArrayList<SlideAtomsSet>(); for (SlideAtomsSet ns : nslwt.getSlideAtomsSets()) { if (ns.getSlidePersistAtom().getSlideIdentifier() == notesId) continue; na.add(ns); records.add(ns.getSlidePersistAtom()); if (ns.getSlideRecords() != null) { records.addAll(Arrays.asList(ns.getSlideRecords())); } } if (na.isEmpty()) { _documentRecord.removeSlideListWithText(nslwt); } else { nslwt.setSlideAtomsSets(na.toArray(new SlideAtomsSet[na.size()])); nslwt.setChildRecord(records.toArray(new Record[records.size()])); } } return removedSlide; }
/** * Opens a new copy of SlideShow C, writes the active SlideListWithText out, and compares it to * the write out of the supplied SlideShow. Also compares the contents. * * @param s */ private void assertMatchesSLTWC(SlideShow s) throws Exception { // Grab a new copy of slideshow C SlideShow refC = new SlideShow(_slTests.openResourceAsStream(filenameC)); // Write out the 2nd SLWT in the active document SlideListWithText refSLWT = refC.getDocumentRecord().getSlideListWithTexts()[1]; byte[] raw_slwt = writeRecord(refSLWT); // Write out the same for the supplied slideshow SlideListWithText s_SLWT = s.getDocumentRecord().getSlideListWithTexts()[1]; byte[] s_slwt = writeRecord(s_SLWT); // Check the records are the same assertEquals(refSLWT.getChildRecords().length, s_SLWT.getChildRecords().length); for (int i = 0; i < refSLWT.getChildRecords().length; i++) { Record ref_r = refSLWT.getChildRecords()[i]; Record s_r = s_SLWT.getChildRecords()[i]; byte[] r_rb = writeRecord(ref_r); byte[] s_rb = writeRecord(s_r); assertEquals(r_rb.length, s_rb.length); for (int j = 0; j < r_rb.length; j++) { assertEquals(r_rb[j], s_rb[j]); } } // Check the bytes are the same assertEquals(raw_slwt.length, s_slwt.length); for (int i = 0; i < raw_slwt.length; i++) { assertEquals(raw_slwt[i], s_slwt[i]); } }
/** * Create a blank <code>Slide</code>. * * @return the created <code>Slide</code> */ @Override public HSLFSlide createSlide() { SlideListWithText slist = null; // We need to add the records to the SLWT that deals // with Slides. // Add it, if it doesn't exist slist = _documentRecord.getSlideSlideListWithText(); if (slist == null) { // Need to add a new one slist = new SlideListWithText(); slist.setInstance(SlideListWithText.SLIDES); _documentRecord.addSlideListWithText(slist); } // Grab the SlidePersistAtom with the highest Slide Number. // (Will stay as null if no SlidePersistAtom exists yet in // the slide, or only master slide's ones do) SlidePersistAtom prev = null; for (SlideAtomsSet sas : slist.getSlideAtomsSets()) { SlidePersistAtom spa = sas.getSlidePersistAtom(); if (spa.getSlideIdentifier() < 0) { // This is for a master slide // Odd, since we only deal with the Slide SLWT } else { // Must be for a real slide if (prev == null) { prev = spa; } if (prev.getSlideIdentifier() < spa.getSlideIdentifier()) { prev = spa; } } } // Set up a new SlidePersistAtom for this slide SlidePersistAtom sp = new SlidePersistAtom(); // First slideId is always 256 sp.setSlideIdentifier(prev == null ? 256 : (prev.getSlideIdentifier() + 1)); // Add this new SlidePersistAtom to the SlideListWithText slist.addSlidePersistAtom(sp); // Create a new Slide HSLFSlide slide = new HSLFSlide(sp.getSlideIdentifier(), sp.getRefID(), _slides.size() + 1); slide.setSlideShow(this); slide.onCreate(); // Add in to the list of Slides _slides.add(slide); logger.log( POILogger.INFO, "Added slide " + _slides.size() + " with ref " + sp.getRefID() + " and identifier " + sp.getSlideIdentifier()); // Add the core records for this new Slide to the record tree org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord(); int psrId = addPersistentObject(slideRecord); sp.setRefID(psrId); slideRecord.setSheetId(psrId); slide.setMasterSheet(_masters.get(0)); // All done and added return slide; }
/** Build up model level Slide and Notes objects, from the underlying records. */ private void buildSlidesAndNotes() { // Ensure we really found a Document record earlier // If we didn't, then the file is probably corrupt if (_documentRecord == null) { throw new CorruptPowerPointFileException( "The PowerPoint file didn't contain a Document Record in its PersistPtr blocks. It is probably corrupt."); } // Fetch the SlideListWithTexts in the most up-to-date Document Record // // As far as we understand it: // * The first SlideListWithText will contain a SlideAtomsSet // for each of the master slides // * The second SlideListWithText will contain a SlideAtomsSet // for each of the slides, in their current order // These SlideAtomsSets will normally contain text // * The third SlideListWithText (if present), will contain a // SlideAtomsSet for each Notes // These SlideAtomsSets will not normally contain text // // Having indentified the masters, slides and notes + their orders, // we have to go and find their matching records // We always use the latest versions of these records, and use the // SlideAtom/NotesAtom to match them with the StyleAtomSet SlideListWithText masterSLWT = _documentRecord.getMasterSlideListWithText(); SlideListWithText slidesSLWT = _documentRecord.getSlideSlideListWithText(); SlideListWithText notesSLWT = _documentRecord.getNotesSlideListWithText(); // Find master slides // These can be MainMaster records, but oddly they can also be // Slides or Notes, and possibly even other odd stuff.... // About the only thing you can say is that the master details are in // the first SLWT. if (masterSLWT != null) { for (SlideAtomsSet sas : masterSLWT.getSlideAtomsSets()) { Record r = getCoreRecordForSAS(sas); int sheetNo = sas.getSlidePersistAtom().getSlideIdentifier(); if (r instanceof org.apache.poi.hslf.record.Slide) { HSLFTitleMaster master = new HSLFTitleMaster((org.apache.poi.hslf.record.Slide) r, sheetNo); master.setSlideShow(this); _titleMasters.add(master); } else if (r instanceof org.apache.poi.hslf.record.MainMaster) { HSLFSlideMaster master = new HSLFSlideMaster((org.apache.poi.hslf.record.MainMaster) r, sheetNo); master.setSlideShow(this); _masters.add(master); } } } // Having sorted out the masters, that leaves the notes and slides // Start by finding the notes records to go with the entries in // notesSLWT org.apache.poi.hslf.record.Notes[] notesRecords; Map<Integer, Integer> slideIdToNotes = new HashMap<Integer, Integer>(); if (notesSLWT == null) { // None notesRecords = new org.apache.poi.hslf.record.Notes[0]; } else { // Match up the records and the SlideAtomSets List<org.apache.poi.hslf.record.Notes> notesRecordsL = new ArrayList<org.apache.poi.hslf.record.Notes>(); int idx = -1; for (SlideAtomsSet notesSet : notesSLWT.getSlideAtomsSets()) { idx++; // Get the right core record Record r = getCoreRecordForSAS(notesSet); SlidePersistAtom spa = notesSet.getSlidePersistAtom(); String loggerLoc = "A Notes SlideAtomSet at " + idx + " said its record was at refID " + spa.getRefID(); // Ensure it really is a notes record if (r == null || r instanceof org.apache.poi.hslf.record.Notes) { if (r == null) { logger.log( POILogger.WARN, loggerLoc + ", but that record didn't exist - record ignored."); } // we need to add also null-records, otherwise the index references to other existing // don't work anymore org.apache.poi.hslf.record.Notes notesRecord = (org.apache.poi.hslf.record.Notes) r; notesRecordsL.add(notesRecord); // Record the match between slide id and these notes int slideId = spa.getSlideIdentifier(); slideIdToNotes.put(slideId, idx); } else { logger.log(POILogger.ERROR, loggerLoc + ", but that was actually a " + r); } } notesRecords = new org.apache.poi.hslf.record.Notes[notesRecordsL.size()]; notesRecords = notesRecordsL.toArray(notesRecords); } // Now, do the same thing for our slides org.apache.poi.hslf.record.Slide[] slidesRecords; SlideAtomsSet[] slidesSets = new SlideAtomsSet[0]; if (slidesSLWT == null) { // None slidesRecords = new org.apache.poi.hslf.record.Slide[0]; } else { // Match up the records and the SlideAtomSets slidesSets = slidesSLWT.getSlideAtomsSets(); slidesRecords = new org.apache.poi.hslf.record.Slide[slidesSets.length]; for (int i = 0; i < slidesSets.length; i++) { // Get the right core record Record r = getCoreRecordForSAS(slidesSets[i]); // Ensure it really is a slide record if (r instanceof org.apache.poi.hslf.record.Slide) { slidesRecords[i] = (org.apache.poi.hslf.record.Slide) r; } else { logger.log( POILogger.ERROR, "A Slide SlideAtomSet at " + i + " said its record was at refID " + slidesSets[i].getSlidePersistAtom().getRefID() + ", but that was actually a " + r); } } } // Finally, generate model objects for everything // Notes first for (org.apache.poi.hslf.record.Notes n : notesRecords) { HSLFNotes hn = null; if (n != null) { hn = new HSLFNotes(n); hn.setSlideShow(this); } _notes.add(hn); } // Then slides for (int i = 0; i < slidesRecords.length; i++) { SlideAtomsSet sas = slidesSets[i]; int slideIdentifier = sas.getSlidePersistAtom().getSlideIdentifier(); // Do we have a notes for this? HSLFNotes notes = null; // Slide.SlideAtom.notesId references the corresponding notes slide. // 0 if slide has no notes. int noteId = slidesRecords[i].getSlideAtom().getNotesID(); if (noteId != 0) { Integer notesPos = slideIdToNotes.get(noteId); if (notesPos != null) { notes = _notes.get(notesPos); } else { logger.log(POILogger.ERROR, "Notes not found for noteId=" + noteId); } } // Now, build our slide HSLFSlide hs = new HSLFSlide(slidesRecords[i], notes, sas, slideIdentifier, (i + 1)); hs.setSlideShow(this); _slides.add(hs); } }