public int read(char[] buf, int n) {
        if (buf == null || n <= 0) return 0;

        // read any remaining chars from last read
        int i = 0;
        while (!q.isEmpty() && i < n) {
            buf[i++] = q.remove();
        }

        char[] res = new char[4];
        for (; i < n; i += 4) {
            int resLen = read4(res);
            int len = Math.min(resLen, n - i);
            // normal copy
            for (int k = 0; k < len; ++k) buf[i + k] = res[k];

            // buffer any remaining chars to a queue so won't miss them upon next read
            if (len == n - i) {
                for (int k = n - i; k < resLen; ++k) q.add(res[k]);
            }

            // reach EOF
            if (resLen < 4) return i + len;
        }
        return n;
    }