1/*
2 * log-escape.c :  Functions for escaping log items
3 *                 copied from Apache httpd
4 *
5 * ====================================================================
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *     http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 * ====================================================================
22 *    Licensed to the Apache Software Foundation (ASF) under one
23 *    or more contributor license agreements.  See the NOTICE file
24 *    distributed with this work for additional information
25 *    regarding copyright ownership.  The ASF licenses this file
26 *    to you under the Apache License, Version 2.0 (the
27 *    "License"); you may not use this file except in compliance
28 *    with the License.  You may obtain a copy of the License at
29 *
30 *      http://www.apache.org/licenses/LICENSE-2.0
31 *
32 *    Unless required by applicable law or agreed to in writing,
33 *    software distributed under the License is distributed on an
34 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
35 *    KIND, either express or implied.  See the License for the
36 *    specific language governing permissions and limitations
37 *    under the License.
38 * ====================================================================
39 */
40
41
42#include <apr.h>
43#define APR_WANT_STRFUNC
44#include <apr_want.h>
45#include "server.h"
46#include "svn_ctype.h"
47
48/* copied from httpd-2.2.4/server/util.c */
49/* c2x takes an unsigned, and expects the caller has guaranteed that
50 * 0 <= what < 256... which usually means that you have to cast to
51 * unsigned char first, because (unsigned)(char)(x) first goes through
52 * signed extension to an int before the unsigned cast.
53 *
54 * The reason for this assumption is to assist gcc code generation --
55 * the unsigned char -> unsigned extension is already done earlier in
56 * both uses of this code, so there's no need to waste time doing it
57 * again.
58 */
59static const char c2x_table[] = "0123456789abcdef";
60
61/* copied from httpd-2.2.4/server/util.c */
62static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
63                                     unsigned char *where)
64{
65#if APR_CHARSET_EBCDIC
66    what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
67#endif /*APR_CHARSET_EBCDIC*/
68    *where++ = prefix;
69    *where++ = c2x_table[what >> 4];
70    *where++ = c2x_table[what & 0xf];
71    return where;
72}
73
74/* copied from httpd-2.2.4/server/util.c */
75apr_size_t escape_errorlog_item(char *dest, const char *source,
76                                apr_size_t buflen)
77{
78    unsigned char *d, *ep;
79    const unsigned char *s;
80
81    if (!source || !buflen) { /* be safe */
82        return 0;
83    }
84
85    d = (unsigned char *)dest;
86    s = (const unsigned char *)source;
87    ep = d + buflen - 1;
88
89    for (; d < ep && *s; ++s) {
90
91        /* httpd-2.2.4/server/util.c has this:
92             if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
93           which does this same check with a fast lookup table.  Well,
94           mostly the same; we don't escape quotes, as that does.
95        */
96        if (*s && (   !svn_ctype_isprint(*s)
97                   || *s == '\\'
98                   || svn_ctype_iscntrl(*s))) {
99            *d++ = '\\';
100            if (d >= ep) {
101                --d;
102                break;
103            }
104
105            switch(*s) {
106            case '\b':
107                *d++ = 'b';
108                break;
109            case '\n':
110                *d++ = 'n';
111                break;
112            case '\r':
113                *d++ = 'r';
114                break;
115            case '\t':
116                *d++ = 't';
117                break;
118            case '\v':
119                *d++ = 'v';
120                break;
121            case '\\':
122                *d++ = *s;
123                break;
124            case '"': /* no need for this in error log */
125                d[-1] = *s;
126                break;
127            default:
128                if (d >= ep - 2) {
129                    ep = --d; /* break the for loop as well */
130                    break;
131                }
132                c2x(*s, 'x', d);
133                d += 3;
134            }
135        }
136        else {
137            *d++ = *s;
138        }
139    }
140    *d = '\0';
141
142    return (d - (unsigned char *)dest);
143}
144