mercurial/base85.c
changeset 3287 e93c926e069e
parent 3279 1f2c3983a6c5
child 3330 a5209a1e53d8
equal deleted inserted replaced
3279:1f2c3983a6c5 3287:e93c926e069e
    31 	const unsigned char *text;
    31 	const unsigned char *text;
    32 	PyObject *out;
    32 	PyObject *out;
    33 	char *dst;
    33 	char *dst;
    34 	int len, olen, i;
    34 	int len, olen, i;
    35 	unsigned int acc, val, ch;
    35 	unsigned int acc, val, ch;
       
    36         int pad = 0;
    36 
    37 
    37 	if (!PyArg_ParseTuple(args, "s#", &text, &len))
    38 	if (!PyArg_ParseTuple(args, "s#|i", &text, &len, &pad))
    38 		return NULL;
    39 		return NULL;
    39 
    40 
    40 	olen = (len + 3) / 4 * 5;
    41         if (pad)
    41 	if (!(out = PyString_FromStringAndSize(NULL, olen)))
    42                 olen = ((len + 3) / 4 * 5) - 3;
       
    43         else {
       
    44                 olen = len % 4;
       
    45                 if (olen)
       
    46                         olen++;
       
    47                 olen += len / 4 * 5;
       
    48         }
       
    49 	if (!(out = PyString_FromStringAndSize(NULL, olen + 3)))
    42 		return NULL;
    50 		return NULL;
    43 
    51 
    44 	dst = PyString_AS_STRING(out);
    52 	dst = PyString_AS_STRING(out);
    45 
    53 
    46 	while (len)
    54 	while (len) {
    47 	{
       
    48 		acc = 0;
    55 		acc = 0;
    49 		for (i = 24; i >= 0; i -= 8) {
    56 		for (i = 24; i >= 0; i -= 8) {
    50 			ch = *text++;
    57 			ch = *text++;
    51 			acc |= ch << i;
    58 			acc |= ch << i;
    52 			if (--len == 0)
    59 			if (--len == 0)
    58 			dst[i] = b85chars[val];
    65 			dst[i] = b85chars[val];
    59 		}
    66 		}
    60 		dst += 5;
    67 		dst += 5;
    61 	}
    68 	}
    62 
    69 
       
    70         if (!pad)
       
    71                 _PyString_Resize(&out, olen);
       
    72 
    63 	return out;
    73 	return out;
    64 }
    74 }
    65 
    75 
    66 static PyObject *
    76 static PyObject *
    67 b85decode(PyObject *self, PyObject *args)
    77 b85decode(PyObject *self, PyObject *args)
    68 {
    78 {
    69 	PyObject *out;
    79 	PyObject *out;
    70 	const char *text;
    80 	const char *text;
    71 	char *dst;
    81 	char *dst;
    72 	int len, i, j, olen, c;
    82 	int len, i, j, olen, c, cap;
    73 	unsigned int acc;
    83 	unsigned int acc;
    74 
    84 
    75 	if (!PyArg_ParseTuple(args, "s#", &text, &len))
    85 	if (!PyArg_ParseTuple(args, "s#", &text, &len))
    76 		return NULL;
    86 		return NULL;
    77 
    87 
    78 	olen = (len + 4) / 5 * 4;
    88 	olen = len / 5 * 4;
       
    89 	i = len % 5;
       
    90 	if (i)
       
    91 		olen += i - 1;
    79 	if (!(out = PyString_FromStringAndSize(NULL, olen)))
    92 	if (!(out = PyString_FromStringAndSize(NULL, olen)))
    80 		return NULL;
    93 		return NULL;
    81 
    94 
    82 	dst = PyString_AS_STRING(out);
    95 	dst = PyString_AS_STRING(out);
    83 
    96 
    84 	for (i = 1; len; i++)
    97 	i = 0;
       
    98 	while (i < len)
    85 	{
    99 	{
    86 		acc = 0;
   100 		acc = 0;
    87 		for (j = 0; j < 4 && --len; j++)
   101 		cap = len - i - 1;
       
   102 		if (cap > 4)
       
   103 			cap = 4;
       
   104 		for (j = 0; j < cap; i++, j++)
    88 		{
   105 		{
    89 			c = b85dec[(int)*text++] - 1;
   106 			c = b85dec[(int)*text++] - 1;
    90 			if (c < 0)
   107 			if (c < 0)
    91 				return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i);
   108 				return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i);
    92 			acc = acc * 85 + c;
   109 			acc = acc * 85 + c;
    93 		}
   110 		}
    94 		if (len--)
   111 		if (i++ < len)
    95 		{
   112 		{
    96 			c = b85dec[(int)*text++] - 1;
   113 			c = b85dec[(int)*text++] - 1;
    97 			if (c < 0)
   114 			if (c < 0)
    98 				return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i);
   115 				return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i);
       
   116 			/* overflow detection: 0xffffffff == "|NsC0",
       
   117 			 * "|NsC" == 0x03030303 */
       
   118 			if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c)
       
   119 				return PyErr_Format(PyExc_ValueError, "Bad base85 sequence at position %d", i);
       
   120 			acc += c;
    99 		}
   121 		}
   100 		else
       
   101 			c = 0;
       
   102 		/* overflow detection: 0xffffffff == "|NsC0",
       
   103 		 * "|NsC" == 0x03030303 */
       
   104 		if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c)
       
   105 			return PyErr_Format(PyExc_ValueError, "Bad base85 sequence at position %d", i);
       
   106 		
       
   107 		acc += c;
       
   108 
   122 
   109 		for (j = 0; j < 4; j++)
   123 		cap = olen < 4 ? olen : 4;
       
   124 		olen -= cap;
       
   125 		for (j = 0; j < 4 - cap; j++)
       
   126 			acc *= 85;
       
   127 		if (cap && cap < 4)
       
   128 			acc += 0xffffff >> (cap - 1) * 8;
       
   129 		for (j = 0; j < cap; j++)
   110 		{
   130 		{
   111 			acc = (acc << 8) | (acc >> 24);
   131 			acc = (acc << 8) | (acc >> 24);
   112 			*dst++ = (char)acc;
   132 			*dst++ = acc;
   113 		}
   133 		}
   114 	}
   134 	}
   115 
   135 
   116 	return out;
   136 	return out;
   117 }
   137 }
   118 
   138 
   119 static char base85_doc[] = "Base85 Data Encoding";
   139 static char base85_doc[] = "Base85 Data Encoding";
   120 
   140 
   121 static PyMethodDef methods[] = {
   141 static PyMethodDef methods[] = {
   122 	{"b85encode", b85encode, METH_VARARGS, "encode text in base85\n"},
   142 	{"b85encode", b85encode, METH_VARARGS,
   123 	{"b85decode", b85decode, METH_VARARGS, "decode base85 text\n"},
   143          "Encode text in base85.\n\n"
       
   144          "If the second parameter is true, pad the result to a multiple of "
       
   145          "five characters.\n"},
       
   146 	{"b85decode", b85decode, METH_VARARGS, "Decode base85 text.\n"},
   124 	{NULL, NULL}
   147 	{NULL, NULL}
   125 };
   148 };
   126 
   149 
   127 PyMODINIT_FUNC initbase85(void)
   150 PyMODINIT_FUNC initbase85(void)
   128 {
   151 {