瀏覽代碼

Bugzilla#53502: MODCA end structured field now more conformant with the spec by allowing 0xFFFF match (match any). Submitted by Robert Meyer


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1357110 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_0
Mehdi Houshmand 12 年之前
父節點
當前提交
8f37765b5c

+ 63
- 34
src/java/org/apache/fop/afp/util/AFPResourceUtil.java 查看文件

@@ -56,8 +56,11 @@ import org.apache.fop.afp.parser.UnparsedStructuredField;
*/
public final class AFPResourceUtil {

private static final byte TYPE_CODE_BEGIN = (byte)(0xA8 & 0xFF);
private static final byte TYPE_CODE_END = (byte)(0xA9 & 0xFF);
private static final byte TYPE_CODE_BEGIN = (byte) (0xA8 & 0xFF);

private static final byte TYPE_CODE_END = (byte) (0xA9 & 0xFF);

private static final byte END_FIELD_ANY_NAME = (byte) (0xFF & 0xFF);

private static final Log LOG = LogFactory.getLog(AFPResourceUtil.class);

@@ -92,10 +95,13 @@ public final class AFPResourceUtil {
throws UnsupportedEncodingException {
//The first 8 bytes of the field data represent the resource name
byte[] nameBytes = new byte[8];
System.arraycopy(field.getData(), 0, nameBytes, 0, 8);
String asciiName;
asciiName = new String(nameBytes, AFPConstants.EBCIDIC_ENCODING);
return asciiName;

byte[] fieldData = field.getData();
if (fieldData.length < 8) {
throw new IllegalArgumentException("Field data does not contain a resource name");
}
System.arraycopy(fieldData, 0, nameBytes, 0, 8);
return new String(nameBytes, AFPConstants.EBCIDIC_ENCODING);
}

/**
@@ -128,12 +134,13 @@ public final class AFPResourceUtil {
public static void copyNamedResource(String name,
final InputStream in, final OutputStream out) throws IOException {
final MODCAParser parser = new MODCAParser(in);
Collection resourceNames = new java.util.HashSet();
Collection<String> resourceNames = new java.util.HashSet<String>();

//Find matching "Begin" field
final UnparsedStructuredField fieldBegin;
while (true) {
UnparsedStructuredField field = parser.readNextStructuredField();
final UnparsedStructuredField field = parser.readNextStructuredField();

if (field == null) {
throw new IOException("Requested resource '" + name
+ "' not found. Encountered resource names: " + resourceNames);
@@ -142,8 +149,10 @@ public final class AFPResourceUtil {
if (field.getSfTypeCode() != TYPE_CODE_BEGIN) { //0xA8=Begin
continue; //Not a "Begin" field
}
String resourceName = getResourceName(field);
final String resourceName = getResourceName(field);

resourceNames.add(resourceName);

if (resourceName.equals(name)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Start of requested structured field found:\n"
@@ -170,45 +179,65 @@ public final class AFPResourceUtil {
if (wrapInResource) {
ResourceObject resourceObject = new ResourceObject(name) {
protected void writeContent(OutputStream os) throws IOException {
copyStructuredFields(name, fieldBegin, parser, out);
copyNamedStructuredFields(name, fieldBegin, parser, out);
}
};
resourceObject.setType(ResourceObject.TYPE_PAGE_SEGMENT);
resourceObject.writeToStream(out);
} else {
copyStructuredFields(name, fieldBegin, parser, out);
copyNamedStructuredFields(name, fieldBegin, parser, out);
}
}

private static void copyStructuredFields(String name, UnparsedStructuredField fieldBegin,
private static void copyNamedStructuredFields(final String name, UnparsedStructuredField fieldBegin,
MODCAParser parser, OutputStream out) throws IOException {
boolean inRequestedResource;

//The "Begin" field first
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
fieldBegin.writeTo(out);
UnparsedStructuredField field;

//Then the rest of the fields until the corresponding "End" field
inRequestedResource = true;
do {
field = parser.readNextStructuredField();
UnparsedStructuredField field = fieldBegin;
while (true) {
if (field == null) {
break; //Unexpected EOF
}

if (field.getSfTypeCode() == TYPE_CODE_END) {
String resourceName = getResourceName(field);
if (resourceName.equals(name)) {
inRequestedResource = false; //Signal end of loop
}
throw new IOException("Ending structured field not found for resource " + name);
}
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
field.writeTo(out);
} while (inRequestedResource);
if (inRequestedResource) {
throw new IOException("Ending structured field not found for resource " + name);

if (isEndOfStructuredField(field, fieldBegin, name)) {
break;
}
field = parser.readNextStructuredField();
}
}

private static boolean isEndOfStructuredField(UnparsedStructuredField field,
UnparsedStructuredField fieldBegin, String name) throws UnsupportedEncodingException {
return fieldMatchesEndTagType(field)
&& fieldMatchesBeginCategoryCode(field, fieldBegin)
&& fieldHasValidName(field, name);
}

private static boolean fieldMatchesEndTagType(UnparsedStructuredField field) {
return field.getSfTypeCode() == TYPE_CODE_END;
}

private static boolean fieldMatchesBeginCategoryCode(UnparsedStructuredField field,
UnparsedStructuredField fieldBegin) {
return fieldBegin.getSfCategoryCode() == field.getSfCategoryCode();
}

/**
* The AFP specification states that it is valid for the end structured field to have:
* - No tag name specified, which will cause it to match any existing tag type match.
* - The name has FFFF as its first two bytes
* - The given name matches the previous structured field name
*/
private static boolean fieldHasValidName(UnparsedStructuredField field, String name)
throws UnsupportedEncodingException {
if (field.getData().length > 0) {
if (field.getData()[0] == field.getData()[1]
&& field.getData()[0] == END_FIELD_ANY_NAME) {
return true;
} else {
return name.equals(getResourceName(field));
}
}
return true;
}
}

+ 88
- 29
test/java/org/apache/fop/afp/AFPResourceUtilTestCase.java 查看文件

@@ -22,23 +22,34 @@ package org.apache.fop.afp;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

import org.junit.Test;

import org.apache.commons.io.IOUtils;
import org.apache.fop.afp.util.AFPResourceUtil;
import org.junit.Test;

import static org.junit.Assert.assertTrue;

/**
* Tests the {@link AFPResourceUtil} class.
*/
public class AFPResourceUtilTestCase {

private static final String RESOURCE_FILENAME = "expected_resource.afp";

private static final String NAMED_RESOURCE_FILENAME = "expected_named_resource.afp";

private static final String PSEG = "XFEATHER";
private static final String RESOURCE_ANY_NAME = "resource_any_name.afp";
private static final String RESOURCE_NAME_MATCH = "resource_name_match.afp";
private static final String RESOURCE_NAME_MISMATCH = "resource_name_mismatch.afp";
private static final String RESOURCE_NO_END_NAME = "resource_no_end_name.afp";

private static final String PSEG_A = "XFEATHER";
private static final String PSEG_B = "S1CODEQR";

/**
* Tests copyResourceFile()
@@ -46,57 +57,105 @@ public class AFPResourceUtilTestCase {
*/
@Test
public void testCopyResourceFile() throws Exception {
compareResources(new ResourceCopier() {
public void copy(InputStream in, OutputStream out) throws IOException {
AFPResourceUtil.copyResourceFile(in, out);
}
}, RESOURCE_FILENAME, RESOURCE_FILENAME);
}

final ByteArrayOutputStream baos = new ByteArrayOutputStream();
/**
* Tests copyNamedResource()
* @throws Exception -
*/
@Test
public void testCopyNamedResource() throws Exception {
compareResources(new ResourceCopier() {
public void copy(InputStream in, OutputStream out) throws IOException {
AFPResourceUtil.copyNamedResource(PSEG_A, in, out);
}
}, RESOURCE_FILENAME, NAMED_RESOURCE_FILENAME);
}

InputStream in = null;
private void compareResources(ResourceCopier copyResource, String resourceA, String resourceB)
throws IOException {
ByteArrayOutputStream baos = copyResource(resourceA, copyResource);
byte[] expectedBytes = resourceAsByteArray(resourceB);
assertTrue(Arrays.equals(expectedBytes, baos.toByteArray()));
}

private ByteArrayOutputStream copyResource(String resource, ResourceCopier resourceCopier)
throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream in = null;
try {
in = getClass().getResourceAsStream(RESOURCE_FILENAME);
AFPResourceUtil.copyResourceFile(in, baos);
in = getClass().getResourceAsStream(resource);
resourceCopier.copy(in, baos);
} finally {
in.close();
}
return baos;
}

private byte[] resourceAsByteArray(String resource) throws IOException {
InputStream in = null;
byte[] expectedBytes = null;

try {
in = getClass().getResourceAsStream(RESOURCE_FILENAME);
in = getClass().getResourceAsStream(resource);
expectedBytes = IOUtils.toByteArray(in);
} finally {
in.close();
}

assertTrue(Arrays.equals(expectedBytes, baos.toByteArray()));

return expectedBytes;
}

/**
* Tests copyNamedResource()
* Tests the validity of a closing structured field having an FF FF name which
* allows it to match any existing matching starting field
* @throws Exception -
*/
@Test
public void testCopyNamedResource() throws Exception {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
public void testResourceAnyName() throws Exception {
testResource(RESOURCE_ANY_NAME, PSEG_B);
}

InputStream in = null;
/**
* Tests a matching end structured field name
* @throws Exception -
*/
@Test
public void testResourceNameMatch() throws Exception {
testResource(RESOURCE_NAME_MATCH, PSEG_B);
}

try {
in = getClass().getResourceAsStream(RESOURCE_FILENAME);
AFPResourceUtil.copyNamedResource(PSEG, in, baos);
} finally {
in.close();
}
/**
* Tests to see whether a matching structured field pair with mismatching
* names fails.
* @throws Exception -
*/
@Test(expected=Exception.class)
public void testResourceNameMismatch() throws Exception {
testResource(RESOURCE_NAME_MISMATCH, PSEG_B);
}

byte[] expectedBytes = null;
/**
* Tests a matching structured end field with no name
* @throws Exception -
*/
@Test
public void testResourceNoEndName() throws Exception {
testResource(RESOURCE_NO_END_NAME, PSEG_B);
}

try {
in = getClass().getResourceAsStream(NAMED_RESOURCE_FILENAME);
expectedBytes = IOUtils.toByteArray(in);
} finally {
in.close();
}
private void testResource(String resource, final String pseg) throws Exception {
copyResource(resource, new ResourceCopier() {
public void copy(InputStream in, OutputStream out) throws IOException {
AFPResourceUtil.copyNamedResource(pseg, in, out);
}
});
}

assertTrue(Arrays.equals(expectedBytes, baos.toByteArray()));
private interface ResourceCopier {
public void copy(InputStream in, OutputStream out) throws IOException;
}
}

二進制
test/java/org/apache/fop/afp/resource_any_name.afp 查看文件


二進制
test/java/org/apache/fop/afp/resource_name_match.afp 查看文件


二進制
test/java/org/apache/fop/afp/resource_name_mismatch.afp 查看文件


二進制
test/java/org/apache/fop/afp/resource_no_end_name.afp 查看文件


Loading…
取消
儲存