protected boolean fill() throws IOException {
            // check if we already have readable data
            if (head != tail)
                return true;
            // shift extra unread data to beginning of buffer
            if (tail > 0 && extra > 0)
                System.arraycopy(buf, tail, buf, 0, extra);
            head = tail = 0;
            // read more until we have at least enough data for a boundary,
            // and if possible, more readable data
            do { 
                int read = super.read(buf, extra, buf.length - extra);
                if (read > -1) {
                    extra += read;
                } else if (extra < boundaryLength) {
                    if (extra == 0)
                        return false; // end of stream
                    throw new IOException("missing end boundary");
                }
            } while (extra < boundaryLength);
            // check if there's a boundary and update indices
            int max = findBoundary()[0];
            head = 0;
            tail = max == -1 ? extra - boundaryLength : max;
            extra -= tail;
            return max != 0; // no more readable data in current part
        }