diff --git a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java index 976c888ce..7bddcdd67 100644 --- a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java +++ b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java @@ -17,10 +17,11 @@ package org.apache.poi.hssf.model; +import static org.apache.poi.util.POILogger.DEBUG; + import java.security.AccessControlException; import java.security.GeneralSecurityException; import java.util.ArrayList; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -137,7 +138,7 @@ public final class InternalWorkbook { private static final int MAX_SENSITIVE_SHEET_NAME_LEN = 31; /** - * Normally, the Workbook will be in a POIFS Stream called + * Normally, the Workbook will be in a POIFS Stream called * "Workbook". However, some weird XLS generators use "WORKBOOK" * or "BOOK". */ @@ -153,14 +154,13 @@ public final class InternalWorkbook { */ public static final String OLD_WORKBOOK_DIR_ENTRY_NAME = "Book"; - private static final POILogger log = POILogFactory.getLogger(InternalWorkbook.class); - private static final int DEBUG = POILogger.DEBUG; + private static final POILogger LOG = POILogFactory.getLogger(InternalWorkbook.class); /** * constant used to set the "codepage" wherever "codepage" is set in records * (which is duplicated in more than one record) */ - private final static short CODEPAGE = 0x04B0; + private static final short CODEPAGE = 0x04B0; /** * this contains the Worksheet record objects @@ -231,147 +231,130 @@ public final class InternalWorkbook { * @return Workbook object */ public static InternalWorkbook createWorkbook(List recs) { - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "Workbook (readfile) created with reclen=", - Integer.valueOf(recs.size())); - } + LOG.log(DEBUG, "Workbook (readfile) created with reclen=", recs.size()); InternalWorkbook retval = new InternalWorkbook(); List records = new ArrayList(recs.size() / 3); retval.records.setRecords(records); - int k; - for (k = 0; k < recs.size(); k++) { + boolean eofPassed = false; + for (int k = 0; k < recs.size(); k++) { Record rec = recs.get(k); - - if (rec.getSid() == EOFRecord.sid) { - records.add(rec); - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found workbook eof record at " + k); - } - break; - } + String logObj; switch (rec.getSid()) { + case EOFRecord.sid : + logObj = "workbook eof"; + break; + case BoundSheetRecord.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found boundsheet record at " + k); - } + logObj = "boundsheet"; retval.boundsheets.add((BoundSheetRecord) rec); retval.records.setBspos( k ); break; case SSTRecord.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found sst record at " + k); - } + logObj = "sst"; retval.sst = ( SSTRecord ) rec; break; case FontRecord.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found font record at " + k); - } + logObj = "font"; retval.records.setFontpos( k ); retval.numfonts++; break; case ExtendedFormatRecord.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found XF record at " + k); - } + logObj = "XF"; retval.records.setXfpos( k ); retval.numxfs++; break; case TabIdRecord.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found tabid record at " + k); - } + logObj = "tabid"; retval.records.setTabpos( k ); break; case ProtectRecord.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found protect record at " + k); - } + logObj = "protect"; retval.records.setProtpos( k ); break; case BackupRecord.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found backup record at " + k); - } + logObj = "backup"; retval.records.setBackuppos( k ); break; + case ExternSheetRecord.sid : - throw new RuntimeException("Extern sheet is part of LinkTable"); + throw new RecordFormatException("Extern sheet is part of LinkTable"); + case NameRecord.sid : case SupBookRecord.sid : // LinkTable can start with either of these - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found SupBook record at " + k); - } + LOG.log(DEBUG, "found SupBook record at " + k); retval.linkTable = new LinkTable(recs, k, retval.records, retval.commentRecords); k+=retval.linkTable.getRecordCount() - 1; continue; + case FormatRecord.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found format record at " + k); - } - retval.formats.add((FormatRecord) rec); - retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode(); + logObj = "format"; + FormatRecord fr = (FormatRecord) rec; + retval.formats.add(fr); + retval.maxformatid = retval.maxformatid >= fr.getIndexCode() ? retval.maxformatid : fr.getIndexCode(); break; + case DateWindow1904Record.sid : - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found datewindow1904 record at " + k); - } + logObj = "datewindow1904"; retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1; break; + case PaletteRecord.sid: - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found palette record at " + k); - } + logObj = "palette"; retval.records.setPalettepos( k ); break; + case WindowOneRecord.sid: - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found WindowOneRecord at " + k); - } + logObj = "WindowOneRecord"; retval.windowOne = (WindowOneRecord) rec; break; + case WriteAccessRecord.sid: - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found WriteAccess at " + k); - } + logObj = "WriteAccess"; retval.writeAccess = (WriteAccessRecord) rec; break; + case WriteProtectRecord.sid: - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found WriteProtect at " + k); - } + logObj = "WriteProtect"; retval.writeProtect = (WriteProtectRecord) rec; break; + case FileSharingRecord.sid: - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found FileSharing at " + k); - } + logObj = "FileSharing"; retval.fileShare = (FileSharingRecord) rec; break; case NameCommentRecord.sid: + logObj = "NameComment"; final NameCommentRecord ncr = (NameCommentRecord) rec; - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "found NameComment at " + k); - } retval.commentRecords.put(ncr.getNameText(), ncr); break; + + case HyperlinkRecord.sid: + // Look for other interesting values that follow the EOFRecord + logObj = "Hyperlink"; + retval.hyperlinks.add((HyperlinkRecord)rec); + break; + default: - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "ignoring record (sid=" + rec.getSid() + ") at " + k); - } + logObj = "(sid=" + rec.getSid() + ")"; break; } - records.add(rec); + if (!eofPassed) { + records.add(rec); + } + LOG.log(DEBUG, "found "+logObj+" record at " + k); + if (rec.getSid() == EOFRecord.sid) { + eofPassed = true; + } } //What if we dont have any ranges and supbooks // if (retval.records.supbookpos == 0) { @@ -379,39 +362,22 @@ public final class InternalWorkbook { // retval.records.namepos = retval.records.supbookpos + 1; // } - // Look for other interesting values that - // follow the EOFRecord - for ( ; k < recs.size(); k++) { - Record rec = recs.get(k); - switch (rec.getSid()) { - case HyperlinkRecord.sid: - retval.hyperlinks.add((HyperlinkRecord)rec); - break; - default: - break; - } - } - if (retval.windowOne == null) { retval.windowOne = createWindowOne(); } - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "exit create workbook from existing file function"); - } + LOG.log(DEBUG, "exit create workbook from existing file function"); return retval; } /** * Creates an empty workbook object with three blank sheets and all the empty * fields. Use this to create a workbook from scratch. - * + * * @return an empty workbook object */ - public static InternalWorkbook createWorkbook() - { - if (log.check( POILogger.DEBUG )) { - log.log( DEBUG, "creating new workbook from scratch" ); - } + public static InternalWorkbook createWorkbook() { + LOG.log( DEBUG, "creating new workbook from scratch" ); + InternalWorkbook retval = new InternalWorkbook(); List records = new ArrayList( 30 ); retval.records.setRecords(records); @@ -484,9 +450,8 @@ public final class InternalWorkbook { records.add(InternalWorkbook.createExtendedSST()); records.add(EOFRecord.instance); - if (log.check( POILogger.DEBUG )) { - log.log( DEBUG, "exit create new workbook from scratch" ); - } + LOG.log( DEBUG, "exit create new workbook from scratch" ); + return retval; } @@ -544,12 +509,12 @@ public final class InternalWorkbook { /** * Retrieves the index of the given font - * + * * @param font the font - * + * * @return the font index - * - * @throws IllegalArgumentException if the font index can't be determined + * + * @throws IllegalArgumentException if the font index can't be determined */ public int getFontIndex(FontRecord font) { for(int i=0; i<=numfonts; i++) { @@ -557,10 +522,7 @@ public final class InternalWorkbook { ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + i); if(thisFont == font) { // There is no 4! - if(i > 3) { - return (i+1); - } - return i; + return (i > 3) ? i+1 : i; } } throw new IllegalArgumentException("Could not find that font!"); @@ -588,7 +550,7 @@ public final class InternalWorkbook { * file's list. This will make all * subsequent font indicies drop by one, * so you'll need to update those yourself! - * + * * @param rec the font record */ public void removeFontRecord(FontRecord rec) { @@ -614,10 +576,8 @@ public final class InternalWorkbook { */ public void setSheetBof(int sheetIndex, int pos) { - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "setting bof for sheetnum =", Integer.valueOf(sheetIndex), - " at pos=", Integer.valueOf(pos)); - } + LOG.log(DEBUG, "setting bof for sheetnum =", sheetIndex, " at pos=", pos); + checkSheets(sheetIndex); getBoundSheetRec(sheetIndex) .setPositionOfBof(pos); @@ -629,7 +589,7 @@ public final class InternalWorkbook { /** * Returns the position of the backup record. - * + * * @return the position of the backup record */ public BackupRecord getBackupRecord() { @@ -645,16 +605,14 @@ public final class InternalWorkbook { * @param sheetnum the sheet number (0 based) * @param sheetname the name for the sheet */ - public void setSheetName(int sheetnum, String sheetname) { + public void setSheetName(int sheetnum, final String sheetname) { checkSheets(sheetnum); // YK: Mimic Excel and silently truncate sheet names longer than 31 characters - if(sheetname.length() > 31) { - sheetname = sheetname.substring(0, 31); - } + String sn = (sheetname.length() > 31) ? sheetname.substring(0, 31) : sheetname; BoundSheetRecord sheet = boundsheets.get(sheetnum); - sheet.setSheetname(sheetname); + sheet.setSheetname(sn); } /** @@ -670,9 +628,9 @@ public final class InternalWorkbook { if (aName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) { aName = aName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN); } - for (int i = 0; i < boundsheets.size(); i++) { - BoundSheetRecord boundSheetRecord = getBoundSheetRec(i); - if (excludeSheetIdx == i) { + int i=0; + for (BoundSheetRecord boundSheetRecord : boundsheets) { + if (excludeSheetIdx == i++) { continue; } String bName = boundSheetRecord.getSheetname(); @@ -696,7 +654,7 @@ public final class InternalWorkbook { int sheetNumber = getSheetIndex(sheetname); //remove the sheet that needs to be reordered and place it in the spot we want boundsheets.add(pos, boundsheets.remove(sheetNumber)); - + // also adjust order of Records, calculate the position of the Boundsheets via getBspos()... int initialBspos = records.getBspos(); int pos0 = initialBspos - (boundsheets.size() - 1); @@ -741,7 +699,7 @@ public final class InternalWorkbook { public boolean isSheetVeryHidden(int sheetnum) { return getBoundSheetRec(sheetnum).isVeryHidden(); } - + /** * Gets the hidden flag for a given sheet. * Note that a sheet could instead be @@ -856,7 +814,7 @@ public final class InternalWorkbook { nr.setSheetNumber(nr.getSheetNumber()-1); } } - + if (linkTable != null) { // also tell the LinkTable about the removed sheet //index hasn't change in the linktable @@ -893,9 +851,7 @@ public final class InternalWorkbook { */ public int getNumSheets() { - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "getNumSheets=", Integer.valueOf(boundsheets.size())); - } + LOG.log(DEBUG, "getNumSheets=", boundsheets.size()); return boundsheets.size(); } @@ -906,9 +862,7 @@ public final class InternalWorkbook { */ public int getNumExFormats() { - if (log.check( POILogger.DEBUG )) { - log.log(DEBUG, "getXF=", Integer.valueOf(numxfs)); - } + LOG.log(DEBUG, "getXF=", numxfs); return numxfs; } @@ -934,14 +888,14 @@ public final class InternalWorkbook { * file's list. This will make all * subsequent font indicies drop by one, * so you'll need to update those yourself! - * + * * @param rec the ExtendedFormatRecord */ public void removeExFormatRecord(ExtendedFormatRecord rec) { records.remove(rec); // this updates XfPos for us numxfs--; } - + /** * Removes ExtendedFormatRecord record with given index from the * file's list. This will make all @@ -976,9 +930,9 @@ public final class InternalWorkbook { * Returns the StyleRecord for the given * xfIndex, or null if that ExtendedFormat doesn't * have a Style set. - * + * * @param xfIndex the extended format index - * + * * @return the StyleRecord, {@code null} if it that ExtendedFormat doesn't have a Style set. */ public StyleRecord getStyleRecord(int xfIndex) { @@ -986,27 +940,23 @@ public final class InternalWorkbook { // the ExtendedFormat records for(int i=records.getXfpos(); i 0) { @@ -1189,30 +1093,21 @@ public final class InternalWorkbook { } private void updateEncryptionRecord() { - FilePassRecord fpr = null; - int fprPos = -1; - for (Record r : records.getRecords()) { - fprPos++; - if (r instanceof FilePassRecord) { - fpr = (FilePassRecord)r; - break; - } - } - + FilePassRecord fpr = (FilePassRecord)findFirstRecordBySid(FilePassRecord.sid); + String password = Biff8EncryptionKey.getCurrentUserPassword(); if (password == null) { if (fpr != null) { // need to remove password data - records.remove(fprPos); + records.remove(fpr); } - return; } else { // create password record if (fpr == null) { fpr = new FilePassRecord(EncryptionMode.binaryRC4); records.add(1, fpr); } - + // check if the password has been changed EncryptionInfo ei = fpr.getEncryptionInfo(); byte encVer[] = ei.getVerifier().getEncryptedVerifier(); @@ -1230,21 +1125,18 @@ public final class InternalWorkbook { } } } - - public int getSize() - { + + public int getSize() { int retval = 0; - SSTRecord sst = null; - for ( int k = 0; k < records.size(); k++ ) - { - Record record = records.get( k ); + SSTRecord lSST = null; + for ( Record record : records ) { if (record instanceof SSTRecord) { - sst = (SSTRecord)record; + lSST = (SSTRecord)record; } - if (record.getSid() == ExtSSTRecord.sid && sst != null) { - retval += sst.calcExtSSTRecordSize(); + if (record.getSid() == ExtSSTRecord.sid && lSST != null) { + retval += lSST.calcExtSSTRecordSize(); } else { retval += record.getRecordSize(); } @@ -1260,7 +1152,8 @@ public final class InternalWorkbook { retval.setType(BOFRecord.TYPE_WORKBOOK); retval.setBuild(( short ) 0x10d3); retval.setBuildYear(( short ) 1996); - retval.setHistoryBitMask(0x41); // was c1 before verify + // was c1 before verify + retval.setHistoryBitMask(0x41); retval.setRequiredVersion(0x6); return retval; } @@ -1290,9 +1183,10 @@ public final class InternalWorkbook { retval.setUsername(username); } catch (AccessControlException e) { - // AccessControlException can occur in a restricted context - // (client applet/jws application or restricted security server) - retval.setUsername(defaultUserName); + LOG.log(POILogger.WARN, "can't determine user.name", e); + // AccessControlException can occur in a restricted context + // (client applet/jws application or restricted security server) + retval.setUsername(defaultUserName); } return retval; } @@ -1471,21 +1365,12 @@ public final class InternalWorkbook { * a file as M$ Excel would create it.) */ private static FormatRecord createFormat(int id) { - // we'll need multiple editions for - // the different formats - - - switch (id) { - case 0: return new FormatRecord(5, BuiltinFormats.getBuiltinFormat(5)); - case 1: return new FormatRecord(6, BuiltinFormats.getBuiltinFormat(6)); - case 2: return new FormatRecord(7, BuiltinFormats.getBuiltinFormat(7)); - case 3: return new FormatRecord(8, BuiltinFormats.getBuiltinFormat(8)); - case 4: return new FormatRecord(0x2a, BuiltinFormats.getBuiltinFormat(0x2a)); - case 5: return new FormatRecord(0x29, BuiltinFormats.getBuiltinFormat(0x29)); - case 6: return new FormatRecord(0x2c, BuiltinFormats.getBuiltinFormat(0x2c)); - case 7: return new FormatRecord(0x2b, BuiltinFormats.getBuiltinFormat(0x2b)); + // we'll need multiple editions for the different formats + final int mappings[] = { 5, 6, 7, 8, 0x2a, 0x29, 0x2c, 0x2b }; + if (id < 0 || id >= mappings.length) { + throw new IllegalArgumentException("Unexpected id " + id); } - throw new IllegalArgumentException("Unexpected id " + id); + return new FormatRecord(mappings[id], BuiltinFormats.getBuiltinFormat(mappings[id])); } /** @@ -1493,335 +1378,62 @@ public final class InternalWorkbook { * @param id the number of the extended format record to create (meaning its position in * a file as MS Excel would create it.) */ - private static ExtendedFormatRecord createExtendedFormat(int id) { // we'll need multiple editions - ExtendedFormatRecord retval = new ExtendedFormatRecord(); - + private static ExtendedFormatRecord createExtendedFormat(int id) { + // we'll need multiple editions switch (id) { + case 0: return createExtendedFormat(0, 0, 0xfffffff5, 0); + case 1: + case 2: return createExtendedFormat(1, 0, 0xfffffff5, 0xfffff400); + case 3: + case 4: return createExtendedFormat(2, 0, 0xfffffff5, 0xfffff400); + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: return createExtendedFormat(0, 0, 0xfffffff5, 0xfffff400); + // cell records + case 15: return createExtendedFormat(0, 0, 1, 0); + // style + case 16: return createExtendedFormat(1, 0x2b, 0xfffffff5, 0xfffff800); + case 17: return createExtendedFormat(1, 0x29, 0xfffffff5, 0xfffff800); + case 18: return createExtendedFormat(1, 0x2c, 0xfffffff5, 0xfffff800); + case 19: return createExtendedFormat(1, 0x2a, 0xfffffff5, 0xfffff800); + case 20: return createExtendedFormat(1, 0x09, 0xfffffff5, 0xfffff800); + // unused from this point down + case 21: return createExtendedFormat(5, 0, 1, 0x800); + case 22: return createExtendedFormat(6, 0, 1, 0x5c00); + case 23: return createExtendedFormat(0, 0x31, 1, 0x5c00); + case 24: return createExtendedFormat(0, 8, 1, 0x5c00); + case 25: return createExtendedFormat(6, 8, 1, 0x5c00); - case 0 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 1 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 2 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 3 : - retval.setFontIndex(( short ) 2); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 4 : - retval.setFontIndex(( short ) 2); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 5 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 6 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 7 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 8 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 9 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 10 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 11 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 12 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 13 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 14 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff400); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - // cell records - case 15 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x0); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - // style - case 16 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x2b); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 17 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x29); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 18 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x2c); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 19 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x2a); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 20 : - retval.setFontIndex(( short ) 1); - retval.setFormatIndex(( short ) 0x9); - retval.setCellOptions(( short ) 0xfffffff5); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0xfffff800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - // unused from this point down - case 21 : - retval.setFontIndex(( short ) 5); - retval.setFormatIndex(( short ) 0x0); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x800); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 22 : - retval.setFontIndex(( short ) 6); - retval.setFormatIndex(( short ) 0x0); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x5c00); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 23 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0x31); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x5c00); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 24 : - retval.setFontIndex(( short ) 0); - retval.setFormatIndex(( short ) 0x8); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x5c00); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - case 25 : - retval.setFontIndex(( short ) 6); - retval.setFormatIndex(( short ) 0x8); - retval.setCellOptions(( short ) 0x1); - retval.setAlignmentOptions(( short ) 0x20); - retval.setIndentionOptions(( short ) 0x5c00); - retval.setBorderOptions(( short ) 0); - retval.setPaletteOptions(( short ) 0); - retval.setAdtlPaletteOptions(( short ) 0); - retval.setFillPaletteOptions(( short ) 0x20c0); - break; - - default: - throw new IllegalStateException("Unrecognized format id: " + id); + default: throw new IllegalStateException("Unrecognized format id: " + id); } + } + + private static ExtendedFormatRecord createExtendedFormat( + int fontIndex, int formatIndex, int cellOptions, int indentionOptions + ) { + ExtendedFormatRecord retval = new ExtendedFormatRecord(); + retval.setFontIndex(( short ) fontIndex); + retval.setFormatIndex(( short ) formatIndex); + retval.setCellOptions(( short ) cellOptions); + retval.setAlignmentOptions(( short ) 0x20); + retval.setIndentionOptions(( short ) indentionOptions); + retval.setBorderOptions(( short ) 0); + retval.setPaletteOptions(( short ) 0); + retval.setAdtlPaletteOptions(( short ) 0); + retval.setFillPaletteOptions(( short ) 0x20c0); return retval; } /** * creates an default cell type ExtendedFormatRecord object. - * @return ExtendedFormatRecord with intial defaults (cell-type) + * @return ExtendedFormatRecord with initial defaults (cell-type) */ private static ExtendedFormatRecord createExtendedFormat() { ExtendedFormatRecord retval = new ExtendedFormatRecord(); @@ -1847,50 +1459,19 @@ public final class InternalWorkbook { * @param id the number of the style record to create (meaning its position in * a file as MS Excel would create it. */ - private static StyleRecord createStyle(int id) { // we'll need multiple editions - StyleRecord retval = new StyleRecord(); - - switch (id) { - - case 0 : - retval.setXFIndex(0x010); - retval.setBuiltinStyle(3); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 1 : - retval.setXFIndex(0x011); - retval.setBuiltinStyle(6); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 2 : - retval.setXFIndex(0x012); - retval.setBuiltinStyle(4); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 3 : - retval.setXFIndex(0x013); - retval.setBuiltinStyle(7); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 4 : - retval.setXFIndex(0x000); - retval.setBuiltinStyle(0); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - case 5 : - retval.setXFIndex(0x014); - retval.setBuiltinStyle(5); - retval.setOutlineStyleLevel(( byte ) 0xffffffff); - break; - - default: - throw new IllegalStateException("Unrecognized style id: " + id); + private static StyleRecord createStyle(int id) { + // we'll need multiple editions + final int mappings[][] = { + { 0x010, 3 }, { 0x011, 6 }, { 0x012, 4 }, { 0x013, 7 }, { 0x000, 0 }, { 0x014, 5 } + }; + if (id < 0 || id >= mappings.length) { + throw new IllegalArgumentException("Unexpected style id " + id); } + + StyleRecord retval = new StyleRecord(); + retval.setOutlineStyleLevel(( byte ) 0xffffffff); + retval.setXFIndex(mappings[id][0]); + retval.setBuiltinStyle(mappings[id][1]); return retval; } @@ -1930,10 +1511,9 @@ public final class InternalWorkbook { retval.setDefaultCountry(( short ) 1); // from Russia with love ;) - if ( LocaleUtil.getUserLocale().toString().equals( "ru_RU" ) ) { + if ( "ru_RU".equals( LocaleUtil.getUserLocale().toString() ) ) { retval.setCurrentCountry(( short ) 7); - } - else { + } else { retval.setCurrentCountry(( short ) 1); } @@ -1961,12 +1541,12 @@ public final class InternalWorkbook { } return linkTable; } - + public int linkExternalWorkbook(String name, Workbook externalWorkbook) { return getOrCreateLinkTable().linkExternalWorkbook(name, externalWorkbook); } - /** + /** * Finds the first sheet name by his extern sheet index * @param externSheetIndex extern sheet index * @return first sheet name. @@ -1991,7 +1571,7 @@ public final class InternalWorkbook { } return getSheetName(internalSheetIndex); } - + public ExternalSheet getExternalSheet(int externSheetIndex) { String[] extNames = linkTable.getExternalBookAndSheetName(externSheetIndex); if (extNames == null) { @@ -2033,7 +1613,7 @@ public final class InternalWorkbook { return linkTable.getLastInternalSheetIndexForExtIndex(externSheetNumber); } - /** + /** * Returns the extern sheet number for specific sheet number. * If this sheet doesn't exist in extern sheet, add it * @param sheetNumber local sheet number @@ -2042,7 +1622,7 @@ public final class InternalWorkbook { public short checkExternSheet(int sheetNumber){ return (short)getOrCreateLinkTable().checkExternSheet(sheetNumber); } - /** + /** * Returns the extern sheet number for specific range of sheets. * If this sheet range doesn't exist in extern sheet, add it * @param firstSheetNumber first local sheet number @@ -2100,25 +1680,21 @@ public final class InternalWorkbook { /** * adds a name record - * + * * @param name the name record to be added - * @return the given name record + * @return the given name record */ - public NameRecord addName(NameRecord name) - { - - LinkTable linkTable = getOrCreateLinkTable(); - linkTable.addName(name); - + public NameRecord addName(NameRecord name) { + getOrCreateLinkTable().addName(name); return name; } /** * Generates a NameRecord to represent a built-in region - * + * * @param builtInName the built-in name * @param sheetNumber the sheet number - * + * * @return a new NameRecord */ public NameRecord createBuiltInName(byte builtInName, int sheetNumber) { @@ -2152,7 +1728,7 @@ public final class InternalWorkbook { /** * If a {@link NameCommentRecord} is added or the name it references * is renamed, then this will update the lookup cache for it. - * + * * @param commentRecord the comment record */ public void updateNameCommentRecordCache(final NameCommentRecord commentRecord) { @@ -2221,9 +1797,9 @@ public final class InternalWorkbook { /** * Returns the first occurance of a record matching a particular sid. - * + * * @param sid the sid - * + * * @return the matching record or {@code null} if it wasn't found */ public Record findFirstRecordBySid(short sid) { @@ -2253,19 +1829,17 @@ public final class InternalWorkbook { /** * Returns the next occurance of a record matching a particular sid. - * + * * @param sid the sid * @param pos specifies the n-th matching sid - * + * * @return the matching record or {@code null} if it wasn't found */ public Record findNextRecordBySid(short sid, int pos) { int matches = 0; for (Record record : records) { - if (record.getSid() == sid) { - if (matches++ == pos) { - return record; - } + if (record.getSid() == sid && matches++ == pos) { + return record; } } return null; @@ -2293,34 +1867,31 @@ public final class InternalWorkbook { /** * Returns the custom palette in use for this workbook; if a custom palette record * does not exist, then it is created. - * + * * @return the custom palette */ - public PaletteRecord getCustomPalette() - { - PaletteRecord palette; - int palettePos = records.getPalettepos(); - if (palettePos != -1) { - Record rec = records.get(palettePos); - if (rec instanceof PaletteRecord) { - palette = (PaletteRecord) rec; + public PaletteRecord getCustomPalette() { + PaletteRecord palette; + int palettePos = records.getPalettepos(); + if (palettePos != -1) { + Record rec = records.get(palettePos); + if (rec instanceof PaletteRecord) { + palette = (PaletteRecord) rec; + } else { + throw new RuntimeException("InternalError: Expected PaletteRecord but got a '"+rec+"'"); + } } else { - throw new RuntimeException("InternalError: Expected PaletteRecord but got a '"+rec+"'"); + palette = createPalette(); + //Add the palette record after the bof which is always the first record + records.add(1, palette); + records.setPalettepos(1); } - } - else - { - palette = createPalette(); - //Add the palette record after the bof which is always the first record - records.add(1, palette); - records.setPalettepos(1); - } - return palette; + return palette; } /** * Finds the primary drawing group, if one already exists - * + * * @return the primary drawing group */ public DrawingManager2 findDrawingGroup() { @@ -2328,72 +1899,60 @@ public final class InternalWorkbook { // We already have it! return drawingManager; } - - // Need to find a DrawingGroupRecord that - // contains a EscherDggRecord + + // Need to find a DrawingGroupRecord that contains a EscherDggRecord for(Record r : records) { - if(r instanceof DrawingGroupRecord) { - DrawingGroupRecord dg = (DrawingGroupRecord)r; - dg.processChildRecords(); - - EscherContainerRecord cr = - dg.getEscherContainer(); - if(cr == null) { - continue; - } - - EscherDggRecord dgg = null; - EscherContainerRecord bStore = null; - for(EscherRecord er : cr) { - if(er instanceof EscherDggRecord) { - dgg = (EscherDggRecord)er; - } else if (er.getRecordId() == EscherContainerRecord.BSTORE_CONTAINER) { - bStore = (EscherContainerRecord) er; - } - } - - if(dgg != null) { - drawingManager = new DrawingManager2(dgg); - if(bStore != null){ - for(EscherRecord bs : bStore.getChildRecords()){ - if(bs instanceof EscherBSERecord) { - escherBSERecords.add((EscherBSERecord)bs); - } - } - } - return drawingManager; - } + if (!(r instanceof DrawingGroupRecord)) { + continue; + } + DrawingGroupRecord dg = (DrawingGroupRecord)r; + dg.processChildRecords(); + drawingManager = findDrawingManager(dg, escherBSERecords); + if (drawingManager != null) { + return drawingManager; } } + // TODO: we've already scanned the records, why should this work any better now? // Look for the DrawingGroup record - int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid); - + DrawingGroupRecord dg = (DrawingGroupRecord)findFirstRecordBySid(DrawingGroupRecord.sid); + drawingManager = findDrawingManager(dg, escherBSERecords); + return drawingManager; + } + + private static DrawingManager2 findDrawingManager(DrawingGroupRecord dg, List escherBSERecords) { + if (dg == null) { + return null; + } // If there is one, does it have a EscherDggRecord? - if(dgLoc != -1) { - DrawingGroupRecord dg = (DrawingGroupRecord)records.get(dgLoc); - EscherDggRecord dgg = null; - EscherContainerRecord bStore = null; - for(EscherRecord er : dg.getEscherRecords()) { - if (er instanceof EscherDggRecord) { - dgg = (EscherDggRecord) er; - } else if (er.getRecordId() == EscherContainerRecord.BSTORE_CONTAINER) { - bStore = (EscherContainerRecord) er; - } - } + EscherContainerRecord cr = dg.getEscherContainer(); + if (cr == null) { + return null; + } - if(dgg != null) { - drawingManager = new DrawingManager2(dgg); - if(bStore != null){ - for(EscherRecord bs : bStore.getChildRecords()){ - if(bs instanceof EscherBSERecord) { - escherBSERecords.add((EscherBSERecord)bs); - } - } + EscherDggRecord dgg = null; + EscherContainerRecord bStore = null; + for(EscherRecord er : cr) { + if (er instanceof EscherDggRecord) { + dgg = (EscherDggRecord) er; + } else if (er.getRecordId() == EscherContainerRecord.BSTORE_CONTAINER) { + bStore = (EscherContainerRecord) er; + } + } + + if(dgg == null) { + return null; + } + + DrawingManager2 dm = new DrawingManager2(dgg); + if(bStore != null){ + for(EscherRecord bs : bStore.getChildRecords()){ + if(bs instanceof EscherBSERecord) { + escherBSERecords.add((EscherBSERecord)bs); } } } - return drawingManager; + return dm; } /** @@ -2417,7 +1976,7 @@ public final class InternalWorkbook { dgg.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {} ); drawingManager = new DrawingManager2(dgg); EscherContainerRecord bstoreContainer = null; - if (escherBSERecords.size() > 0) + if (!escherBSERecords.isEmpty()) { bstoreContainer = new EscherContainerRecord(); bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER ); @@ -2483,9 +2042,7 @@ public final class InternalWorkbook { if (dggContainer.getChild( 1 ).getRecordId() == EscherContainerRecord.BSTORE_CONTAINER ) { bstoreContainer = (EscherContainerRecord) dggContainer.getChild( 1 ); - } - else - { + } else { bstoreContainer = new EscherContainerRecord(); bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER ); List childRecords = dggContainer.getChildRecords(); @@ -2507,11 +2064,7 @@ public final class InternalWorkbook { public WriteProtectRecord getWriteProtect() { if (writeProtect == null) { writeProtect = new WriteProtectRecord(); - int i = 0; - for (i = 0; - i < records.size() && !(records.get(i) instanceof BOFRecord); - i++) { - } + int i = findFirstRecordLocBySid(BOFRecord.sid); records.add(i+1, writeProtect); } return this.writeProtect; @@ -2520,11 +2073,7 @@ public final class InternalWorkbook { public WriteAccessRecord getWriteAccess() { if (writeAccess == null) { writeAccess = createWriteAccess(); - int i = 0; - for (i = 0; - i < records.size() && !(records.get(i) instanceof InterfaceEndRecord); - i++) { - } + int i = findFirstRecordLocBySid(InterfaceEndRecord.sid); records.add(i+1, writeAccess); } return writeAccess; @@ -2533,11 +2082,7 @@ public final class InternalWorkbook { public FileSharingRecord getFileSharing() { if (fileShare == null) { fileShare = new FileSharingRecord(); - int i = 0; - for (i = 0; - i < records.size() && !(records.get(i) instanceof WriteAccessRecord); - i++) { - } + int i = findFirstRecordLocBySid(WriteAccessRecord.sid); records.add(i+1, fileShare); } return fileShare; @@ -2545,7 +2090,7 @@ public final class InternalWorkbook { /** * is the workbook protected with a password (not encrypted)? - * + * * @return {@code true} if the workbook is write protected */ public boolean isWriteProtected() { @@ -2559,7 +2104,7 @@ public final class InternalWorkbook { /** * protect a workbook with a password (not encypted, just sets writeprotect * flags and the password. - * + * * @param password the password * @param username the username */ @@ -2631,61 +2176,61 @@ public final class InternalWorkbook { //check if the cloned sheet has drawings int aggLoc = sheet.aggregateDrawingRecords(drawingManager, false); - if(aggLoc != -1) { - EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid); - EscherContainerRecord escherContainer = agg.getEscherContainer(); - if (escherContainer == null) { - return; - } + if(aggLoc == -1) { + return; + } + + EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid); + EscherContainerRecord escherContainer = agg.getEscherContainer(); + if (escherContainer == null) { + return; + } - EscherDggRecord dgg = drawingManager.getDgg(); + EscherDggRecord dgg = drawingManager.getDgg(); - //register a new drawing group for the cloned sheet - int dgId = drawingManager.findNewDrawingGroupId(); - dgg.addCluster( dgId, 0 ); - dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1); - - EscherDgRecord dg = null; - for(EscherRecord er : escherContainer) { - if(er instanceof EscherDgRecord) { - dg = (EscherDgRecord)er; - //update id of the drawing in the cloned sheet - dg.setOptions( (short) ( dgId << 4 ) ); - } else if (er instanceof EscherContainerRecord){ - // iterate over shapes and re-generate shapeId - EscherContainerRecord cp = (EscherContainerRecord)er; - for(Iterator spIt = cp.getChildRecords().iterator(); spIt.hasNext();) { - EscherContainerRecord shapeContainer = (EscherContainerRecord)spIt.next(); - for(EscherRecord shapeChildRecord : shapeContainer.getChildRecords()) { - int recordId = shapeChildRecord.getRecordId(); - if (recordId == EscherSpRecord.RECORD_ID){ - if (dg == null) { - throw new RecordFormatException("EscherDgRecord wasn't set/processed before."); - } - EscherSpRecord sp = (EscherSpRecord)shapeChildRecord; - int shapeId = drawingManager.allocateShapeId((short)dgId, dg); - //allocateShapeId increments the number of shapes. roll back to the previous value - dg.setNumShapes(dg.getNumShapes()-1); - sp.setShapeId(shapeId); - } else if (recordId == EscherOptRecord.RECORD_ID){ - EscherOptRecord opt = (EscherOptRecord)shapeChildRecord; - EscherSimpleProperty prop = (EscherSimpleProperty)opt.lookup( - EscherProperties.BLIP__BLIPTODISPLAY ); - if (prop != null){ - int pictureIndex = prop.getPropertyValue(); - // increment reference count for pictures - EscherBSERecord bse = getBSERecord(pictureIndex); - bse.setRef(bse.getRef() + 1); - } + //register a new drawing group for the cloned sheet + int dgId = drawingManager.findNewDrawingGroupId(); + dgg.addCluster( dgId, 0 ); + dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1); + EscherDgRecord dg = null; + for(EscherRecord er : escherContainer) { + if(er instanceof EscherDgRecord) { + dg = (EscherDgRecord)er; + //update id of the drawing in the cloned sheet + dg.setOptions( (short) ( dgId << 4 ) ); + } else if (er instanceof EscherContainerRecord){ + // iterate over shapes and re-generate shapeId + for(EscherRecord er2 : (EscherContainerRecord)er) { + for(EscherRecord shapeChildRecord : (EscherContainerRecord)er2) { + int recordId = shapeChildRecord.getRecordId(); + if (recordId == EscherSpRecord.RECORD_ID){ + if (dg == null) { + throw new RecordFormatException("EscherDgRecord wasn't set/processed before."); } + EscherSpRecord sp = (EscherSpRecord)shapeChildRecord; + int shapeId = drawingManager.allocateShapeId((short)dgId, dg); + //allocateShapeId increments the number of shapes. roll back to the previous value + dg.setNumShapes(dg.getNumShapes()-1); + sp.setShapeId(shapeId); + } else if (recordId == EscherOptRecord.RECORD_ID){ + EscherOptRecord opt = (EscherOptRecord)shapeChildRecord; + EscherSimpleProperty prop = (EscherSimpleProperty)opt.lookup( + EscherProperties.BLIP__BLIPTODISPLAY ); + if (prop != null){ + int pictureIndex = prop.getPropertyValue(); + // increment reference count for pictures + EscherBSERecord bse = getBSERecord(pictureIndex); + bse.setRef(bse.getRef() + 1); + } + } } } } } } - + public NameRecord cloneFilter(int filterDbNameIndex, int newSheetIndex){ NameRecord origNameRecord = getNameRecord(filterDbNameIndex); // copy original formula but adjust 3D refs to the new external sheet index @@ -2712,7 +2257,7 @@ public final class InternalWorkbook { } /** * Updates named ranges due to moving of cells - * + * * @param shifter the formula shifter */ public void updateNamesAfterCellShift(FormulaShifter shifter) { @@ -2743,10 +2288,10 @@ public final class InternalWorkbook { return record; } - + /** * Changes an external referenced file to another file. - * A formular in Excel which refers a cell in another file is saved in two parts: + * A formular in Excel which refers a cell in another file is saved in two parts: * The referenced file is stored in an reference table. the row/cell information is saved separate. * This method invokation will only change the reference in the lookup-table itself. * @param oldUrl The old URL to search for and which is to be replaced @@ -2756,4 +2301,4 @@ public final class InternalWorkbook { public boolean changeExternalReference(String oldUrl, String newUrl) { return linkTable.changeExternalReference(oldUrl, newUrl); } -} +} \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java index 1a6d8b8f4..bfacb4b19 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java @@ -19,11 +19,15 @@ package org.apache.poi.hwpf.converter; import static org.apache.poi.hwpf.converter.AbstractWordUtils.TWIPS_PER_INCH; import java.io.File; +import java.io.IOException; +import java.util.Deque; +import java.util.LinkedList; import java.util.List; -import java.util.Stack; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; @@ -56,8 +60,6 @@ import org.w3c.dom.Text; * This implementation doesn't create images or links to them. This can be * changed by overriding {@link #processImage(Element, boolean, Picture)} * method. - * - * @author Sergey Vladimirov (vlsergey {at} gmail {dot} com) */ @Beta public class WordToHtmlConverter extends AbstractWordConverter @@ -78,9 +80,27 @@ public class WordToHtmlConverter extends AbstractWordConverter } } - private static final POILogger logger = POILogFactory - .getLogger( WordToHtmlConverter.class ); + private static final POILogger logger = POILogFactory.getLogger( WordToHtmlConverter.class ); + private final Deque blocksProperies = new LinkedList(); + + private final HtmlDocumentFacade htmlDocumentFacade; + + private Element notes; + + /** + * Creates new instance of {@link WordToHtmlConverter}. Can be used for + * output several {@link HWPFDocument}s into single HTML document. + * + * @param document XML DOM Document used as HTML document + */ + public WordToHtmlConverter( Document document ) { + this.htmlDocumentFacade = new HtmlDocumentFacade( document ); + } + + public WordToHtmlConverter( HtmlDocumentFacade htmlDocumentFacade ) { + this.htmlDocumentFacade = htmlDocumentFacade; + } private static String getSectionStyle( Section section ) { @@ -110,20 +130,17 @@ public class WordToHtmlConverter extends AbstractWordConverter } /** - * Java main() interface to interact with {@link WordToHtmlConverter} + * Java main() interface to interact with {@link WordToHtmlConverter}

