321 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			321 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#include <Python.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject* markup;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								init_constants(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									PyObject *module;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* import markup type so that we can mark the return value */
							 | 
						||
| 
								 | 
							
									module = PyImport_ImportModule("markupsafe");
							 | 
						||
| 
								 | 
							
									if (!module)
							 | 
						||
| 
								 | 
							
										return 0;
							 | 
						||
| 
								 | 
							
									markup = PyObject_GetAttrString(module, "Markup");
							 | 
						||
| 
								 | 
							
									Py_DECREF(module);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define GET_DELTA(inp, inp_end, delta) \
							 | 
						||
| 
								 | 
							
									while (inp < inp_end) { \
							 | 
						||
| 
								 | 
							
										switch (*inp++) { \
							 | 
						||
| 
								 | 
							
										case '"': \
							 | 
						||
| 
								 | 
							
										case '\'': \
							 | 
						||
| 
								 | 
							
										case '&': \
							 | 
						||
| 
								 | 
							
											delta += 4; \
							 | 
						||
| 
								 | 
							
											break; \
							 | 
						||
| 
								 | 
							
										case '<': \
							 | 
						||
| 
								 | 
							
										case '>': \
							 | 
						||
| 
								 | 
							
											delta += 3; \
							 | 
						||
| 
								 | 
							
											break; \
							 | 
						||
| 
								 | 
							
										} \
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define DO_ESCAPE(inp, inp_end, outp) \
							 | 
						||
| 
								 | 
							
									{ \
							 | 
						||
| 
								 | 
							
										Py_ssize_t ncopy = 0; \
							 | 
						||
| 
								 | 
							
										while (inp < inp_end) { \
							 | 
						||
| 
								 | 
							
											switch (*inp) { \
							 | 
						||
| 
								 | 
							
											case '"': \
							 | 
						||
| 
								 | 
							
												memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \
							 | 
						||
| 
								 | 
							
												outp += ncopy; ncopy = 0; \
							 | 
						||
| 
								 | 
							
												*outp++ = '&'; \
							 | 
						||
| 
								 | 
							
												*outp++ = '#'; \
							 | 
						||
| 
								 | 
							
												*outp++ = '3'; \
							 | 
						||
| 
								 | 
							
												*outp++ = '4'; \
							 | 
						||
| 
								 | 
							
												*outp++ = ';'; \
							 | 
						||
| 
								 | 
							
												break; \
							 | 
						||
| 
								 | 
							
											case '\'': \
							 | 
						||
| 
								 | 
							
												memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \
							 | 
						||
| 
								 | 
							
												outp += ncopy; ncopy = 0; \
							 | 
						||
| 
								 | 
							
												*outp++ = '&'; \
							 | 
						||
| 
								 | 
							
												*outp++ = '#'; \
							 | 
						||
| 
								 | 
							
												*outp++ = '3'; \
							 | 
						||
| 
								 | 
							
												*outp++ = '9'; \
							 | 
						||
| 
								 | 
							
												*outp++ = ';'; \
							 | 
						||
| 
								 | 
							
												break; \
							 | 
						||
| 
								 | 
							
											case '&': \
							 | 
						||
| 
								 | 
							
												memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \
							 | 
						||
| 
								 | 
							
												outp += ncopy; ncopy = 0; \
							 | 
						||
| 
								 | 
							
												*outp++ = '&'; \
							 | 
						||
| 
								 | 
							
												*outp++ = 'a'; \
							 | 
						||
| 
								 | 
							
												*outp++ = 'm'; \
							 | 
						||
| 
								 | 
							
												*outp++ = 'p'; \
							 | 
						||
| 
								 | 
							
												*outp++ = ';'; \
							 | 
						||
| 
								 | 
							
												break; \
							 | 
						||
| 
								 | 
							
											case '<': \
							 | 
						||
| 
								 | 
							
												memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \
							 | 
						||
| 
								 | 
							
												outp += ncopy; ncopy = 0; \
							 | 
						||
| 
								 | 
							
												*outp++ = '&'; \
							 | 
						||
| 
								 | 
							
												*outp++ = 'l'; \
							 | 
						||
| 
								 | 
							
												*outp++ = 't'; \
							 | 
						||
| 
								 | 
							
												*outp++ = ';'; \
							 | 
						||
| 
								 | 
							
												break; \
							 | 
						||
| 
								 | 
							
											case '>': \
							 | 
						||
| 
								 | 
							
												memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \
							 | 
						||
| 
								 | 
							
												outp += ncopy; ncopy = 0; \
							 | 
						||
| 
								 | 
							
												*outp++ = '&'; \
							 | 
						||
| 
								 | 
							
												*outp++ = 'g'; \
							 | 
						||
| 
								 | 
							
												*outp++ = 't'; \
							 | 
						||
| 
								 | 
							
												*outp++ = ';'; \
							 | 
						||
| 
								 | 
							
												break; \
							 | 
						||
| 
								 | 
							
											default: \
							 | 
						||
| 
								 | 
							
												ncopy++; \
							 | 
						||
| 
								 | 
							
											} \
							 | 
						||
| 
								 | 
							
											inp++; \
							 | 
						||
| 
								 | 
							
										} \
							 | 
						||
| 
								 | 
							
										memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject*
							 | 
						||
| 
								 | 
							
								escape_unicode_kind1(PyUnicodeObject *in)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									Py_UCS1 *inp = PyUnicode_1BYTE_DATA(in);
							 | 
						||
| 
								 | 
							
									Py_UCS1 *inp_end = inp + PyUnicode_GET_LENGTH(in);
							 | 
						||
| 
								 | 
							
									Py_UCS1 *outp;
							 | 
						||
| 
								 | 
							
									PyObject *out;
							 | 
						||
| 
								 | 
							
									Py_ssize_t delta = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									GET_DELTA(inp, inp_end, delta);
							 | 
						||
| 
								 | 
							
									if (!delta) {
							 | 
						||
| 
								 | 
							
										Py_INCREF(in);
							 | 
						||
| 
								 | 
							
										return (PyObject*)in;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta,
							 | 
						||
| 
								 | 
							
														PyUnicode_IS_ASCII(in) ? 127 : 255);
							 | 
						||
| 
								 | 
							
									if (!out)
							 | 
						||
| 
								 | 
							
										return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									inp = PyUnicode_1BYTE_DATA(in);
							 | 
						||
| 
								 | 
							
									outp = PyUnicode_1BYTE_DATA(out);
							 | 
						||
| 
								 | 
							
									DO_ESCAPE(inp, inp_end, outp);
							 | 
						||
| 
								 | 
							
									return out;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject*
							 | 
						||
| 
								 | 
							
								escape_unicode_kind2(PyUnicodeObject *in)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									Py_UCS2 *inp = PyUnicode_2BYTE_DATA(in);
							 | 
						||
| 
								 | 
							
									Py_UCS2 *inp_end = inp + PyUnicode_GET_LENGTH(in);
							 | 
						||
| 
								 | 
							
									Py_UCS2 *outp;
							 | 
						||
| 
								 | 
							
									PyObject *out;
							 | 
						||
| 
								 | 
							
									Py_ssize_t delta = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									GET_DELTA(inp, inp_end, delta);
							 | 
						||
| 
								 | 
							
									if (!delta) {
							 | 
						||
| 
								 | 
							
										Py_INCREF(in);
							 | 
						||
| 
								 | 
							
										return (PyObject*)in;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta, 65535);
							 | 
						||
| 
								 | 
							
									if (!out)
							 | 
						||
| 
								 | 
							
										return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									inp = PyUnicode_2BYTE_DATA(in);
							 | 
						||
| 
								 | 
							
									outp = PyUnicode_2BYTE_DATA(out);
							 | 
						||
| 
								 | 
							
									DO_ESCAPE(inp, inp_end, outp);
							 | 
						||
| 
								 | 
							
									return out;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject*
							 | 
						||
| 
								 | 
							
								escape_unicode_kind4(PyUnicodeObject *in)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									Py_UCS4 *inp = PyUnicode_4BYTE_DATA(in);
							 | 
						||
| 
								 | 
							
									Py_UCS4 *inp_end = inp + PyUnicode_GET_LENGTH(in);
							 | 
						||
| 
								 | 
							
									Py_UCS4 *outp;
							 | 
						||
| 
								 | 
							
									PyObject *out;
							 | 
						||
| 
								 | 
							
									Py_ssize_t delta = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									GET_DELTA(inp, inp_end, delta);
							 | 
						||
| 
								 | 
							
									if (!delta) {
							 | 
						||
| 
								 | 
							
										Py_INCREF(in);
							 | 
						||
| 
								 | 
							
										return (PyObject*)in;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta, 1114111);
							 | 
						||
| 
								 | 
							
									if (!out)
							 | 
						||
| 
								 | 
							
										return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									inp = PyUnicode_4BYTE_DATA(in);
							 | 
						||
| 
								 | 
							
									outp = PyUnicode_4BYTE_DATA(out);
							 | 
						||
| 
								 | 
							
									DO_ESCAPE(inp, inp_end, outp);
							 | 
						||
| 
								 | 
							
									return out;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject*
							 | 
						||
| 
								 | 
							
								escape_unicode(PyUnicodeObject *in)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (PyUnicode_READY(in))
							 | 
						||
| 
								 | 
							
										return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									switch (PyUnicode_KIND(in)) {
							 | 
						||
| 
								 | 
							
									case PyUnicode_1BYTE_KIND:
							 | 
						||
| 
								 | 
							
										return escape_unicode_kind1(in);
							 | 
						||
| 
								 | 
							
									case PyUnicode_2BYTE_KIND:
							 | 
						||
| 
								 | 
							
										return escape_unicode_kind2(in);
							 | 
						||
| 
								 | 
							
									case PyUnicode_4BYTE_KIND:
							 | 
						||
| 
								 | 
							
										return escape_unicode_kind4(in);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									assert(0);  /* shouldn't happen */
							 | 
						||
| 
								 | 
							
									return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject*
							 | 
						||
| 
								 | 
							
								escape(PyObject *self, PyObject *text)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									static PyObject *id_html;
							 | 
						||
| 
								 | 
							
									PyObject *s = NULL, *rv = NULL, *html;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (id_html == NULL) {
							 | 
						||
| 
								 | 
							
										id_html = PyUnicode_InternFromString("__html__");
							 | 
						||
| 
								 | 
							
										if (id_html == NULL) {
							 | 
						||
| 
								 | 
							
											return NULL;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* we don't have to escape integers, bools or floats */
							 | 
						||
| 
								 | 
							
									if (PyLong_CheckExact(text) ||
							 | 
						||
| 
								 | 
							
										PyFloat_CheckExact(text) || PyBool_Check(text) ||
							 | 
						||
| 
								 | 
							
										text == Py_None)
							 | 
						||
| 
								 | 
							
										return PyObject_CallFunctionObjArgs(markup, text, NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* if the object has an __html__ method that performs the escaping */
							 | 
						||
| 
								 | 
							
									html = PyObject_GetAttr(text ,id_html);
							 | 
						||
| 
								 | 
							
									if (html) {
							 | 
						||
| 
								 | 
							
										s = PyObject_CallObject(html, NULL);
							 | 
						||
| 
								 | 
							
										Py_DECREF(html);
							 | 
						||
| 
								 | 
							
										if (s == NULL) {
							 | 
						||
| 
								 | 
							
											return NULL;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										/* Convert to Markup object */
							 | 
						||
| 
								 | 
							
										rv = PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL);
							 | 
						||
| 
								 | 
							
										Py_DECREF(s);
							 | 
						||
| 
								 | 
							
										return rv;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* otherwise make the object unicode if it isn't, then escape */
							 | 
						||
| 
								 | 
							
									PyErr_Clear();
							 | 
						||
| 
								 | 
							
									if (!PyUnicode_Check(text)) {
							 | 
						||
| 
								 | 
							
										PyObject *unicode = PyObject_Str(text);
							 | 
						||
| 
								 | 
							
										if (!unicode)
							 | 
						||
| 
								 | 
							
											return NULL;
							 | 
						||
| 
								 | 
							
										s = escape_unicode((PyUnicodeObject*)unicode);
							 | 
						||
| 
								 | 
							
										Py_DECREF(unicode);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										s = escape_unicode((PyUnicodeObject*)text);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* convert the unicode string into a markup object. */
							 | 
						||
| 
								 | 
							
									rv = PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL);
							 | 
						||
| 
								 | 
							
									Py_DECREF(s);
							 | 
						||
| 
								 | 
							
									return rv;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject*
							 | 
						||
| 
								 | 
							
								escape_silent(PyObject *self, PyObject *text)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (text != Py_None)
							 | 
						||
| 
								 | 
							
										return escape(self, text);
							 | 
						||
| 
								 | 
							
									return PyObject_CallFunctionObjArgs(markup, NULL);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject*
							 | 
						||
| 
								 | 
							
								soft_str(PyObject *self, PyObject *s)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (!PyUnicode_Check(s))
							 | 
						||
| 
								 | 
							
										return PyObject_Str(s);
							 | 
						||
| 
								 | 
							
									Py_INCREF(s);
							 | 
						||
| 
								 | 
							
									return s;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyMethodDef module_methods[] = {
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										"escape",
							 | 
						||
| 
								 | 
							
										(PyCFunction)escape,
							 | 
						||
| 
								 | 
							
										METH_O,
							 | 
						||
| 
								 | 
							
										"Replace the characters ``&``, ``<``, ``>``, ``'``, and ``\"`` in"
							 | 
						||
| 
								 | 
							
										" the string with HTML-safe sequences. Use this if you need to display"
							 | 
						||
| 
								 | 
							
										" text that might contain such characters in HTML.\n\n"
							 | 
						||
| 
								 | 
							
										"If the object has an ``__html__`` method, it is called and the"
							 | 
						||
| 
								 | 
							
										" return value is assumed to already be safe for HTML.\n\n"
							 | 
						||
| 
								 | 
							
										":param s: An object to be converted to a string and escaped.\n"
							 | 
						||
| 
								 | 
							
										":return: A :class:`Markup` string with the escaped text.\n"
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										"escape_silent",
							 | 
						||
| 
								 | 
							
										(PyCFunction)escape_silent,
							 | 
						||
| 
								 | 
							
										METH_O,
							 | 
						||
| 
								 | 
							
										"Like :func:`escape` but treats ``None`` as the empty string."
							 | 
						||
| 
								 | 
							
										" Useful with optional values, as otherwise you get the string"
							 | 
						||
| 
								 | 
							
										" ``'None'`` when the value is ``None``.\n\n"
							 | 
						||
| 
								 | 
							
										">>> escape(None)\n"
							 | 
						||
| 
								 | 
							
										"Markup('None')\n"
							 | 
						||
| 
								 | 
							
										">>> escape_silent(None)\n"
							 | 
						||
| 
								 | 
							
										"Markup('')\n"
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										"soft_str",
							 | 
						||
| 
								 | 
							
										(PyCFunction)soft_str,
							 | 
						||
| 
								 | 
							
										METH_O,
							 | 
						||
| 
								 | 
							
										"Convert an object to a string if it isn't already. This preserves"
							 | 
						||
| 
								 | 
							
										" a :class:`Markup` string rather than converting it back to a basic"
							 | 
						||
| 
								 | 
							
										" string, so it will still be marked as safe and won't be escaped"
							 | 
						||
| 
								 | 
							
										" again.\n\n"
							 | 
						||
| 
								 | 
							
										">>> value = escape(\"<User 1>\")\n"
							 | 
						||
| 
								 | 
							
										">>> value\n"
							 | 
						||
| 
								 | 
							
										"Markup('<User 1>')\n"
							 | 
						||
| 
								 | 
							
										">>> escape(str(value))\n"
							 | 
						||
| 
								 | 
							
										"Markup('&lt;User 1&gt;')\n"
							 | 
						||
| 
								 | 
							
										">>> escape(soft_str(value))\n"
							 | 
						||
| 
								 | 
							
										"Markup('<User 1>')\n"
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{NULL, NULL, 0, NULL}  /* Sentinel */
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static struct PyModuleDef module_definition = {
							 | 
						||
| 
								 | 
							
									PyModuleDef_HEAD_INIT,
							 | 
						||
| 
								 | 
							
									"markupsafe._speedups",
							 | 
						||
| 
								 | 
							
									NULL,
							 | 
						||
| 
								 | 
							
									-1,
							 | 
						||
| 
								 | 
							
									module_methods,
							 | 
						||
| 
								 | 
							
									NULL,
							 | 
						||
| 
								 | 
							
									NULL,
							 | 
						||
| 
								 | 
							
									NULL,
							 | 
						||
| 
								 | 
							
									NULL
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PyMODINIT_FUNC
							 | 
						||
| 
								 | 
							
								PyInit__speedups(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (!init_constants())
							 | 
						||
| 
								 | 
							
										return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return PyModule_Create(&module_definition);
							 | 
						||
| 
								 | 
							
								}
							 |