1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Anatol Belski <ab@php.net>                                  |
16    +----------------------------------------------------------------------+
17 */
18 
19 #ifdef HAVE_CONFIG_H
20 #	include "config.h"
21 #endif
22 
23 #include "phpdbg.h"
24 #include "phpdbg_eol.h"
25 
26 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
27 
28 #define EOL_LIST_LEN 4
29 struct phpdbg_eol_rep phpdbg_eol_list[EOL_LIST_LEN] = {
30 	{"CRLF", "\r\n", PHPDBG_EOL_CRLF},
31 /*	{"LFCR", "\n\r", PHPDBG_EOL_LFCR},*/
32 	{"LF", "\n", PHPDBG_EOL_LF},
33 	{"CR", "\r", PHPDBG_EOL_CR},
34 };
35 
phpdbg_eol_global_update(char *name)36 int phpdbg_eol_global_update(char *name)
37 {
38 
39 	if (0 == strcmp(name, "CRLF") || 0 == strcmp(name, "crlf") || 0 == strcmp(name, "DOS") || 0 == strcmp(name, "dos")) {
40 		PHPDBG_G(eol) = PHPDBG_EOL_CRLF;
41 	} else if (0 == strcmp(name, "LF") || 0 == strcmp(name, "lf") || 0 == strcmp(name, "UNIX") || 0 == strcmp(name, "unix")) {
42 		PHPDBG_G(eol) = PHPDBG_EOL_LF;
43 	} else if (0 == strcmp(name, "CR") || 0 == strcmp(name, "cr") || 0 == strcmp(name, "MAC") || 0 == strcmp(name, "mac")) {
44 		PHPDBG_G(eol) = PHPDBG_EOL_CR;
45 	} else {
46 		return FAILURE;
47 	}
48 
49 	return SUCCESS;
50 }
51 
phpdbg_eol_name(int id)52 char *phpdbg_eol_name(int id)
53 {
54 	size_t i = 0;
55 
56 	while (i < EOL_LIST_LEN) {
57 
58 		if (id == phpdbg_eol_list[i].id) {
59 			return phpdbg_eol_list[i].name;
60 		}
61 
62 		i++;
63 	}
64 
65 	return NULL;
66 }
67 
phpdbg_eol_rep(int id)68 char *phpdbg_eol_rep(int id)
69 {
70 	size_t i = 0;
71 
72 	while (i < EOL_LIST_LEN) {
73 
74 		if (id == phpdbg_eol_list[i].id) {
75 			return phpdbg_eol_list[i].rep;
76 		}
77 
78 		i++;
79 	}
80 
81 	return NULL;
82 }
83 
84 /* Marked as never_inline to work around a -Walloc-size-larger-than bug in GCC. */
count_lf_and_cr(const char *in, int in_len)85 static zend_never_inline int count_lf_and_cr(const char *in, int in_len) {
86 	int i, count = 0;
87 	for (i = 0; i < in_len; i++) {
88 		if (0x0a == in[i] || 0x0d == in[i]) {
89 			count++;
90 		}
91 	}
92 	return count;
93 }
94 
95 /* Inspired by https://ccrma.stanford.edu/~craig/utility/flip/flip.cpp */
phpdbg_eol_convert(char **str, int *len)96 void phpdbg_eol_convert(char **str, int *len)
97 {
98 	char *in = *str, *out;
99 	int in_len = *len, cursor, i;
100 	char last, cur;
101 
102 	if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) != PHPDBG_IS_REMOTE) {
103 		return;
104 	}
105 
106 	if (PHPDBG_EOL_CRLF == PHPDBG_G(eol)) { /* XXX add LFCR case if it's gonna be needed */
107 		out = (char *)emalloc(in_len + count_lf_and_cr(in, in_len));
108 
109 		last = cur = in[0];
110 		i = cursor = 0;
111 		for (; i < in_len;) {
112 			if (0x0a == cur && last != 0x0d) {
113 				out[cursor] = 0x0d;
114 				cursor++;
115 				out[cursor] = cur;
116 			} else if(0x0d == cur) {
117 				if (i + 1 < in_len && 0x0a != in[i+1]) {
118 					out[cursor] = cur;
119 					cursor++;
120 					out[cursor] = 0x0a;
121 					last = 0x0a;
122 				} else {
123 					out[cursor] = 0x0d;
124 					last = 0x0d;
125 				}
126 			} else {
127 				out[cursor] = cur;
128 				last = cur;
129 			}
130 
131 			i++;
132 			cursor++;
133 			cur = in[i];
134 		}
135 
136 	} else if (PHPDBG_EOL_LF == PHPDBG_G(eol) || PHPDBG_EOL_CR == PHPDBG_G(eol)) {
137 		char want, kick;
138 
139 		if (PHPDBG_EOL_LF == PHPDBG_G(eol)) {
140 			want = 0x0a;
141 			kick = 0x0d;
142 		} else {
143 			want = 0x0d;
144 			kick = 0x0a;
145 		}
146 
147 		/* We gonna have a smaller or equally long string, estimation is almost neglecting */
148 		out = (char *)emalloc(in_len);
149 
150 		last = cur = in[0];
151 		i = cursor = 0;
152 		for (; cursor < in_len;) {
153 			if (kick == cur) {
154 				out[cursor] = want;
155 			} else if (want == cur) {
156 				if (kick != last) {
157 					out[cursor] = want;
158 				}
159 			} else {
160 				out[cursor] = cur;
161 			}
162 
163 			last = cur;
164 			cursor++;
165 			cur = in[cursor];
166 		}
167 	} else {
168 		return;
169 	}
170 
171 	efree(*str);
172 	*str = erealloc(out, cursor);
173 	*len = cursor;
174 	in = NULL;
175 }
176