From 3150399136cf2712e99974b04d41da2f613b97c9 Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Sun, 3 Aug 2008 22:15:46 +0000 Subject: [PATCH] should have been submitted with c682225 - Extensive fixes for data validation (bug 44953) git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@682227 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hssf/usermodel/StreamUtility.java | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/testcases/org/apache/poi/hssf/usermodel/StreamUtility.java diff --git a/src/testcases/org/apache/poi/hssf/usermodel/StreamUtility.java b/src/testcases/org/apache/poi/hssf/usermodel/StreamUtility.java new file mode 100644 index 000000000..45ae4ac36 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/StreamUtility.java @@ -0,0 +1,131 @@ +/* ==================================================================== + 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. +==================================================================== */ + +package org.apache.poi.hssf.usermodel; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * Utility class to help test code verify that generated files do not differ from proof copies in + * any significant detail. Normally this task would be simple except for the presence of artifacts + * in the file that change every time it is generated. Usually these volatile artifacts are + * time-stamps, user names, or other machine dependent parameters. + * + * @author Josh Micich + */ +public final class StreamUtility { + + /** + * Compares two streams with expected differences in specified regions. The streams are + * expected to be of equal length and comparison is always byte for byte. That is - + * differences can only involve exchanging each individual byte for another single byte.
+ * Both input streams are closed. + * + * @param allowableDifferenceRegions array of integer pairs: (offset, length). + * Any differences encountered in these regions of the streams will be ignored + * @return null if streams are identical, else the + * byte indexes of differing data. If streams were different lengths, + * the returned indexes will be -1 and the length of the shorter stream + */ + public static int[] diffStreams(InputStream isA, InputStream isB, int[] allowableDifferenceRegions) { + + if((allowableDifferenceRegions.length % 2) != 0) { + throw new RuntimeException("allowableDifferenceRegions length is odd"); + } + boolean success = false; + int[] result; + try { + result = diffInternal(isA, isB, allowableDifferenceRegions); + success = true; + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + close(isA, success); + close(isB, success); + } + return result; + } + + /** + * @param success false if the outer method is throwing an exception. + */ + private static void close(InputStream is, boolean success) { + try { + is.close(); + } catch (IOException e) { + if(success) { + // this is a new error. ok to throw + throw new RuntimeException(e); + } + // else don't subvert original exception. just print stack trace for this one + e.printStackTrace(); + } + } + + private static int[] diffInternal(InputStream isA, InputStream isB, int[] allowableDifferenceRegions) + throws IOException { + int offset = 0; + List temp = new ArrayList(); + while (true) { + int b = isA.read(); + int b2 = isB.read(); + if (b == -1) { + // EOF + if (b2 == -1) { + return toPrimitiveIntArray(temp); + } + return new int[] { -1, offset, }; + } + if (b2 == -1) { + return new int[] { -1, offset, }; + } + if (b != b2 && !isIgnoredRegion(allowableDifferenceRegions, offset)) { + temp.add(new Integer(offset)); + } + offset++; + } + } + + private static boolean isIgnoredRegion(int[] allowableDifferenceRegions, int offset) { + for (int i = 0; i < allowableDifferenceRegions.length; i+=2) { + int start = allowableDifferenceRegions[i]; + int end = start + allowableDifferenceRegions[i+1]; + if(start <= offset && offset < end) { + return true; + } + } + return false; + } + + private static int[] toPrimitiveIntArray(List temp) { + int nItems = temp.size(); + if(nItems < 1) { + return null; + } + Integer[] boxInts = new Integer[nItems]; + temp.toArray(boxInts); + + int[] result = new int[nItems]; + for (int i = 0; i < result.length; i++) { + result[i] = boxInts[i].intValue(); + } + return result; + } +}