// Path: subsonic-main/src/main/java/net/sourceforge/subsonic/util/HttpRange.java
// public class HttpRange {
// 
//     private static final Pattern PATTERN = Pattern.compile("bytes=(\\d+)-(\\d*)");
//     private final Long firstBytePos;
//     private final Long lastBytePos;
// 
//     /**
//      * Parses the given string as a HTTP header byte range.  See chapter 14.36.1 in RFC 2068
//      * for details.
//      * <p/>
//      * Only a subset of the allowed syntaxes are supported. Only ranges which specify first-byte-pos
//      * are supported. The last-byte-pos is optional.
//      *
//      * @param range The range from the HTTP header, for instance "bytes=0-499" or "bytes=500-"
//      * @return A range object (using inclusive values). If the last-byte-pos is not given, the end of
//      *         the returned range is {@code null}. The method returns <code>null</code> if the syntax
//      *         of the given range is not supported.
//      */
//     public static HttpRange valueOf(String range) {
//         if (range == null) {
//             return null;
//         }
// 
//         Matcher matcher = PATTERN.matcher(range);
//         if (matcher.matches()) {
//             String firstString = matcher.group(1);
//             String lastString = StringUtils.trimToNull(matcher.group(2));
// 
//             Long first = Long.parseLong(firstString);
//             Long last = lastString == null ? null : Long.parseLong(lastString);
// 
//             if (last != null && first > last) {
//                 return null;
//             }
//             return new HttpRange(first, last);
//         }
//         return null;
//     }
// 
//     public HttpRange(long firstBytePos, Long lastBytePos) {
//         this.firstBytePos = firstBytePos;
//         this.lastBytePos = lastBytePos;
//     }
// 
//     /**
//      * @return The first byte position (inclusive) in the range. Never {@code null}.
//      */
//     public Long getFirstBytePos() {
//         return firstBytePos;
//     }
// 
//     /**
//      * @return The last byte position (inclusive) in the range. Can be {@code null}.
//      */
//     public Long getLastBytePos() {
//         return lastBytePos;
//     }
// 
//     /**
//      * @return Whether this is a closed range (both first and last byte position specified).
//      */
//     public boolean isClosed() {
//         return firstBytePos != null && lastBytePos != null;
//     }
// 
//     /**
//      * @return The size in bytes if the range is closed, -1 otherwise.
//      */
//     public long size() {
//         return isClosed() ? (lastBytePos - firstBytePos + 1) : -1;
//     }
// 
//     /**
//      * @return Returns whether the given byte position is within this range.
//      */
//     public boolean contains(long pos) {
//         if (pos < firstBytePos) {
//             return false;
//         }
//         return lastBytePos == null || pos <= lastBytePos;
//     }
// 
//     @Override
//     public String toString() {
//         StringBuilder builder = new StringBuilder();
//         builder.append(firstBytePos).append('-');
//         if (lastBytePos != null) {
//             builder.append(lastBytePos);
//         }
//         return builder.toString();
//     }
// }


