559 lines
16 KiB
Java
559 lines
16 KiB
Java
package jxl.write.biff;
|
|
|
|
import common.Assert;
|
|
import common.Logger;
|
|
import java.io.File;
|
|
import java.net.URL;
|
|
import java.util.ArrayList;
|
|
import jxl.CellType;
|
|
import jxl.Hyperlink;
|
|
import jxl.Range;
|
|
import jxl.Sheet;
|
|
import jxl.biff.CellReferenceHelper;
|
|
import jxl.biff.IntegerHelper;
|
|
import jxl.biff.SheetRangeImpl;
|
|
import jxl.biff.StringHelper;
|
|
import jxl.biff.Type;
|
|
import jxl.biff.WritableRecordData;
|
|
import jxl.write.Label;
|
|
import jxl.write.WritableCell;
|
|
import jxl.write.WritableSheet;
|
|
|
|
public class HyperlinkRecord extends WritableRecordData {
|
|
private static Logger logger = Logger.getLogger(HyperlinkRecord.class);
|
|
|
|
private int firstRow;
|
|
|
|
private int lastRow;
|
|
|
|
private int firstColumn;
|
|
|
|
private int lastColumn;
|
|
|
|
private URL url;
|
|
|
|
private File file;
|
|
|
|
private String location;
|
|
|
|
private String contents;
|
|
|
|
private LinkType linkType;
|
|
|
|
private byte[] data;
|
|
|
|
private Range range;
|
|
|
|
private WritableSheet sheet;
|
|
|
|
private boolean modified;
|
|
|
|
private static class LinkType {
|
|
private LinkType() {}
|
|
}
|
|
|
|
private static final LinkType urlLink = new LinkType();
|
|
|
|
private static final LinkType fileLink = new LinkType();
|
|
|
|
private static final LinkType uncLink = new LinkType();
|
|
|
|
private static final LinkType workbookLink = new LinkType();
|
|
|
|
private static final LinkType unknown = new LinkType();
|
|
|
|
protected HyperlinkRecord(Hyperlink h, WritableSheet s) {
|
|
super(Type.HLINK);
|
|
Assert.verify(h instanceof jxl.read.biff.HyperlinkRecord);
|
|
jxl.read.biff.HyperlinkRecord hl = (jxl.read.biff.HyperlinkRecord)h;
|
|
this.data = hl.getRecord().getData();
|
|
this.sheet = s;
|
|
this.firstRow = hl.getRow();
|
|
this.firstColumn = hl.getColumn();
|
|
this.lastRow = hl.getLastRow();
|
|
this.lastColumn = hl.getLastColumn();
|
|
this.range = (Range)new SheetRangeImpl((Sheet)s, this.firstColumn, this.firstRow, this.lastColumn, this.lastRow);
|
|
this.linkType = unknown;
|
|
if (hl.isFile()) {
|
|
this.linkType = fileLink;
|
|
this.file = hl.getFile();
|
|
} else if (hl.isURL()) {
|
|
this.linkType = urlLink;
|
|
this.url = hl.getURL();
|
|
} else if (hl.isLocation()) {
|
|
this.linkType = workbookLink;
|
|
this.location = hl.getLocation();
|
|
}
|
|
this.modified = false;
|
|
}
|
|
|
|
protected HyperlinkRecord(int col, int row, int lastcol, int lastrow, URL url, String desc) {
|
|
super(Type.HLINK);
|
|
this.firstColumn = col;
|
|
this.firstRow = row;
|
|
this.lastColumn = Math.max(this.firstColumn, lastcol);
|
|
this.lastRow = Math.max(this.firstRow, lastrow);
|
|
this.url = url;
|
|
this.contents = desc;
|
|
this.linkType = urlLink;
|
|
this.modified = true;
|
|
}
|
|
|
|
protected HyperlinkRecord(int col, int row, int lastcol, int lastrow, File file, String desc) {
|
|
super(Type.HLINK);
|
|
this.firstColumn = col;
|
|
this.firstRow = row;
|
|
this.lastColumn = Math.max(this.firstColumn, lastcol);
|
|
this.lastRow = Math.max(this.firstRow, lastrow);
|
|
this.contents = desc;
|
|
this.file = file;
|
|
if (file.getPath().startsWith("\\\\")) {
|
|
this.linkType = uncLink;
|
|
} else {
|
|
this.linkType = fileLink;
|
|
}
|
|
this.modified = true;
|
|
}
|
|
|
|
protected HyperlinkRecord(int col, int row, int lastcol, int lastrow, String desc, WritableSheet s, int destcol, int destrow, int lastdestcol, int lastdestrow) {
|
|
super(Type.HLINK);
|
|
this.firstColumn = col;
|
|
this.firstRow = row;
|
|
this.lastColumn = Math.max(this.firstColumn, lastcol);
|
|
this.lastRow = Math.max(this.firstRow, lastrow);
|
|
setLocation(s, destcol, destrow, lastdestcol, lastdestrow);
|
|
this.contents = desc;
|
|
this.linkType = workbookLink;
|
|
this.modified = true;
|
|
}
|
|
|
|
public boolean isFile() {
|
|
return (this.linkType == fileLink);
|
|
}
|
|
|
|
public boolean isUNC() {
|
|
return (this.linkType == uncLink);
|
|
}
|
|
|
|
public boolean isURL() {
|
|
return (this.linkType == urlLink);
|
|
}
|
|
|
|
public boolean isLocation() {
|
|
return (this.linkType == workbookLink);
|
|
}
|
|
|
|
public int getRow() {
|
|
return this.firstRow;
|
|
}
|
|
|
|
public int getColumn() {
|
|
return this.firstColumn;
|
|
}
|
|
|
|
public int getLastRow() {
|
|
return this.lastRow;
|
|
}
|
|
|
|
public int getLastColumn() {
|
|
return this.lastColumn;
|
|
}
|
|
|
|
public URL getURL() {
|
|
return this.url;
|
|
}
|
|
|
|
public File getFile() {
|
|
return this.file;
|
|
}
|
|
|
|
public byte[] getData() {
|
|
if (!this.modified)
|
|
return this.data;
|
|
byte[] commonData = new byte[32];
|
|
IntegerHelper.getTwoBytes(this.firstRow, commonData, 0);
|
|
IntegerHelper.getTwoBytes(this.lastRow, commonData, 2);
|
|
IntegerHelper.getTwoBytes(this.firstColumn, commonData, 4);
|
|
IntegerHelper.getTwoBytes(this.lastColumn, commonData, 6);
|
|
commonData[8] = -48;
|
|
commonData[9] = -55;
|
|
commonData[10] = -22;
|
|
commonData[11] = 121;
|
|
commonData[12] = -7;
|
|
commonData[13] = -70;
|
|
commonData[14] = -50;
|
|
commonData[15] = 17;
|
|
commonData[16] = -116;
|
|
commonData[17] = -126;
|
|
commonData[18] = 0;
|
|
commonData[19] = -86;
|
|
commonData[20] = 0;
|
|
commonData[21] = 75;
|
|
commonData[22] = -87;
|
|
commonData[23] = 11;
|
|
commonData[24] = 2;
|
|
commonData[25] = 0;
|
|
commonData[26] = 0;
|
|
commonData[27] = 0;
|
|
int optionFlags = 0;
|
|
if (isURL()) {
|
|
optionFlags = 3;
|
|
if (this.contents != null)
|
|
optionFlags |= 0x14;
|
|
} else if (isFile()) {
|
|
optionFlags = 3;
|
|
if (this.contents == null)
|
|
optionFlags |= 0x14;
|
|
} else if (isLocation()) {
|
|
optionFlags = 8;
|
|
} else if (isUNC()) {
|
|
optionFlags = 259;
|
|
}
|
|
IntegerHelper.getFourBytes(optionFlags, commonData, 28);
|
|
if (isURL()) {
|
|
this.data = getURLData(commonData);
|
|
} else if (isFile()) {
|
|
this.data = getFileData(commonData);
|
|
} else if (isLocation()) {
|
|
this.data = getLocationData(commonData);
|
|
} else if (isUNC()) {
|
|
this.data = getUNCData(commonData);
|
|
}
|
|
return this.data;
|
|
}
|
|
|
|
public String toString() {
|
|
if (isFile())
|
|
return this.file.toString();
|
|
if (isURL())
|
|
return this.url.toString();
|
|
if (isUNC())
|
|
return this.file.toString();
|
|
return "";
|
|
}
|
|
|
|
public Range getRange() {
|
|
return this.range;
|
|
}
|
|
|
|
public void setURL(URL url) {
|
|
this.linkType = urlLink;
|
|
this.file = null;
|
|
this.location = null;
|
|
this.contents = null;
|
|
this.url = url;
|
|
this.modified = true;
|
|
if (this.sheet == null)
|
|
return;
|
|
WritableCell wc = this.sheet.getWritableCell(this.firstColumn, this.firstRow);
|
|
Assert.verify((wc.getType() == CellType.LABEL));
|
|
Label l = (Label)wc;
|
|
l.setString(url.toString());
|
|
}
|
|
|
|
public void setFile(File file) {
|
|
this.linkType = fileLink;
|
|
this.url = null;
|
|
this.location = null;
|
|
this.contents = null;
|
|
this.file = file;
|
|
this.modified = true;
|
|
if (this.sheet == null)
|
|
return;
|
|
WritableCell wc = this.sheet.getWritableCell(this.firstColumn, this.firstRow);
|
|
Assert.verify((wc.getType() == CellType.LABEL));
|
|
Label l = (Label)wc;
|
|
l.setString(file.toString());
|
|
}
|
|
|
|
protected void setLocation(String desc, WritableSheet sheet, int destcol, int destrow, int lastdestcol, int lastdestrow) {
|
|
this.linkType = workbookLink;
|
|
this.url = null;
|
|
this.file = null;
|
|
this.modified = true;
|
|
this.contents = desc;
|
|
setLocation(sheet, destcol, destrow, lastdestcol, lastdestrow);
|
|
if (sheet == null)
|
|
return;
|
|
WritableCell wc = sheet.getWritableCell(this.firstColumn, this.firstRow);
|
|
Assert.verify((wc.getType() == CellType.LABEL));
|
|
Label l = (Label)wc;
|
|
l.setString(desc);
|
|
}
|
|
|
|
private void setLocation(WritableSheet sheet, int destcol, int destrow, int lastdestcol, int lastdestrow) {
|
|
StringBuffer sb = new StringBuffer();
|
|
sb.append('\'');
|
|
if (sheet.getName().indexOf('\'') == -1) {
|
|
sb.append(sheet.getName());
|
|
} else {
|
|
String sheetName = sheet.getName();
|
|
int pos = 0;
|
|
int nextPos = sheetName.indexOf('\'', pos);
|
|
while (nextPos != -1 && pos < sheetName.length()) {
|
|
sb.append(sheetName.substring(pos, nextPos));
|
|
sb.append("''");
|
|
pos = nextPos + 1;
|
|
nextPos = sheetName.indexOf('\'', pos);
|
|
}
|
|
sb.append(sheetName.substring(pos));
|
|
}
|
|
sb.append('\'');
|
|
sb.append('!');
|
|
lastdestcol = Math.max(destcol, lastdestcol);
|
|
lastdestrow = Math.max(destrow, lastdestrow);
|
|
CellReferenceHelper.getCellReference(destcol, destrow, sb);
|
|
sb.append(':');
|
|
CellReferenceHelper.getCellReference(lastdestcol, lastdestrow, sb);
|
|
this.location = sb.toString();
|
|
}
|
|
|
|
void insertRow(int r) {
|
|
Assert.verify((this.sheet != null && this.range != null));
|
|
if (r > this.lastRow)
|
|
return;
|
|
if (r <= this.firstRow) {
|
|
this.firstRow++;
|
|
this.modified = true;
|
|
}
|
|
if (r <= this.lastRow) {
|
|
this.lastRow++;
|
|
this.modified = true;
|
|
}
|
|
if (this.modified)
|
|
this.range = (Range)new SheetRangeImpl((Sheet)this.sheet, this.firstColumn, this.firstRow, this.lastColumn, this.lastRow);
|
|
}
|
|
|
|
void insertColumn(int c) {
|
|
Assert.verify((this.sheet != null && this.range != null));
|
|
if (c > this.lastColumn)
|
|
return;
|
|
if (c <= this.firstColumn) {
|
|
this.firstColumn++;
|
|
this.modified = true;
|
|
}
|
|
if (c <= this.lastColumn) {
|
|
this.lastColumn++;
|
|
this.modified = true;
|
|
}
|
|
if (this.modified)
|
|
this.range = (Range)new SheetRangeImpl((Sheet)this.sheet, this.firstColumn, this.firstRow, this.lastColumn, this.lastRow);
|
|
}
|
|
|
|
void removeRow(int r) {
|
|
Assert.verify((this.sheet != null && this.range != null));
|
|
if (r > this.lastRow)
|
|
return;
|
|
if (r < this.firstRow) {
|
|
this.firstRow--;
|
|
this.modified = true;
|
|
}
|
|
if (r < this.lastRow) {
|
|
this.lastRow--;
|
|
this.modified = true;
|
|
}
|
|
if (this.modified) {
|
|
Assert.verify((this.range != null));
|
|
this.range = (Range)new SheetRangeImpl((Sheet)this.sheet, this.firstColumn, this.firstRow, this.lastColumn, this.lastRow);
|
|
}
|
|
}
|
|
|
|
void removeColumn(int c) {
|
|
Assert.verify((this.sheet != null && this.range != null));
|
|
if (c > this.lastColumn)
|
|
return;
|
|
if (c < this.firstColumn) {
|
|
this.firstColumn--;
|
|
this.modified = true;
|
|
}
|
|
if (c < this.lastColumn) {
|
|
this.lastColumn--;
|
|
this.modified = true;
|
|
}
|
|
if (this.modified) {
|
|
Assert.verify((this.range != null));
|
|
this.range = (Range)new SheetRangeImpl((Sheet)this.sheet, this.firstColumn, this.firstRow, this.lastColumn, this.lastRow);
|
|
}
|
|
}
|
|
|
|
private byte[] getURLData(byte[] cd) {
|
|
String urlString = this.url.toString();
|
|
int dataLength = cd.length + 20 + (urlString.length() + 1) * 2;
|
|
if (this.contents != null)
|
|
dataLength += 4 + (this.contents.length() + 1) * 2;
|
|
byte[] d = new byte[dataLength];
|
|
System.arraycopy(cd, 0, d, 0, cd.length);
|
|
int urlPos = cd.length;
|
|
if (this.contents != null) {
|
|
IntegerHelper.getFourBytes(this.contents.length() + 1, d, urlPos);
|
|
StringHelper.getUnicodeBytes(this.contents, d, urlPos + 4);
|
|
urlPos += (this.contents.length() + 1) * 2 + 4;
|
|
}
|
|
d[urlPos] = -32;
|
|
d[urlPos + 1] = -55;
|
|
d[urlPos + 2] = -22;
|
|
d[urlPos + 3] = 121;
|
|
d[urlPos + 4] = -7;
|
|
d[urlPos + 5] = -70;
|
|
d[urlPos + 6] = -50;
|
|
d[urlPos + 7] = 17;
|
|
d[urlPos + 8] = -116;
|
|
d[urlPos + 9] = -126;
|
|
d[urlPos + 10] = 0;
|
|
d[urlPos + 11] = -86;
|
|
d[urlPos + 12] = 0;
|
|
d[urlPos + 13] = 75;
|
|
d[urlPos + 14] = -87;
|
|
d[urlPos + 15] = 11;
|
|
IntegerHelper.getFourBytes((urlString.length() + 1) * 2, d, urlPos + 16);
|
|
StringHelper.getUnicodeBytes(urlString, d, urlPos + 20);
|
|
return d;
|
|
}
|
|
|
|
private byte[] getUNCData(byte[] cd) {
|
|
String uncString = this.file.getPath();
|
|
byte[] d = new byte[cd.length + uncString.length() * 2 + 2 + 4];
|
|
System.arraycopy(cd, 0, d, 0, cd.length);
|
|
int urlPos = cd.length;
|
|
int length = uncString.length() + 1;
|
|
IntegerHelper.getFourBytes(length, d, urlPos);
|
|
StringHelper.getUnicodeBytes(uncString, d, urlPos + 4);
|
|
return d;
|
|
}
|
|
|
|
private byte[] getFileData(byte[] cd) {
|
|
ArrayList path = new ArrayList();
|
|
ArrayList shortFileName = new ArrayList();
|
|
path.add(this.file.getName());
|
|
shortFileName.add(getShortName(this.file.getName()));
|
|
File parent = this.file.getParentFile();
|
|
while (parent != null) {
|
|
path.add(parent.getName());
|
|
shortFileName.add(getShortName(parent.getName()));
|
|
parent = parent.getParentFile();
|
|
}
|
|
int upLevelCount = 0;
|
|
int pos = path.size() - 1;
|
|
boolean upDir = true;
|
|
while (upDir) {
|
|
String s = path.get(pos);
|
|
if (s.equals("..")) {
|
|
upLevelCount++;
|
|
path.remove(pos);
|
|
shortFileName.remove(pos);
|
|
} else {
|
|
upDir = false;
|
|
}
|
|
pos--;
|
|
}
|
|
StringBuffer filePathSB = new StringBuffer();
|
|
StringBuffer shortFilePathSB = new StringBuffer();
|
|
if (this.file.getPath().charAt(1) == ':') {
|
|
char driveLetter = this.file.getPath().charAt(0);
|
|
if (driveLetter != 'C' && driveLetter != 'c') {
|
|
filePathSB.append(driveLetter);
|
|
filePathSB.append(':');
|
|
shortFilePathSB.append(driveLetter);
|
|
shortFilePathSB.append(':');
|
|
}
|
|
}
|
|
for (int i = path.size() - 1; i >= 0; i--) {
|
|
filePathSB.append(path.get(i));
|
|
shortFilePathSB.append(shortFileName.get(i));
|
|
if (i != 0) {
|
|
filePathSB.append("\\");
|
|
shortFilePathSB.append("\\");
|
|
}
|
|
}
|
|
String filePath = filePathSB.toString();
|
|
String shortFilePath = shortFilePathSB.toString();
|
|
int dataLength = cd.length + 4 + (shortFilePath.length() + 1) * 2 + 16 + 2 + 4 + filePath.length() + 1 + 4 + 24;
|
|
if (this.contents != null)
|
|
dataLength += 4 + (this.contents.length() + 1) * 2;
|
|
byte[] d = new byte[dataLength];
|
|
System.arraycopy(cd, 0, d, 0, cd.length);
|
|
int filePos = cd.length;
|
|
if (this.contents != null) {
|
|
IntegerHelper.getFourBytes(this.contents.length() + 1, d, filePos);
|
|
StringHelper.getUnicodeBytes(this.contents, d, filePos + 4);
|
|
filePos += (this.contents.length() + 1) * 2 + 4;
|
|
}
|
|
int curPos = filePos;
|
|
IntegerHelper.getFourBytes(shortFilePath.length() + 1, d, curPos);
|
|
StringHelper.getUnicodeBytes(shortFilePath, d, curPos + 4);
|
|
curPos += 4 + (shortFilePath.length() + 1) * 2;
|
|
d[curPos] = 3;
|
|
d[curPos + 1] = 3;
|
|
d[curPos + 2] = 0;
|
|
d[curPos + 3] = 0;
|
|
d[curPos + 4] = 0;
|
|
d[curPos + 5] = 0;
|
|
d[curPos + 6] = 0;
|
|
d[curPos + 7] = 0;
|
|
d[curPos + 8] = -64;
|
|
d[curPos + 9] = 0;
|
|
d[curPos + 10] = 0;
|
|
d[curPos + 11] = 0;
|
|
d[curPos + 12] = 0;
|
|
d[curPos + 13] = 0;
|
|
d[curPos + 14] = 0;
|
|
d[curPos + 15] = 70;
|
|
curPos += 16;
|
|
IntegerHelper.getTwoBytes(upLevelCount, d, curPos);
|
|
curPos += 2;
|
|
IntegerHelper.getFourBytes(filePath.length() + 1, d, curPos);
|
|
curPos += 4;
|
|
StringHelper.getBytes(filePath, d, curPos);
|
|
curPos += filePath.length() + 1;
|
|
d[curPos] = -1;
|
|
d[curPos + 1] = -1;
|
|
d[curPos + 2] = -83;
|
|
d[curPos + 3] = -34;
|
|
return d;
|
|
}
|
|
|
|
private String getShortName(String s) {
|
|
int sep = s.indexOf('.');
|
|
String prefix = null;
|
|
String suffix = null;
|
|
if (sep == -1) {
|
|
prefix = s;
|
|
suffix = "";
|
|
} else {
|
|
prefix = s.substring(0, sep);
|
|
suffix = s.substring(sep + 1);
|
|
}
|
|
if (prefix.length() > 8) {
|
|
prefix = prefix.substring(0, 6) + "~" + (prefix.length() - 6);
|
|
prefix = prefix.substring(0, 8);
|
|
}
|
|
suffix = suffix.substring(0, Math.min(3, suffix.length()));
|
|
if (suffix.length() > 0)
|
|
return prefix + '.' + suffix;
|
|
return prefix;
|
|
}
|
|
|
|
private byte[] getLocationData(byte[] cd) {
|
|
byte[] d = new byte[cd.length + 4 + (this.location.length() + 1) * 2];
|
|
System.arraycopy(cd, 0, d, 0, cd.length);
|
|
int locPos = cd.length;
|
|
IntegerHelper.getFourBytes(this.location.length() + 1, d, locPos);
|
|
StringHelper.getUnicodeBytes(this.location, d, locPos + 4);
|
|
return d;
|
|
}
|
|
|
|
void initialize(WritableSheet s) {
|
|
this.sheet = s;
|
|
this.range = (Range)new SheetRangeImpl((Sheet)s, this.firstColumn, this.firstRow, this.lastColumn, this.lastRow);
|
|
}
|
|
|
|
String getContents() {
|
|
return this.contents;
|
|
}
|
|
|
|
protected void setContents(String desc) {
|
|
this.contents = desc;
|
|
this.modified = true;
|
|
}
|
|
}
|