Browse Source

Fixed a bug in AFP where the object area axes of an Include Object was incorrectly set when rotated by 180


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1151452 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_1rc1old
Peter Hancock 12 years ago
parent
commit
eee73c4ded

+ 12
- 43
src/java/org/apache/fop/afp/modca/AbstractAFPObject.java View File

@@ -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 '"

+ 1
- 1
src/java/org/apache/fop/afp/modca/AbstractNamedAFPObject.java View File

@@ -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();

+ 10
- 17
src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java View File

@@ -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;
}


+ 87
- 87
src/java/org/apache/fop/afp/modca/IncludeObject.java View File

@@ -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;
}
}

}

+ 1
- 1
src/java/org/apache/fop/afp/modca/TagLogicalElement.java View File

@@ -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();

+ 2
- 2
test/java/org/apache/fop/StandardTestSuite.java View File

@@ -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));

+ 44
- 0
test/java/org/apache/fop/afp/AFPTestSuite.java View File

@@ -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;
}
}

+ 245
- 0
test/java/org/apache/fop/afp/modca/AbstractAFPObjectTestCase.java View File

@@ -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);
}
}
}

+ 60
- 0
test/java/org/apache/fop/afp/modca/AbstractNamedAFPObjectTestCase.java View File

@@ -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));
}
}

+ 63
- 0
test/java/org/apache/fop/afp/modca/AbstractStructuredObjectTestCase.java View File

@@ -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();
}
}

+ 154
- 0
test/java/org/apache/fop/afp/modca/AbstractTripletStructuredObjectTestCase.java View File

@@ -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);
}

}

+ 129
- 0
test/java/org/apache/fop/afp/modca/IncludeObjectTestCase.java View File

@@ -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;
}
}
}

Loading…
Cancel
Save