import junit.framework.TestCase;
import net.sourceforge.subsonic.util.HttpRange;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
        doTestWrap(0, 99, 100, 100);

        doTestWrap(10, 99, 100, 1);
        doTestWrap(10, 99, 100, 10);
        doTestWrap(10, 99, 100, 13);
        doTestWrap(10, 99, 100, 70);
        doTestWrap(10, 99, 100, 100);

        doTestWrap(66, 66, 100, 1);
        doTestWrap(66, 66, 100, 2);

        doTestWrap(10, 20, 100, 1);
        doTestWrap(10, 20, 100, 10);
        doTestWrap(10, 20, 100, 13);
        doTestWrap(10, 20, 100, 70);
        doTestWrap(10, 20, 100, 100);

        for (int start = 0; start < 10; start++) {
            for (int end = start; end < 10; end++) {
                for (int bufferSize = 1; bufferSize < 10; bufferSize++) {
                    doTestWrap(start, end, 10, bufferSize);
                    doTestWrap(start, null, 10, bufferSize);
                }
            }
        }
    }

    private void doTestWrap(int first, Integer last, int sourceSize, int bufferSize) throws Exception {
        byte[] source = createSource(sourceSize);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
// Path: subsonic-main/src/main/java/net/sourceforge/subsonic/util/HttpRange.java
// public class HttpRange {
// 
//     private static final Pattern PATTERN = Pattern.compile("bytes=(\\d+)-(\\d*)");
//     private final Long firstBytePos;
//     private final Long lastBytePos;
// 
//     /**
//      * Parses the given string as a HTTP header byte range.  See chapter 14.36.1 in RFC 2068
//      * for details.
//      * <p/>
//      * Only a subset of the allowed syntaxes are supported. Only ranges which specify first-byte-pos
//      * are supported. The last-byte-pos is optional.
//      *
//      * @param range The range from the HTTP header, for instance "bytes=0-499" or "bytes=500-"
//      * @return A range object (using inclusive values). If the last-byte-pos is not given, the end of
//      *         the returned range is {@code null}. The method returns <code>null</code> if the syntax
//      *         of the given range is not supported.
//      */
//     public static HttpRange valueOf(String range) {
//         if (range == null) {
//             return null;
//         }
// 
//         Matcher matcher = PATTERN.matcher(range);
//         if (matcher.matches()) {
//             String firstString = matcher.group(1);
//             String lastString = StringUtils.trimToNull(matcher.group(2));
// 
//             Long first = Long.parseLong(firstString);
//             Long last = lastString == null ? null : Long.parseLong(lastString);
// 
//             if (last != null && first > last) {
//                 return null;
//             }
//             return new HttpRange(first, last);
//         }
//         return null;
//     }
// 
//     public HttpRange(long firstBytePos, Long lastBytePos) {
//         this.firstBytePos = firstBytePos;
//         this.lastBytePos = lastBytePos;
//     }
// 
//     /**
//      * @return The first byte position (inclusive) in the range. Never {@code null}.
//      */
//     public Long getFirstBytePos() {
//         return firstBytePos;
//     }
// 
//     /**
//      * @return The last byte position (inclusive) in the range. Can be {@code null}.
//      */
//     public Long getLastBytePos() {
//         return lastBytePos;
//     }
// 
//     /**
//      * @return Whether this is a closed range (both first and last byte position specified).
//      */
//     public boolean isClosed() {
//         return firstBytePos != null && lastBytePos != null;
//     }
// 
//     /**
//      * @return The size in bytes if the range is closed, -1 otherwise.
//      */
//     public long size() {
//         return isClosed() ? (lastBytePos - firstBytePos + 1) : -1;
//     }
// 
//     /**
//      * @return Returns whether the given byte position is within this range.
//      */
//     public boolean contains(long pos) {
//         if (pos < firstBytePos) {
//             return false;
//         }
//         return lastBytePos == null || pos <= lastBytePos;
//     }
// 
//     @Override
//     public String toString() {
//         StringBuilder builder = new StringBuilder();
//         builder.append(firstBytePos).append('-');
//         if (lastBytePos != null) {
//             builder.append(lastBytePos);
//         }
//         return builder.toString();
//     }
// }


// Path: subsonic-main/src/test/java/net/sourceforge/subsonic/io/RangeOutputStreamTestCase.java
import junit.framework.TestCase;
import net.sourceforge.subsonic.util.HttpRange;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

        doTestWrap(0, 99, 100, 100);

        doTestWrap(10, 99, 100, 1);
        doTestWrap(10, 99, 100, 10);
        doTestWrap(10, 99, 100, 13);
        doTestWrap(10, 99, 100, 70);
        doTestWrap(10, 99, 100, 100);

        doTestWrap(66, 66, 100, 1);
        doTestWrap(66, 66, 100, 2);

        doTestWrap(10, 20, 100, 1);
        doTestWrap(10, 20, 100, 10);
        doTestWrap(10, 20, 100, 13);
        doTestWrap(10, 20, 100, 70);
        doTestWrap(10, 20, 100, 100);

        for (int start = 0; start < 10; start++) {
            for (int end = start; end < 10; end++) {
                for (int bufferSize = 1; bufferSize < 10; bufferSize++) {
                    doTestWrap(start, end, 10, bufferSize);
                    doTestWrap(start, null, 10, bufferSize);
                }
            }
        }
    }

    private void doTestWrap(int first, Integer last, int sourceSize, int bufferSize) throws Exception {
        byte[] source = createSource(sourceSize);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        OutputStream rangeOut = RangeOutputStream.wrap(out, new HttpRange((long) first, last == null ? null : last.longValue()));