//Keep offset of the topDICT so it can be updated once all data has been written
int topDictOffset = currentPos;
//Top DICT Index and Data
- byte[] topDictIndex = cffReader.getTopDictIndex().getByteData();
- int offSize = topDictIndex[2];
- writeBytes(topDictIndex, 0, 3 + (offSize * 2));
- int topDictDataOffset = currentPos;
- writeTopDICT();
+ int topDictDataOffset = topDictOffset + writeTopDICT();
//Create the char string index data and related local / global subroutines
if (cffReader.getFDSelect() == null) {
return fontNameSIDs;
}
- protected void writeTopDICT() throws IOException {
+ protected int writeTopDICT() throws IOException {
Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries();
List<String> topDictStringEntries = Arrays.asList("version", "Notice", "Copyright",
"FullName", "FamilyName", "Weight", "PostScript");
+ ByteArrayOutputStream dict = new ByteArrayOutputStream();
+ int offsetExtra = 0;
for (Map.Entry<String, DICTEntry> dictEntry : topDICT.entrySet()) {
String dictKey = dictEntry.getKey();
DICTEntry entry = dictEntry.getValue();
//If the value is an SID, update the reference but keep the size the same
- if (dictKey.equals("ROS")) {
- writeROSEntry(entry);
+ entry.setOffset(entry.getOffset() + offsetExtra);
+ if (dictKey.equals("CharStrings") && entry.getOperandLength() == 3) {
+ byte[] extra = new byte[2];
+ offsetExtra += extra.length;
+ dict.write(extra);
+ dict.write(entry.getByteData());
+ entry.setOperandLength(5);
+ } else if (dictKey.equals("ROS")) {
+ dict.write(writeROSEntry(entry));
} else if (dictKey.equals("CIDCount")) {
- writeCIDCount(entry);
+ dict.write(writeCIDCount(entry));
} else if (topDictStringEntries.contains(dictKey)) {
- writeTopDictStringEntry(entry);
+ dict.write(writeTopDictStringEntry(entry));
} else {
- writeBytes(entry.getByteData());
+ dict.write(entry.getByteData());
}
}
+ byte[] topDictIndex = cffReader.getTopDictIndex().getByteData();
+ int offSize = topDictIndex[2];
+ return writeIndex(Arrays.asList(dict.toByteArray()), offSize) - dict.size();
}
- private void writeROSEntry(DICTEntry dictEntry) throws IOException {
+ private byte[] writeROSEntry(DICTEntry dictEntry) throws IOException {
int sidA = dictEntry.getOperands().get(0).intValue();
if (sidA > 390) {
stringIndexData.add(cffReader.getStringIndex().getValue(sidA - NUM_STANDARD_STRINGS));
dictEntry.getOperandLengths().get(1), sidBStringIndex);
updateOffset(cidEntryByteData, dictEntry.getOperandLengths().get(0)
+ dictEntry.getOperandLengths().get(1), dictEntry.getOperandLengths().get(2), 0);
- writeBytes(cidEntryByteData);
+ return cidEntryByteData;
}
- protected void writeCIDCount(DICTEntry dictEntry) throws IOException {
+ protected byte[] writeCIDCount(DICTEntry dictEntry) throws IOException {
byte[] cidCountByteData = dictEntry.getByteData();
updateOffset(cidCountByteData, 0, dictEntry.getOperandLengths().get(0),
subsetGlyphs.size());
- writeBytes(cidCountByteData);
+ return cidCountByteData;
}
- private void writeTopDictStringEntry(DICTEntry dictEntry) throws IOException {
+ private byte[] writeTopDictStringEntry(DICTEntry dictEntry) throws IOException {
int sid = dictEntry.getOperands().get(0).intValue();
if (sid > 391) {
stringIndexData.add(cffReader.getStringIndex().getValue(sid - 391));
byte[] newDictEntry = createNewRef(stringIndexData.size() + 390, dictEntry.getOperator(),
dictEntry.getOperandLength(), true);
- writeBytes(newDictEntry);
+ return newDictEntry;
}
private void writeStringIndex() throws IOException {
}
protected int writeIndex(List<byte[]> dataArray) {
+ int totLength = 1;
+ for (byte[] aDataArray1 : dataArray) {
+ totLength += aDataArray1.length;
+ }
+ int offSize = getOffSize(totLength);
+ return writeIndex(dataArray, offSize);
+ }
+
+ protected int writeIndex(List<byte[]> dataArray, int offSize) {
int hdrTotal = 3;
//2 byte number of items
this.writeCard16(dataArray.size());
//Offset Size: 1 byte = 256, 2 bytes = 65536 etc.
//Offsets in the offset array are relative to the byte that precedes the object data.
//Therefore the first element of the offset array is always 1.
- int totLength = 1;
- for (byte[] aDataArray1 : dataArray) {
- totLength += aDataArray1.length;
- }
- int offSize = getOffSize(totLength);
this.writeByte(offSize);
//Count the first offset 1
hdrTotal += offSize;
}
protected void updateOffset(byte[] out, int position, int length, int replacement) {
+ if (length == 2 && replacement < 108 && replacement > -108) {
+ length = 1;
+ }
switch (length) {
case 1:
out[position] = (byte)(replacement + 139);
break;
case 2:
+ assert replacement <= 1131;
if (replacement <= -876) {
out[position] = (byte)254;
} else if (replacement <= -620) {
}
break;
case 3:
+ assert replacement <= 32767;
out[position] = (byte)28;
out[position + 1] = (byte)((replacement >> 8) & 0xFF);
out[position + 2] = (byte)(replacement & 0xFF);
@Test
public void testFDSelect() throws IOException {
- Assert.assertEquals(getSubset(1).length, 41);
- Assert.assertEquals(getSubset(2).length, 48);
+ Assert.assertEquals(getSubset(1).length, 43);
+ Assert.assertEquals(getSubset(2).length, 50);
}
private byte[] getSubset(final int opLen) throws IOException {
when(cffReader.getHeader()).thenReturn(new byte[0]);
when(cffReader.getTopDictIndex()).thenReturn(new CFFDataReader().new CFFIndexData() {
public byte[] getByteData() throws IOException {
- return new byte[3];
+ return new byte[] {0, 0, 1};
}
});
super.updateFixedOffsets(topDICT, dataTopDictOffset, charsetOffset, charStringOffset, encodingOffset);
}
}
+
+ @Test
+ public void testResizeOfOperand() throws IOException {
+ OTFSubSetFile otfSubSetFile = new OTFSubSetFile() {
+ protected void writeFDSelect() {
+ super.writeFDSelect();
+ writeBytes(new byte[1024 * 100]);
+ }
+ };
+ otfSubSetFile.readFont(sourceSansReader, "StandardOpenType", null, glyphs);
+ byte[] fontSubset = otfSubSetFile.getFontSubset();
+ CFFDataReader cffReader = new CFFDataReader(fontSubset);
+ assertEquals(cffReader.getTopDictEntries().get("CharStrings").getOperandLength(), 5);
+ assertEquals(cffReader.getTopDictEntries().get("CharStrings").getByteData().length, 6);
+ }
}