git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1151452 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_1rc1old
@@ -39,13 +39,12 @@ import org.apache.fop.afp.util.BinaryUtils; | |||
public abstract class AbstractAFPObject implements Streamable { | |||
/** Static logging instance */ | |||
protected static final Log LOG = LogFactory.getLog("org.apache.xmlgraphics.afp.modca"); | |||
protected static final Log LOG = LogFactory.getLog(AbstractAFPObject.class); | |||
/** the structured field class id */ | |||
protected static final byte SF_CLASS = (byte)0xD3; | |||
/** the structure field header */ | |||
static final byte[] SF_HEADER = new byte[] { | |||
private static final byte[] SF_HEADER = new byte[] { | |||
0x5A, // Structured field identifier | |||
0x00, // Length byte 1 | |||
0x10, // Length byte 2 | |||
@@ -57,6 +56,8 @@ public abstract class AbstractAFPObject implements Streamable { | |||
0x00, // Reserved | |||
}; | |||
protected static final int SF_HEADER_LENGTH = SF_HEADER.length; | |||
/** | |||
* Copies the template structured field data array to the given byte array | |||
* | |||
@@ -90,50 +91,18 @@ public abstract class AbstractAFPObject implements Streamable { | |||
* @param os The stream to write to | |||
* @throws java.io.IOException an I/O exception of some sort has occurred. | |||
*/ | |||
protected void writeObjects(Collection/*<Streamable>*/ objects, OutputStream os) | |||
throws IOException { | |||
if (objects != null && objects.size() > 0) { | |||
Iterator it = objects.iterator(); | |||
protected <S extends Streamable> void writeObjects(Collection<S> objects, OutputStream os) | |||
throws IOException { | |||
if (objects != null) { | |||
Iterator<S> it = objects.iterator(); | |||
while (it.hasNext()) { | |||
Object object = it.next(); | |||
if (object instanceof Streamable) { | |||
((Streamable)object).writeToStream(os); | |||
it.remove(); // once written, immediately remove the object | |||
} | |||
Streamable s = it.next(); | |||
s.writeToStream(os); | |||
it.remove(); // once written, immediately remove the object | |||
} | |||
} | |||
} | |||
/** | |||
* Reads data chunks from an InputStream | |||
* and then formats them with a structured header to a given OutputStream | |||
* | |||
* @param dataHeader the header data | |||
* @param lengthOffset offset of length field in data chunk | |||
* @param maxChunkLength the maximum chunk length | |||
* @param inputStream the InputStream to read from | |||
* @param outputStream the OutputStream to write to | |||
* @throws IOException thrown if an I/O exception of some sort has occurred. | |||
*/ | |||
protected static void copyChunks(byte[] dataHeader, int lengthOffset, | |||
int maxChunkLength, InputStream inputStream, OutputStream outputStream) | |||
throws IOException { | |||
int headerLen = dataHeader.length - lengthOffset; | |||
// length field is just before data so do not include in data length | |||
if (headerLen == 2) { | |||
headerLen = 0; | |||
} | |||
byte[] data = new byte[maxChunkLength]; | |||
int numBytesRead = 0; | |||
while ((numBytesRead = inputStream.read(data, 0, maxChunkLength)) > 0) { | |||
byte[] len = BinaryUtils.convert(headerLen + numBytesRead, 2); | |||
dataHeader[lengthOffset] = len[0]; // Length byte 1 | |||
dataHeader[lengthOffset + 1] = len[1]; // Length byte 2 | |||
outputStream.write(dataHeader); | |||
outputStream.write(data, 0, numBytesRead); | |||
} | |||
} | |||
/** | |||
* Writes data chunks to a given outputstream | |||
* | |||
@@ -186,7 +155,7 @@ public abstract class AbstractAFPObject implements Streamable { | |||
* @param maxLength the maximum length allowed for the string | |||
* @return a possibly truncated string | |||
*/ | |||
protected String truncate(String str, int maxLength) { | |||
protected static String truncate(String str, int maxLength) { | |||
if (str.length() > maxLength) { | |||
str = str.substring(0, maxLength); | |||
LOG.warn("truncated character string '" |
@@ -90,7 +90,7 @@ public abstract class AbstractNamedAFPObject extends AbstractTripletStructuredOb | |||
return nameBytes; | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void copySF(byte[] data, byte type, byte category) { | |||
super.copySF(data, type, category); | |||
byte[] nameData = getNameBytes(); |
@@ -22,7 +22,6 @@ package org.apache.fop.afp.modca; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.Collection; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.fop.afp.modca.Registry.ObjectType; | |||
@@ -35,10 +34,10 @@ import org.apache.fop.afp.modca.triplets.Triplet; | |||
/** | |||
* A MODCA structured object base class providing support for Triplets | |||
*/ | |||
public class AbstractTripletStructuredObject extends AbstractStructuredObject { | |||
public abstract class AbstractTripletStructuredObject extends AbstractStructuredObject { | |||
/** list of object triplets */ | |||
protected List/*<Triplet>*/ triplets = new java.util.ArrayList/*<Triplet>*/(); | |||
protected List<AbstractTriplet> triplets = new java.util.ArrayList<AbstractTriplet>(); | |||
/** | |||
* Returns the triplet data length | |||
@@ -47,12 +46,8 @@ public class AbstractTripletStructuredObject extends AbstractStructuredObject { | |||
*/ | |||
protected int getTripletDataLength() { | |||
int dataLength = 0; | |||
if (hasTriplets()) { | |||
Iterator it = triplets.iterator(); | |||
while (it.hasNext()) { | |||
AbstractTriplet triplet = (AbstractTriplet)it.next(); | |||
dataLength += triplet.getDataLength(); | |||
} | |||
for (Triplet triplet : triplets) { | |||
dataLength += triplet.getDataLength(); | |||
} | |||
return dataLength; | |||
} | |||
@@ -85,11 +80,9 @@ public class AbstractTripletStructuredObject extends AbstractStructuredObject { | |||
* @param tripletId the triplet identifier | |||
*/ | |||
private AbstractTriplet getTriplet(byte tripletId) { | |||
Iterator it = getTriplets().iterator(); | |||
while (it.hasNext()) { | |||
AbstractTriplet triplet = (AbstractTriplet)it.next(); | |||
if (triplet.getId() == tripletId) { | |||
return triplet; | |||
for (AbstractTriplet trip : triplets) { | |||
if (trip.getId() == tripletId) { | |||
return trip; | |||
} | |||
} | |||
return null; | |||
@@ -110,7 +103,7 @@ public class AbstractTripletStructuredObject extends AbstractStructuredObject { | |||
* | |||
* @param triplet the triplet to add | |||
*/ | |||
protected void addTriplet(Triplet triplet) { | |||
protected void addTriplet(AbstractTriplet triplet) { | |||
triplets.add(triplet); | |||
} | |||
@@ -119,14 +112,14 @@ public class AbstractTripletStructuredObject extends AbstractStructuredObject { | |||
* | |||
* @param tripletCollection a collection of triplets | |||
*/ | |||
public void addTriplets(Collection/*<Triplet>*/ tripletCollection) { | |||
public void addTriplets(Collection<AbstractTriplet> tripletCollection) { | |||
if (tripletCollection != null) { | |||
triplets.addAll(tripletCollection); | |||
} | |||
} | |||
/** @return the triplet list pertaining to this resource */ | |||
protected List/*<Triplet>*/ getTriplets() { | |||
protected List<AbstractTriplet> getTriplets() { | |||
return triplets; | |||
} | |||
@@ -57,7 +57,6 @@ public class IncludeObject extends AbstractNamedAFPObject { | |||
/** the object referenced is of type image */ | |||
public static final byte TYPE_IMAGE = (byte)0xFB; | |||
/** the object type referenced (default is other) */ | |||
private byte objectType = TYPE_OTHER; | |||
@@ -68,7 +67,7 @@ public class IncludeObject extends AbstractNamedAFPObject { | |||
private int yoaOset = 0; | |||
/** the orientation of the referenced object */ | |||
private int oaOrent = 0; | |||
private ObjectAreaRotation oaOrent = ObjectAreaRotation.RIGHT_HANDED_0; | |||
/** the X-axis origin defined in the object */ | |||
private int xocaOset = -1; | |||
@@ -94,13 +93,7 @@ public class IncludeObject extends AbstractNamedAFPObject { | |||
* The orientation (0,90, 180, 270) | |||
*/ | |||
public void setObjectAreaOrientation(int orientation) { | |||
if (orientation == 0 || orientation == 90 || orientation == 180 | |||
|| orientation == 270) { | |||
this.oaOrent = orientation; | |||
} else { | |||
throw new IllegalArgumentException( | |||
"The orientation must be one of the values 0, 90, 180, 270"); | |||
} | |||
this.oaOrent = ObjectAreaRotation.objectAreaRotationFor(orientation); | |||
} | |||
/** | |||
@@ -151,87 +144,16 @@ public class IncludeObject extends AbstractNamedAFPObject { | |||
data[17] = 0x00; // reserved | |||
data[18] = objectType; | |||
//XoaOset (object area) | |||
if (xoaOset > -1) { | |||
byte[] x = BinaryUtils.convert(xoaOset, 3); | |||
data[19] = x[0]; | |||
data[20] = x[1]; | |||
data[21] = x[2]; | |||
} else { | |||
data[19] = (byte)0xFF; | |||
data[20] = (byte)0xFF; | |||
data[21] = (byte)0xFF; | |||
} | |||
writeOsetTo(data, 19, xoaOset); | |||
// YoaOset (object area) | |||
if (yoaOset > -1) { | |||
byte[] y = BinaryUtils.convert(yoaOset, 3); | |||
data[22] = y[0]; | |||
data[23] = y[1]; | |||
data[24] = y[2]; | |||
} else { | |||
data[22] = (byte)0xFF; | |||
data[23] = (byte)0xFF; | |||
data[24] = (byte)0xFF; | |||
} | |||
writeOsetTo(data, 22, yoaOset); | |||
// XoaOrent/YoaOrent | |||
switch (oaOrent) { | |||
case -1: // use x/y axis orientation defined in object | |||
data[25] = (byte)0xFF; // x axis rotation | |||
data[26] = (byte)0xFF; // | |||
data[27] = (byte)0xFF; // y axis rotation | |||
data[28] = (byte)0xFF; | |||
break; | |||
case 90: | |||
data[25] = 0x2D; | |||
data[26] = 0x00; | |||
data[27] = 0x5A; | |||
data[28] = 0x00; | |||
break; | |||
case 180: | |||
data[25] = 0x5A; | |||
data[25] = 0x00; | |||
data[27] = (byte)0x87; | |||
data[28] = 0x00; | |||
break; | |||
case 270: | |||
data[25] = (byte)0x87; | |||
data[26] = 0x00; | |||
data[27] = 0x00; | |||
data[28] = 0x00; | |||
break; | |||
default: // 0 degrees | |||
data[25] = 0x00; | |||
data[26] = 0x00; | |||
data[27] = 0x2D; | |||
data[28] = 0x00; | |||
break; | |||
} | |||
oaOrent.writeTo(data, 25); | |||
// XocaOset (object content) | |||
if (xocaOset > -1) { | |||
byte[] x = BinaryUtils.convert(xocaOset, 3); | |||
data[29] = x[0]; | |||
data[30] = x[1]; | |||
data[31] = x[2]; | |||
} else { | |||
data[29] = (byte)0xFF; | |||
data[30] = (byte)0xFF; | |||
data[31] = (byte)0xFF; | |||
} | |||
writeOsetTo(data, 29, xocaOset); | |||
writeOsetTo(data, 32, yocaOset); | |||
// YocaOset (object content) | |||
if (yocaOset > -1) { | |||
byte[] y = BinaryUtils.convert(yocaOset, 3); | |||
data[32] = y[0]; | |||
data[33] = y[1]; | |||
data[34] = y[2]; | |||
} else { | |||
data[32] = (byte)0xFF; | |||
data[33] = (byte)0xFF; | |||
data[34] = (byte)0xFF; | |||
} | |||
// RefCSys (Reference coordinate system) | |||
data[35] = 0x01; // Page or overlay coordinate system | |||
@@ -242,6 +164,19 @@ public class IncludeObject extends AbstractNamedAFPObject { | |||
writeTriplets(os); | |||
} | |||
private static void writeOsetTo(byte[] out, int offset, int oset) { | |||
if (oset > -1) { | |||
byte[] y = BinaryUtils.convert(oset, 3); | |||
out[offset] = y[0]; | |||
out[offset + 1] = y[1]; | |||
out[offset + 2] = y[2]; | |||
} else { | |||
out[offset] = (byte)0xFF; | |||
out[offset + 1] = (byte)0xFF; | |||
out[offset + 2] = (byte)0xFF; | |||
} | |||
} | |||
private String getObjectTypeName() { | |||
String objectTypeName = null; | |||
if (objectType == TYPE_PAGE_SEGMENT) { | |||
@@ -299,4 +234,69 @@ public class IncludeObject extends AbstractNamedAFPObject { | |||
addTriplet(new MeasurementUnitsTriplet(xRes, xRes)); | |||
} | |||
} | |||
/** | |||
* Represents the 4 bytes that specify the area rotation reference coordinate system | |||
* | |||
*/ | |||
private enum ObjectAreaRotation { | |||
RIGHT_HANDED_0(Rotation.ROTATION_0, Rotation.ROTATION_90), | |||
RIGHT_HANDED_90(Rotation.ROTATION_90, Rotation.ROTATION_180), | |||
RIGHT_HANDED_180(Rotation.ROTATION_180, Rotation.ROTATION_270), | |||
RIGHT_HANDED_270(Rotation.ROTATION_270, Rotation.ROTATION_0); | |||
/** | |||
* The object area’s X-axis rotation from the X axis of the reference coordinate system | |||
*/ | |||
private final Rotation xoaOrent; | |||
/** | |||
* The object area’s Y-axis rotation from the Y axis of the reference coordinate system | |||
*/ | |||
private final Rotation yoaOrent; | |||
public void writeTo(byte[] out, int offset) { | |||
xoaOrent.writeTo(out, offset); | |||
yoaOrent.writeTo(out, offset + 2); | |||
} | |||
ObjectAreaRotation(Rotation xoaOrent, Rotation yoaOrent) { | |||
this.xoaOrent = xoaOrent; | |||
this.yoaOrent = yoaOrent; | |||
} | |||
private static ObjectAreaRotation objectAreaRotationFor(int orientation) { | |||
switch (orientation) { | |||
case 0: return RIGHT_HANDED_0; | |||
case 90: return RIGHT_HANDED_90; | |||
case 180: return RIGHT_HANDED_180; | |||
case 270: return RIGHT_HANDED_270; | |||
default: throw new IllegalArgumentException( | |||
"The orientation must be one of the values 0, 90, 180, 270"); | |||
} | |||
} | |||
} | |||
/** | |||
* Represents a rotation value | |||
* | |||
*/ | |||
private enum Rotation { | |||
ROTATION_0(0), | |||
ROTATION_90(0x2D), | |||
ROTATION_180(0x5A), | |||
ROTATION_270(0x87); | |||
private final byte firstByte; | |||
public void writeTo(byte[] out, int offset) { | |||
out[offset] = firstByte; | |||
out[offset + 1] = (byte)0; | |||
} | |||
Rotation(int firstByte) { | |||
this.firstByte = (byte) firstByte; | |||
} | |||
} | |||
} |
@@ -104,7 +104,7 @@ public class TagLogicalElement extends AbstractTripletStructuredObject { | |||
setAttributeValue(value); | |||
setAttributeQualifier(tleID, 1); | |||
byte[] data = new byte[SF_HEADER.length]; | |||
byte[] data = new byte[SF_HEADER_LENGTH]; | |||
copySF(data, Type.ATTRIBUTE, Category.PROCESS_ELEMENT); | |||
int tripletDataLength = getTripletDataLength(); |
@@ -28,7 +28,6 @@ import org.apache.fop.fonts.DejaVuLGCSerifTest; | |||
import org.apache.fop.image.loader.batik.ImageLoaderTestCase; | |||
import org.apache.fop.image.loader.batik.ImagePreloaderTestCase; | |||
import org.apache.fop.intermediate.IFMimickingTestCase; | |||
import org.apache.fop.render.afp.AFPTestSuite; | |||
import org.apache.fop.render.extensions.prepress.PageBoundariesTest; | |||
import org.apache.fop.render.extensions.prepress.PageScaleTest; | |||
import org.apache.fop.render.pdf.PDFAConformanceTestCase; | |||
@@ -53,13 +52,14 @@ public class StandardTestSuite { | |||
//$JUnit-BEGIN$ | |||
suite.addTest(BasicDriverTestSuite.suite()); | |||
suite.addTest(UtilityCodeTestSuite.suite()); | |||
suite.addTest(org.apache.fop.afp.AFPTestSuite.suite()); | |||
suite.addTest(new TestSuite(PDFAConformanceTestCase.class)); | |||
suite.addTest(new TestSuite(PDFEncodingTestCase.class)); | |||
suite.addTest(new TestSuite(PDFCMapTestCase.class)); | |||
suite.addTest(new TestSuite(PDFsRGBSettingsTestCase.class)); | |||
suite.addTest(new TestSuite(DejaVuLGCSerifTest.class)); | |||
suite.addTest(new TestSuite(MODCAParserTestCase.class)); | |||
suite.addTest(AFPTestSuite.suite()); | |||
suite.addTest(org.apache.fop.render.afp.AFPTestSuite.suite()); | |||
suite.addTest(PSTestSuite.suite()); | |||
suite.addTest(RichTextFormatTestSuite.suite()); | |||
suite.addTest(new TestSuite(ImageLoaderTestCase.class)); |
@@ -0,0 +1,44 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.afp; | |||
import junit.framework.Test; | |||
import junit.framework.TestSuite; | |||
import org.apache.fop.afp.modca.AbstractStructuredObjectTestCase; | |||
import org.apache.fop.afp.modca.AbstractTripletStructuredObjectTestCase; | |||
import org.apache.fop.afp.modca.IncludeObjectTestCase; | |||
/** | |||
* Test suite for FOP's AFP classes. | |||
*/ | |||
public class AFPTestSuite { | |||
/** | |||
* Builds the test suite | |||
* @return the test suite | |||
*/ | |||
public static Test suite() { | |||
TestSuite suite = new TestSuite("Test suite for FOP's AFP classes"); | |||
//$JUnit-BEGIN$ | |||
suite.addTest(new TestSuite(IncludeObjectTestCase.class)); | |||
//$JUnit-END$ | |||
return suite; | |||
} | |||
} |
@@ -0,0 +1,245 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.afp.modca; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import junit.framework.TestCase; | |||
import org.apache.fop.afp.Streamable; | |||
/** | |||
* Tests the {@link AbstractAFPObject} class. | |||
*/ | |||
public abstract class AbstractAFPObjectTestCase<S extends AbstractAFPObject> | |||
extends TestCase { | |||
private S sut; | |||
protected final S getSut() { | |||
return sut; | |||
} | |||
protected final void setSut(S sut) { | |||
if ( this.sut == null) { | |||
this.sut = sut; | |||
} | |||
} | |||
private byte[] header = new byte[] { | |||
0x5A, // Structured field identifier | |||
0x00, // Length byte 1 | |||
0x10, // Length byte 2 | |||
0x00, // Structured field id byte 1 | |||
0x00, // Structured field id byte 2 | |||
0x00, // Structured field id byte 3 | |||
0x00, // Flags | |||
0x00, // Reserved | |||
0x00 // Reserved | |||
}; | |||
public void testCopySFStatic() { | |||
byte[] actual = new byte[9]; | |||
Arrays.fill(actual, (byte)-1); | |||
S.copySF(actual, (byte)0, (byte)0, (byte)0); | |||
assertTrue(Arrays.equals(actual, header)); | |||
byte[] expected2 = new byte[9]; | |||
System.arraycopy(header, 0, expected2, 0, header.length); | |||
final byte clazz = (byte) 0x01; | |||
final byte type = (byte) 0x02; | |||
final byte catagory = (byte) 0x03; | |||
expected2[3] = clazz; | |||
expected2[4] = type; | |||
expected2[5] = catagory; | |||
AbstractAFPObject.copySF(actual, clazz, type, catagory); | |||
assertTrue(Arrays.equals(actual, expected2)); | |||
} | |||
public void testCopySF() { | |||
byte[] expected = new byte[9]; | |||
S.copySF(expected, (byte) 0xD3, (byte)0, (byte)0); | |||
byte[] actual = new byte[9]; | |||
Arrays.fill(actual, (byte)-1); | |||
getSut().copySF(actual, (byte)0, (byte)0); | |||
assertTrue(Arrays.equals(actual, expected)); | |||
byte[] expected2 = new byte[9]; | |||
System.arraycopy(expected, 0, expected2, 0, expected.length); | |||
final byte type = (byte)1; | |||
final byte catagory = (byte)2; | |||
expected2[4] = type; | |||
expected2[5] = catagory; | |||
getSut().copySF(actual, type, catagory); | |||
assertTrue(Arrays.equals(actual, expected2)); | |||
} | |||
/** | |||
* | |||
*/ | |||
public void testwriteObjects() { | |||
final byte[][] expected = {{(byte)0, (byte)1}, {(byte)2, (byte)3}, {(byte)4, (byte)5}}; | |||
List<Streamable> objects = new ArrayList<Streamable>() { | |||
{ | |||
add(StreamableObject.instance(expected[0])); | |||
add(StreamableObject.instance(expected[1])); | |||
add(StreamableObject.instance(expected[2])); | |||
} }; | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
try { | |||
getSut().writeObjects(objects, baos); | |||
} catch (IOException e) { | |||
fail(); | |||
} | |||
byte[] actual = baos.toByteArray(); | |||
int index = 0; | |||
for (int i = 0; i < expected.length; i++) { | |||
for (int j = 0; j < expected[i].length; j++) { | |||
assertTrue("" + index, actual[index] == expected[i][j]); | |||
index++; | |||
} | |||
} | |||
} | |||
/** | |||
* | |||
*/ | |||
public void testTruncate() { | |||
String expected = "abc"; | |||
assertTrue(AbstractAFPObject.truncate(expected, 4) == expected); | |||
assertTrue(AbstractAFPObject.truncate(expected, 3) == expected); | |||
assertEquals(AbstractAFPObject.truncate(expected + "d", 3), expected); | |||
assertEquals(AbstractAFPObject.truncate(expected, 0), ""); | |||
try { | |||
assertTrue(AbstractAFPObject.truncate(null, 4) == null); | |||
fail(); | |||
} catch (NullPointerException e) { | |||
// PASS | |||
} | |||
} | |||
/** | |||
* | |||
*/ | |||
public void testWriteChunksToStream() throws IOException { | |||
final byte[] data = new byte[256]; | |||
int counter = 0; | |||
for (int i = 0; i < data.length; i++) { | |||
data[i] = (byte) counter++; | |||
} | |||
byte[] header = new byte[9]; | |||
// Test when chunk size % data.length == 0 | |||
testWithGivenChunkSize(data, header, 16); | |||
// test when chunk size % data.length != 0 | |||
testWithGivenChunkSize(data, header, 10); | |||
// test with an odd number... | |||
testWithGivenChunkSize(data, header, 13); | |||
} | |||
private void testWithGivenChunkSize(byte[] data, byte[] header, int chunkSize) | |||
throws IOException { | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
S.writeChunksToStream(data, header, 0, chunkSize, baos); | |||
byte[] testData = baos.toByteArray(); | |||
int numberOfFullDataChunks = data.length / chunkSize; | |||
int lastChunkSize = data.length % chunkSize; | |||
int lengthOfTestData = numberOfFullDataChunks * (chunkSize + header.length); | |||
lengthOfTestData += lastChunkSize == 0 ? 0 : header.length + lastChunkSize; | |||
putLengthInHeader(header, chunkSize); | |||
assertEquals(lengthOfTestData, testData.length); | |||
int testIndex = 0; | |||
int expectedIndex = 0; | |||
for (int i = 0; i < numberOfFullDataChunks; i++) { | |||
checkHeaderAndData(header, data, testData, expectedIndex, testIndex, chunkSize); | |||
expectedIndex += chunkSize + header.length; | |||
testIndex += chunkSize; | |||
} | |||
putLengthInHeader(header, lastChunkSize); | |||
// check last chunk | |||
if (lastChunkSize != 0) { | |||
checkHeaderAndData(header, data, testData, expectedIndex, testIndex, lastChunkSize); | |||
} | |||
} | |||
private void putLengthInHeader(byte[] header, int chunkSize) { | |||
header[0] = 0; | |||
header[1] = (byte) (chunkSize + header.length); | |||
} | |||
private void checkHeaderAndData(byte[] header, byte[] data, byte[] testData, int expectedIndex, | |||
int testIndex, int chunkSize) { | |||
for (int i = 0; i < header.length; i++) { | |||
assertEquals(testData[expectedIndex++], header[i]); | |||
} | |||
for (int i = 0; i < chunkSize; i++) { | |||
assertEquals(testData[expectedIndex++], data[i + testIndex]); | |||
} | |||
} | |||
/** | |||
* | |||
*/ | |||
private static class StreamableObject implements Streamable { | |||
private byte[] bytes; | |||
StreamableObject(byte[] bytes) { | |||
this.bytes = new byte[bytes.length]; | |||
System.arraycopy(bytes, 0, this.bytes, 0, bytes.length); | |||
} | |||
private static Streamable instance(byte[] bytes) { | |||
return new StreamableObject(bytes); | |||
} | |||
public void writeToStream(OutputStream os) throws IOException { | |||
os.write(bytes); | |||
} | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.afp.modca; | |||
import java.util.Arrays; | |||
/** | |||
* Tests the {@linkplain AbstractAFPObject} class. | |||
*/ | |||
public abstract class AbstractNamedAFPObjectTestCase<S extends AbstractNamedAFPObject> | |||
extends AbstractAFPObjectTestCase<S> { | |||
public void testCopySF() { | |||
final S sut = getSut(); | |||
byte[] expected = new byte[17]; | |||
S.copySF(expected, (byte) 0xD3, (byte)0, (byte)0); | |||
byte[] nameData = sut.getNameBytes(); | |||
System.arraycopy(nameData, 0, expected, 9, nameData.length); | |||
byte[] actual = new byte[17]; | |||
Arrays.fill(actual, (byte)-1); | |||
getSut().copySF(actual, (byte)0, (byte)0); | |||
assertTrue(Arrays.equals(actual, expected)); | |||
byte[] expected2 = new byte[17]; | |||
System.arraycopy(expected, 0, expected2, 0, expected.length); | |||
System.arraycopy(nameData, 0, expected, 9, nameData.length); | |||
final byte type = (byte)1; | |||
final byte catagory = (byte)2; | |||
expected2[4] = type; | |||
expected2[5] = catagory; | |||
getSut().copySF(actual, type, catagory); | |||
assertTrue(Arrays.equals(actual, expected2)); | |||
} | |||
} |
@@ -0,0 +1,63 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.afp.modca; | |||
import java.io.IOException; | |||
public abstract class AbstractStructuredObjectTestCase<S extends AbstractStructuredObject> extends AbstractAFPObjectTestCase<S> { | |||
/** | |||
* Test writeStart() - test that the contract is maintained with | |||
* {@link AbstractStructuredObject}. | |||
* | |||
* @throws IOException | |||
*/ | |||
public void testwriteStart() throws IOException { | |||
} | |||
/** | |||
* Test writeEnd() - test that the contract is maintained with {@link AbstractStructuredObject}. | |||
* | |||
* @throws IOException | |||
*/ | |||
public void testWriteEnd() throws IOException { | |||
} | |||
/** | |||
* Test writeContent() - test that the contract is maintained with | |||
* {@link AbstractStructuredObject}. | |||
* | |||
* @throws IOException | |||
*/ | |||
public void testWriteContent() throws IOException { | |||
} | |||
/** | |||
* Test writeToStream() - test that the contract is maintained with | |||
* {@link AbstractStructuredObject}. | |||
* | |||
* @throws IOException | |||
*/ | |||
public void testWriteToStream() throws IOException { | |||
testwriteStart(); | |||
testWriteEnd(); | |||
testWriteContent(); | |||
} | |||
} |
@@ -0,0 +1,154 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.afp.modca; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.apache.fop.afp.modca.triplets.AbstractTriplet; | |||
import org.apache.fop.afp.modca.triplets.AttributeQualifierTriplet; | |||
import org.apache.fop.afp.modca.triplets.CommentTriplet; | |||
import org.apache.fop.afp.modca.triplets.ObjectAreaSizeTriplet; | |||
import org.apache.fop.afp.modca.triplets.Triplet; | |||
/** | |||
* Test {@link AbstractTripletStructuredObject} | |||
*/ | |||
public abstract class AbstractTripletStructuredObjectTestCase<S extends AbstractTripletStructuredObject> | |||
extends AbstractStructuredObjectTestCase<AbstractTripletStructuredObject> { | |||
private static final List<AbstractTriplet> TRIPLETS; | |||
static { | |||
List<AbstractTriplet> triplets = new ArrayList<AbstractTriplet>(); | |||
triplets.add(new CommentTriplet((byte) 0x01, "test comment")); | |||
triplets.add(new AttributeQualifierTriplet(1, 1)); | |||
triplets.add(new ObjectAreaSizeTriplet(10, 20)); | |||
TRIPLETS = Collections.unmodifiableList(triplets); | |||
} | |||
private AbstractTripletStructuredObject emptyStructuredObject | |||
= new AbstractTripletStructuredObject() { }; | |||
@Override | |||
public void setUp() throws Exception { | |||
super.setUp(); | |||
AbstractTripletStructuredObject sut = getSut(); | |||
for (AbstractTriplet triplet : TRIPLETS) { | |||
sut.addTriplet(triplet); | |||
} | |||
} | |||
/** | |||
* Test getTripletLength() - ensure a sum of all enclosing object lengths is returned. | |||
*/ | |||
public void testGetTripletLength() { | |||
int dataLength = 0; | |||
for (Triplet t : TRIPLETS) { | |||
dataLength += t.getDataLength(); | |||
} | |||
assertEquals(dataLength, getSut().getTripletDataLength()); | |||
assertEquals(0, emptyStructuredObject.getTripletDataLength()); | |||
} | |||
/** | |||
* Test hasTriplets() | |||
*/ | |||
public void testHasTriplets() { | |||
assertTrue(getSut().hasTriplets()); | |||
assertFalse(emptyStructuredObject.hasTriplets()); | |||
} | |||
/** | |||
* Test writeTriplets() - Ensure the triplets are written properly. | |||
* | |||
* @throws IOException - | |||
*/ | |||
public void testWriteObjects() throws IOException { | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
for (AbstractTriplet triplet : TRIPLETS) { | |||
triplet.writeToStream(baos); | |||
} | |||
byte[] expected = baos.toByteArray(); | |||
baos.reset(); | |||
getSut().writeTriplets(baos); | |||
assertTrue(Arrays.equals(expected, baos.toByteArray())); | |||
baos.reset(); | |||
// Ensure it doesn't die if no data has been added | |||
emptyStructuredObject.writeTriplets(baos); | |||
byte[] emptyArray = baos.toByteArray(); | |||
assertTrue(Arrays.equals(emptyArray, new byte[0])); | |||
} | |||
/** | |||
* Test hasTriplet() - ensure both positive and negative values are returned. | |||
*/ | |||
public void testHasTriplet() { | |||
for (AbstractTriplet triplet : TRIPLETS) { | |||
assertTrue(getSut().hasTriplet(triplet.getId())); | |||
assertFalse(emptyStructuredObject.hasTriplet(triplet.getId())); | |||
} | |||
CommentTriplet notInSystem = new CommentTriplet((byte) 0x30, "This should return false"); | |||
assertFalse(getSut().hasTriplet(notInSystem.getId())); | |||
} | |||
/** | |||
* Test addTriplet() - mostly tested above, but check boundary cases | |||
*/ | |||
public void testAddTriplet() { | |||
// ensure null doesn't kill it... not sure what else to test | |||
getSut().addTriplet(null); | |||
} | |||
/** | |||
* Test addTriplets() - ensure all triplets are added. | |||
*/ | |||
public void testAddTriplets() { | |||
// Tested on empty object | |||
List<AbstractTriplet> expectedList = TRIPLETS; | |||
emptyStructuredObject.addTriplets(expectedList); | |||
// checks equals() on each member of both lists | |||
assertEquals(expectedList, emptyStructuredObject.getTriplets()); | |||
// Add a list to an already populated list | |||
getSut().addTriplets(expectedList); | |||
List<AbstractTriplet> newExpected = new ArrayList<AbstractTriplet>(expectedList); | |||
newExpected.addAll(expectedList); | |||
assertEquals(newExpected, getSut().getTriplets()); | |||
// Ensure null doesn't throw exception | |||
emptyStructuredObject.addTriplets(null); | |||
} | |||
} |
@@ -0,0 +1,129 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id:$ */ | |||
package org.apache.fop.afp.modca; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.util.Arrays; | |||
import org.apache.fop.afp.util.BinaryUtils; | |||
/** | |||
* Test {@link IncludeObject} | |||
*/ | |||
public class IncludeObjectTestCase extends AbstractNamedAFPObjectTestCase<IncludeObject> { | |||
@Override | |||
public void setUp() throws Exception { | |||
setSut(new IncludeObject("8__chars")); | |||
super.setUp(); | |||
} | |||
/** | |||
* Test writeToStream() | |||
* @throws IOException - | |||
*/ | |||
public void testWriteToStream() throws IOException { | |||
final IncludeObject sut = getSut(); | |||
byte[] expected = defaultIncludeObjectBytes(sut.getTripletDataLength(), sut.getNameBytes()); | |||
testWriteToStreamHelper(sut, expected); | |||
} | |||
/** | |||
* Test writeToStream() - the orientation of the referenced object is a right- | |||
* handed with a 180 x-axis | |||
* @throws IOException - | |||
*/ | |||
public void testWriteToStreamForOrientation() throws IOException { | |||
final IncludeObject sut = getSut(); | |||
byte[] expected = defaultIncludeObjectBytes(sut.getTripletDataLength(), sut.getNameBytes()); | |||
expected[25] = (byte)0x5A; | |||
expected[26] = (byte)0x00; | |||
expected[27] = (byte)0x87; | |||
expected[28] = (byte)0x00; | |||
sut.setObjectAreaOrientation(180); | |||
testWriteToStreamHelper(sut, expected); | |||
} | |||
private void testWriteToStreamHelper(IncludeObject sut, byte[] expected) throws IOException { | |||
final ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
sut.writeToStream(baos); | |||
byte[] actual = baos.toByteArray(); | |||
assertTrue(Arrays.equals(actual, expected)); | |||
} | |||
private byte[] defaultIncludeObjectBytes(int tripletDataLength, byte[] nameData) { | |||
byte[] expected = new byte[36]; | |||
byte[] header = new byte[] { | |||
0x5A, // Structured field identifier | |||
0x00, // Length byte 1 | |||
0x10, // Length byte 2 | |||
(byte)0xD3, // Structured field id byte 1 | |||
(byte)0xAF, // Structured field id byte 2 - type 'input' | |||
(byte)0xC3, // Structured field id byte 3 - category 'data resource' | |||
0x00, // Flags | |||
0x00, // Reserved | |||
0x00, // Reserved | |||
}; | |||
System.arraycopy(header, 0, expected, 0, header.length); | |||
byte[] lengthBytes = BinaryUtils.convert(35 + tripletDataLength, 2); //Ignore first byte | |||
expected[1] = lengthBytes[0]; | |||
expected[2] = lengthBytes[1]; | |||
System.arraycopy(nameData, 0, expected, 9, nameData.length); | |||
expected[18] = (byte)0x92; // object type 'other' | |||
expected[27] = (byte)0x2D; // orientation of the reference object | |||
writeOsetTo(expected, 29, -1); // the X-axis origin defined in the object | |||
writeOsetTo(expected, 32, -1); // the Y-axis origin defined in the object | |||
expected[35] = 0x01; // Page or overlay coordinate system | |||
return expected; | |||
} | |||
private static void writeOsetTo(byte[] out, int offset, int oset) { | |||
if (oset > -1) { | |||
byte[] y = BinaryUtils.convert(oset, 3); | |||
out[offset] = y[0]; | |||
out[offset + 1] = y[1]; | |||
out[offset + 2] = y[2]; | |||
} else { | |||
out[offset] = (byte)0xFF; | |||
out[offset + 1] = (byte)0xFF; | |||
out[offset + 2] = (byte)0xFF; | |||
} | |||
} | |||
} |