public static function tokenizeResponse(&$str, $num=0)
    {
        $result = array();

        while (!$num || count($result) < $num) {
            // remove spaces from the beginning of the string
            $str = ltrim($str);

            switch ($str[0]) {

            // String literal
            case '{':
                if (($epos = strpos($str, "}\r\n", 1)) == false) {
                    // error
                }
                if (!is_numeric(($bytes = substr($str, 1, $epos - 1)))) {
                    // error
                }

                $result[] = $bytes ? substr($str, $epos + 3, $bytes) : '';
                $str      = substr($str, $epos + 3 + $bytes);
                break;

            // Quoted string
            case '"':
                $len = strlen($str);

                for ($pos=1; $pos<$len; $pos++) {
                    if ($str[$pos] == '"') {
                        break;
                    }
                    if ($str[$pos] == "\\") {
                        if ($str[$pos + 1] == '"' || $str[$pos + 1] == "\\") {
                            $pos++;
                        }
                    }
                }

                // we need to strip slashes for a quoted string
                $result[] = stripslashes(substr($str, 1, $pos - 1));
                $str      = substr($str, $pos + 1);
                break;

            // Parenthesized list
            case '(':
                $str      = substr($str, 1);
                $result[] = self::tokenizeResponse($str);
                break;

            case ')':
                $str = substr($str, 1);
                return $result;

            // String atom, number, astring, NIL, *, %
            default:
                // empty string
                if ($str === '' || $str === null) {
                    break 2;
                }

                // excluded chars: SP, CTL, ), DEL
                // we do not exclude [ and ] (#1489223)
                if (preg_match('/^([^\x00-\x20\x29\x7F]+)/', $str, $m)) {
                    $result[] = $m[1] == 'NIL' ? null : $m[1];
                    $str      = substr($str, strlen($m[1]));
                }
                break;
            }
        }

        return $num == 1 ? $result[0] : $result;
    }