+ * + * Usage: WordToHtmlConverter infile outfile

* - *

- * Usage: WordToHtmlConverter infile outfile - *

* Where infile is an input .doc file ( Word 95-2007) which will be rendered * as HTML into outfile */ - public static void main( String[] args ) throws Exception - { - if ( args.length < 2 ) - { - System.err - .println( "Usage: WordToHtmlConverter " ); + public static void main( String[] args ) + throws IOException, ParserConfigurationException, TransformerException { + if ( args.length < 2 ) { + System.err.println( "Usage: WordToHtmlConverter " ); return; } @@ -144,9 +161,9 @@ public class WordToHtmlConverter extends AbstractWordConverter serializer.transform( domSource, streamResult ); } - static Document process( File docFile ) throws Exception + static Document process( File docFile ) throws IOException, ParserConfigurationException { - final HWPFDocumentCore wordDocument = WordToHtmlUtils.loadDoc( docFile ); + final HWPFDocumentCore wordDocument = AbstractWordUtils.loadDoc( docFile ); WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter( XMLHelper.getDocumentBuilderFactory().newDocumentBuilder() .newDocument() ); @@ -154,38 +171,17 @@ public class WordToHtmlConverter extends AbstractWordConverter return wordToHtmlConverter.getDocument(); } - private final Stack blocksProperies = new Stack(); - - private final HtmlDocumentFacade htmlDocumentFacade; - - private Element notes; - - /** - * Creates new instance of {@link WordToHtmlConverter}. Can be used for - * output several {@link HWPFDocument}s into single HTML document. - * - * @param document - * XML DOM Document used as HTML document - */ - public WordToHtmlConverter( Document document ) - { - this.htmlDocumentFacade = new HtmlDocumentFacade( document ); - } - - public WordToHtmlConverter( HtmlDocumentFacade htmlDocumentFacade ) - { - this.htmlDocumentFacade = htmlDocumentFacade; - } - @Override protected void afterProcess() { - if ( notes != null ) + if ( notes != null ) { htmlDocumentFacade.getBody().appendChild( notes ); + } htmlDocumentFacade.updateStylesheet(); } + @Override public Document getDocument() { return htmlDocumentFacade.getDocument(); @@ -202,8 +198,8 @@ public class WordToHtmlConverter extends AbstractWordConverter BlockProperies blockProperies = this.blocksProperies.peek(); Triplet triplet = getCharacterRunTriplet( characterRun ); - if ( WordToHtmlUtils.isNotEmpty( triplet.fontName ) - && !WordToHtmlUtils.equals( triplet.fontName, + if ( AbstractWordUtils.isNotEmpty( triplet.fontName ) + && !AbstractWordUtils.equals( triplet.fontName, blockProperies.pFontName ) ) { style.append( "font-family:" + triplet.fontName + ";" ); @@ -222,8 +218,9 @@ public class WordToHtmlConverter extends AbstractWordConverter } WordToHtmlUtils.addCharactersProperties( characterRun, style ); - if ( style.length() != 0 ) + if ( style.length() != 0 ) { htmlDocumentFacade.addStyleClass( span, "s", style.toString() ); + } Text textNode = htmlDocumentFacade.createText( text ); span.appendChild( textNode ); @@ -243,26 +240,31 @@ public class WordToHtmlConverter extends AbstractWordConverter parent = bookmarkElement; } - if ( range != null ) + if ( range != null ) { processCharacters( wordDocument, currentTableLevel, range, parent ); + } } @Override protected void processDocumentInformation( SummaryInformation summaryInformation ) { - if ( WordToHtmlUtils.isNotEmpty( summaryInformation.getTitle() ) ) + if ( AbstractWordUtils.isNotEmpty( summaryInformation.getTitle() ) ) { htmlDocumentFacade.setTitle( summaryInformation.getTitle() ); + } - if ( WordToHtmlUtils.isNotEmpty( summaryInformation.getAuthor() ) ) + if ( AbstractWordUtils.isNotEmpty( summaryInformation.getAuthor() ) ) { htmlDocumentFacade.addAuthor( summaryInformation.getAuthor() ); + } - if ( WordToHtmlUtils.isNotEmpty( summaryInformation.getKeywords() ) ) + if ( AbstractWordUtils.isNotEmpty( summaryInformation.getKeywords() ) ) { htmlDocumentFacade.addKeywords( summaryInformation.getKeywords() ); + } - if ( WordToHtmlUtils.isNotEmpty( summaryInformation.getComments() ) ) + if ( AbstractWordUtils.isNotEmpty( summaryInformation.getComments() ) ) { htmlDocumentFacade .addDescription( summaryInformation.getComments() ); + } } @Override @@ -318,11 +320,13 @@ public class WordToHtmlConverter extends AbstractWordConverter Element basicLink = htmlDocumentFacade.createHyperlink( hyperlink ); currentBlock.appendChild( basicLink ); - if ( textRange != null ) + if ( textRange != null ) { processCharacters( wordDocument, currentTableLevel, textRange, basicLink ); + } } + @Override protected void processImage( Element currentBlock, boolean inlined, Picture picture, String imageSourcePath ) { @@ -372,7 +376,7 @@ public class WordToHtmlConverter extends AbstractWordConverter } Element root; - if ( cropTop != 0 || cropRight != 0 || cropBottom != 0 || cropLeft != 0 ) + if ( Math.abs(cropTop)+Math.abs(cropRight)+Math.abs(cropBottom)+Math.abs(cropLeft) > 0 ) { float visibleWidth = Math .max( 0, imageWidth - cropLeft - cropRight ); @@ -482,6 +486,7 @@ public class WordToHtmlConverter extends AbstractWordConverter flow.appendChild( htmlDocumentFacade.createLineBreak() ); } + @Override protected void processPageref( HWPFDocumentCore hwpfDocument, Element currentBlock, Range textRange, int currentTableLevel, String pageref ) @@ -489,11 +494,13 @@ public class WordToHtmlConverter extends AbstractWordConverter Element basicLink = htmlDocumentFacade.createHyperlink( "#" + pageref ); currentBlock.appendChild( basicLink ); - if ( textRange != null ) + if ( textRange != null ) { processCharacters( hwpfDocument, currentTableLevel, textRange, basicLink ); + } } + @Override protected void processParagraph( HWPFDocumentCore hwpfDocument, Element parentElement, int currentTableLevel, Paragraph paragraph, String bulletText ) @@ -526,13 +533,13 @@ public class WordToHtmlConverter extends AbstractWordConverter else { pFontSize = -1; - pFontName = WordToHtmlUtils.EMPTY; + pFontName = AbstractWordUtils.EMPTY; } blocksProperies.push( new BlockProperies( pFontName, pFontSize ) ); } try { - if ( WordToHtmlUtils.isNotEmpty( bulletText ) ) + if ( AbstractWordUtils.isNotEmpty( bulletText ) ) { if ( bulletText.endsWith( "\t" ) ) { @@ -581,13 +588,15 @@ public class WordToHtmlConverter extends AbstractWordConverter blocksProperies.pop(); } - if ( style.length() > 0 ) + if ( style.length() > 0 ) { htmlDocumentFacade.addStyleClass( pElement, "p", style.toString() ); + } WordToHtmlUtils.compactSpans( pElement ); return; } + @Override protected void processSection( HWPFDocumentCore wordDocument, Section section, int sectionCounter ) { @@ -609,13 +618,14 @@ public class WordToHtmlConverter extends AbstractWordConverter Integer.MIN_VALUE ); } + @Override protected void processTable( HWPFDocumentCore hwpfDocument, Element flow, Table table ) { Element tableHeader = htmlDocumentFacade.createTableHeader(); Element tableBody = htmlDocumentFacade.createTableBody(); - final int[] tableCellEdges = WordToHtmlUtils + final int[] tableCellEdges = AbstractWordUtils .buildTableCellEdgesArray( table ); final int tableRows = table.numRows(); @@ -667,18 +677,21 @@ public class WordToHtmlConverter extends AbstractWordConverter currentEdgeIndex, tableCell ); currentEdgeIndex += colSpan; - if ( colSpan == 0 ) + if ( colSpan == 0 ) { continue; + } - if ( colSpan != 1 ) + if ( colSpan != 1 ) { tableCellElement.setAttribute( "colspan", String.valueOf( colSpan ) ); + } final int rowSpan = getNumberRowsSpanned( table, tableCellEdges, r, c, tableCell ); - if ( rowSpan > 1 ) + if ( rowSpan > 1 ) { tableCellElement.setAttribute( "rowspan", String.valueOf( rowSpan ) ); + } processParagraphes( hwpfDocument, tableCellElement, tableCell, table.getTableLevel() ); @@ -688,17 +701,19 @@ public class WordToHtmlConverter extends AbstractWordConverter tableCellElement.appendChild( htmlDocumentFacade .createParagraph() ); } - if ( tableCellStyle.length() > 0 ) + if ( tableCellStyle.length() > 0 ) { htmlDocumentFacade.addStyleClass( tableCellElement, tableCellElement.getTagName(), tableCellStyle.toString() ); + } tableRowElement.appendChild( tableCellElement ); } - if ( tableRowStyle.length() > 0 ) + if ( tableRowStyle.length() > 0 ) { tableRowElement.setAttribute( "class", htmlDocumentFacade .getOrCreateCssClass( "r", tableRowStyle.toString() ) ); + } if ( tableRow.isTableHeader() ) {