Replace base{32,64}_decode() with table-driven implementations. The new
code is less strict about padding, thus ensuring compatibility with implementations which do not understand padding, such as MIME::Base32. git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@771 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
parent
4645bc1762
commit
17144e7a5f
|
@ -37,14 +37,36 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <security/oath.h>
|
#include <security/oath.h>
|
||||||
|
|
||||||
static const char b32[] =
|
static const char b32enc[] =
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
|
|
||||||
|
static const uint8_t b32dec[256] = {
|
||||||
|
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3,
|
||||||
|
['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7,
|
||||||
|
['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11,
|
||||||
|
['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
|
||||||
|
['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
|
||||||
|
['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23,
|
||||||
|
['Y'] = 24, ['Z'] = 25,
|
||||||
|
|
||||||
|
['a'] = 0, ['b'] = 1, ['c'] = 2, ['d'] = 3,
|
||||||
|
['e'] = 4, ['f'] = 5, ['g'] = 6, ['h'] = 7,
|
||||||
|
['i'] = 8, ['j'] = 9, ['k'] = 10, ['l'] = 11,
|
||||||
|
['m'] = 12, ['n'] = 13, ['o'] = 14, ['p'] = 15,
|
||||||
|
['q'] = 16, ['r'] = 17, ['s'] = 18, ['t'] = 19,
|
||||||
|
['u'] = 20, ['v'] = 21, ['w'] = 22, ['x'] = 23,
|
||||||
|
['y'] = 24, ['z'] = 25,
|
||||||
|
|
||||||
|
['2'] = 26, ['3'] = 27, ['4'] = 28, ['5'] = 29,
|
||||||
|
['6'] = 30, ['7'] = 31,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode data in RFC 3548 base 32 representation. The target buffer must
|
* Encode data in RFC 4648 base 32 representation. The target buffer must
|
||||||
* have room for base32_enclen(len) characters and a terminating NUL.
|
* have room for base32_enclen(len) characters and a terminating NUL.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -52,8 +74,10 @@ base32_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||||
{
|
{
|
||||||
uint64_t bits;
|
uint64_t bits;
|
||||||
|
|
||||||
if (*olen <= base32_enclen(ilen))
|
if (*olen <= base32_enclen(ilen)) {
|
||||||
|
errno = ENOSPC;
|
||||||
return (-1);
|
return (-1);
|
||||||
|
}
|
||||||
*olen = 0;
|
*olen = 0;
|
||||||
while (ilen >= 5) {
|
while (ilen >= 5) {
|
||||||
bits = 0;
|
bits = 0;
|
||||||
|
@ -64,14 +88,14 @@ base32_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||||
bits |= (uint64_t)in[4];
|
bits |= (uint64_t)in[4];
|
||||||
ilen -= 5;
|
ilen -= 5;
|
||||||
in += 5;
|
in += 5;
|
||||||
out[0] = b32[bits >> 35 & 0x1f];
|
out[0] = b32enc[bits >> 35 & 0x1f];
|
||||||
out[1] = b32[bits >> 30 & 0x1f];
|
out[1] = b32enc[bits >> 30 & 0x1f];
|
||||||
out[2] = b32[bits >> 25 & 0x1f];
|
out[2] = b32enc[bits >> 25 & 0x1f];
|
||||||
out[3] = b32[bits >> 20 & 0x1f];
|
out[3] = b32enc[bits >> 20 & 0x1f];
|
||||||
out[4] = b32[bits >> 15 & 0x1f];
|
out[4] = b32enc[bits >> 15 & 0x1f];
|
||||||
out[5] = b32[bits >> 10 & 0x1f];
|
out[5] = b32enc[bits >> 10 & 0x1f];
|
||||||
out[6] = b32[bits >> 5 & 0x1f];
|
out[6] = b32enc[bits >> 5 & 0x1f];
|
||||||
out[7] = b32[bits & 0x1f];
|
out[7] = b32enc[bits & 0x1f];
|
||||||
*olen += 8;
|
*olen += 8;
|
||||||
out += 8;
|
out += 8;
|
||||||
}
|
}
|
||||||
|
@ -87,13 +111,13 @@ base32_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||||
case 1:
|
case 1:
|
||||||
bits |= (uint64_t)in[0] << 32;
|
bits |= (uint64_t)in[0] << 32;
|
||||||
}
|
}
|
||||||
out[0] = b32[bits >> 35 & 0x1f];
|
out[0] = b32enc[bits >> 35 & 0x1f];
|
||||||
out[1] = b32[bits >> 30 & 0x1f];
|
out[1] = b32enc[bits >> 30 & 0x1f];
|
||||||
out[2] = ilen > 1 ? b32[bits >> 25 & 0x1f] : '=';
|
out[2] = ilen > 1 ? b32enc[bits >> 25 & 0x1f] : '=';
|
||||||
out[3] = ilen > 1 ? b32[bits >> 20 & 0x1f] : '=';
|
out[3] = ilen > 1 ? b32enc[bits >> 20 & 0x1f] : '=';
|
||||||
out[4] = ilen > 2 ? b32[bits >> 15 & 0x1f] : '=';
|
out[4] = ilen > 2 ? b32enc[bits >> 15 & 0x1f] : '=';
|
||||||
out[5] = ilen > 3 ? b32[bits >> 10 & 0x1f] : '=';
|
out[5] = ilen > 3 ? b32enc[bits >> 10 & 0x1f] : '=';
|
||||||
out[6] = ilen > 3 ? b32[bits >> 5 & 0x1f] : '=';
|
out[6] = ilen > 3 ? b32enc[bits >> 5 & 0x1f] : '=';
|
||||||
out[7] = '=';
|
out[7] = '=';
|
||||||
*olen += 8;
|
*olen += 8;
|
||||||
out += 8;
|
out += 8;
|
||||||
|
@ -104,10 +128,15 @@ base32_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode data in RFC 2548 base 32 representation, stopping at the
|
* Decode data in RFC 4648 base 32 representation, stopping at the
|
||||||
* terminating NUL, the first invalid (non-base32, non-whitespace)
|
* terminating NUL, the first invalid (non-base32, non-whitespace)
|
||||||
* character or after len characters, whichever comes first.
|
* character or after len characters, whichever comes first.
|
||||||
*
|
*
|
||||||
|
* Padding is handled sloppily: any padding character following the data
|
||||||
|
* is silently consumed. This not only simplifies the code but ensures
|
||||||
|
* compatibility with implementations which do not emit or understand
|
||||||
|
* padding.
|
||||||
|
*
|
||||||
* The olen argument is used by the caller to pass the size of the buffer
|
* The olen argument is used by the caller to pass the size of the buffer
|
||||||
* and by base32_dec() to return the amount of data successfully decoded.
|
* and by base32_dec() to return the amount of data successfully decoded.
|
||||||
* If the buffer is too small, base32_dec() discards the excess data, but
|
* If the buffer is too small, base32_dec() discards the excess data, but
|
||||||
|
@ -117,90 +146,40 @@ int
|
||||||
base32_dec(const char *in, size_t ilen, uint8_t *out, size_t *olen)
|
base32_dec(const char *in, size_t ilen, uint8_t *out, size_t *olen)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
uint64_t bits;
|
int bits, shift, padding;
|
||||||
int shift;
|
|
||||||
|
|
||||||
for (len = 0, bits = 0, shift = 40; ilen && *in && *in != '='; --ilen, ++in) {
|
for (bits = shift = padding = len = 0; ilen && *in; --ilen, ++in) {
|
||||||
if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n') {
|
if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n' ||
|
||||||
|
(padding && *in == '=')) {
|
||||||
|
/* consume */
|
||||||
continue;
|
continue;
|
||||||
} else if (*in >= 'A' && *in <= 'Z') {
|
} else if (!padding && b32dec[(int)*in]) {
|
||||||
shift -= 5;
|
/* shift into accumulator */
|
||||||
bits |= (uint64_t)(*in - 'A') << shift;
|
shift += 5;
|
||||||
} else if (*in >= 'a' && *in <= 'z') {
|
bits = bits << 5 | b32dec[(int)*in];
|
||||||
shift -= 5;
|
} else if (!padding && shift && *in == '=') {
|
||||||
bits |= (uint64_t)(*in - 'a') << shift;
|
/* final byte */
|
||||||
} else if (*in >= '2' && *in <= '7') {
|
shift = 0;
|
||||||
shift -= 5;
|
padding = 1;
|
||||||
bits |= (uint64_t)(*in - '2' + 26) << shift;
|
|
||||||
} else if (*in == '=') {
|
|
||||||
/* handled below */
|
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
goto bad;
|
/* error */
|
||||||
|
*olen = 0;
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
}
|
}
|
||||||
if (shift == 0) {
|
if (shift >= 8) {
|
||||||
if ((len += 5) <= *olen) {
|
/* output accumulated byte */
|
||||||
*out++ = (bits >> 32) & 0xff;
|
shift -= 8;
|
||||||
*out++ = (bits >> 24) & 0xff;
|
if (len++ < *olen)
|
||||||
*out++ = (bits >> 16) & 0xff;
|
*out++ = (bits >> shift) & 0xff;
|
||||||
*out++ = (bits >> 8) & 0xff;
|
|
||||||
*out++ = bits & 0xff;
|
|
||||||
}
|
|
||||||
bits = 0;
|
|
||||||
shift = 40;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ilen && *in == '=' &&
|
/* report decoded length */
|
||||||
(shift == 30 || shift == 20 || shift == 15 || shift == 5)) {
|
|
||||||
/*
|
|
||||||
* Padding:
|
|
||||||
*
|
|
||||||
* 00 8 AA====== 30
|
|
||||||
* 00 00 16 AAAA==== 20
|
|
||||||
* 00 00 00 24 AAAAA=== 15
|
|
||||||
* 00 00 00 00 32 AAAAAAA= 5
|
|
||||||
*
|
|
||||||
* XXX We should check that the last few bits before the
|
|
||||||
* padding starts are zero.
|
|
||||||
*/
|
|
||||||
switch (shift) {
|
|
||||||
case 5:
|
|
||||||
if (++len <= *olen)
|
|
||||||
*out++ = (bits >> 32) & 0xff;
|
|
||||||
bits <<= 8;
|
|
||||||
case 15:
|
|
||||||
if (++len <= *olen)
|
|
||||||
*out++ = (bits >> 32) & 0xff;
|
|
||||||
bits <<= 8;
|
|
||||||
case 20:
|
|
||||||
if (++len <= *olen)
|
|
||||||
*out++ = (bits >> 32) & 0xff;
|
|
||||||
bits <<= 8;
|
|
||||||
case 30:
|
|
||||||
if (++len <= *olen)
|
|
||||||
*out++ = (bits >> 32) & 0xff;
|
|
||||||
bits <<= 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
/* consume remaining padding and whitespace */
|
|
||||||
for (; ilen && *in; --ilen, ++in) {
|
|
||||||
if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n')
|
|
||||||
continue;
|
|
||||||
else if (*in == '=' && shift)
|
|
||||||
shift -= 5;
|
|
||||||
else
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ilen)
|
|
||||||
goto bad;
|
|
||||||
*olen = len;
|
*olen = len;
|
||||||
if (len > *olen)
|
if (len > *olen) {
|
||||||
|
/* overflow */
|
||||||
|
errno = ENOSPC;
|
||||||
return (-1);
|
return (-1);
|
||||||
|
}
|
||||||
return (0);
|
return (0);
|
||||||
bad:
|
|
||||||
*olen = 0;
|
|
||||||
return (-1);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,13 +40,32 @@
|
||||||
|
|
||||||
#include <security/oath.h>
|
#include <security/oath.h>
|
||||||
|
|
||||||
static const char b64[] =
|
static const char b64enc[] =
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
"0123456789+/";
|
"0123456789+/";
|
||||||
|
|
||||||
|
static const uint8_t b64dec[256] = {
|
||||||
|
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3,
|
||||||
|
['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7,
|
||||||
|
['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11,
|
||||||
|
['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
|
||||||
|
['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
|
||||||
|
['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23,
|
||||||
|
['Y'] = 24, ['Z'] = 25, ['a'] = 26, ['b'] = 27,
|
||||||
|
['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31,
|
||||||
|
['g'] = 32, ['h'] = 33, ['i'] = 34, ['j'] = 35,
|
||||||
|
['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39,
|
||||||
|
['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43,
|
||||||
|
['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47,
|
||||||
|
['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51,
|
||||||
|
['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55,
|
||||||
|
['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
|
||||||
|
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode data in RFC 3548 base 64 representation. The target buffer must
|
* Encode data in RFC 4648 base 64 representation. The target buffer must
|
||||||
* have room for base64_enclen(len) characters and a terminating NUL.
|
* have room for base64_enclen(len) characters and a terminating NUL.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -64,10 +83,10 @@ base64_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||||
bits |= (uint32_t)in[2];
|
bits |= (uint32_t)in[2];
|
||||||
ilen -= 3;
|
ilen -= 3;
|
||||||
in += 3;
|
in += 3;
|
||||||
out[0] = b64[bits >> 18 & 0x3f];
|
out[0] = b64enc[bits >> 18 & 0x3f];
|
||||||
out[1] = b64[bits >> 12 & 0x3f];
|
out[1] = b64enc[bits >> 12 & 0x3f];
|
||||||
out[2] = b64[bits >> 6 & 0x3f];
|
out[2] = b64enc[bits >> 6 & 0x3f];
|
||||||
out[3] = b64[bits & 0x3f];
|
out[3] = b64enc[bits & 0x3f];
|
||||||
*olen += 4;
|
*olen += 4;
|
||||||
out += 4;
|
out += 4;
|
||||||
}
|
}
|
||||||
|
@ -79,9 +98,9 @@ base64_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||||
case 1:
|
case 1:
|
||||||
bits |= (uint32_t)in[0] << 16;
|
bits |= (uint32_t)in[0] << 16;
|
||||||
}
|
}
|
||||||
out[0] = b64[bits >> 18 & 0x3f];
|
out[0] = b64enc[bits >> 18 & 0x3f];
|
||||||
out[1] = b64[bits >> 12 & 0x3f];
|
out[1] = b64enc[bits >> 12 & 0x3f];
|
||||||
out[2] = ilen > 1 ? b64[bits >> 6 & 0x3f] : '=';
|
out[2] = ilen > 1 ? b64enc[bits >> 6 & 0x3f] : '=';
|
||||||
out[3] = '=';
|
out[3] = '=';
|
||||||
*olen += 4;
|
*olen += 4;
|
||||||
out += 4;
|
out += 4;
|
||||||
|
@ -92,10 +111,15 @@ base64_enc(const uint8_t *in, size_t ilen, char *out, size_t *olen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode data in RFC 2548 base 64 representation, stopping at the
|
* Decode data in RFC 4648 base 64 representation, stopping at the
|
||||||
* terminating NUL, the first invalid (non-base64, non-whitespace)
|
* terminating NUL, the first invalid (non-base64, non-whitespace)
|
||||||
* character or after len characters, whichever comes first.
|
* character or after len characters, whichever comes first.
|
||||||
*
|
*
|
||||||
|
* Padding is handled sloppily: any padding character following the data
|
||||||
|
* is silently consumed. This not only simplifies the code but ensures
|
||||||
|
* compatibility with implementations which do not emit or understand
|
||||||
|
* padding.
|
||||||
|
*
|
||||||
* The olen argument is used by the caller to pass the size of the buffer
|
* The olen argument is used by the caller to pass the size of the buffer
|
||||||
* and by base64_dec() to return the amount of data successfully decoded.
|
* and by base64_dec() to return the amount of data successfully decoded.
|
||||||
* If the buffer is too small, base64_dec() discards the excess data, but
|
* If the buffer is too small, base64_dec() discards the excess data, but
|
||||||
|
@ -105,83 +129,40 @@ int
|
||||||
base64_dec(const char *in, size_t ilen, uint8_t *out, size_t *olen)
|
base64_dec(const char *in, size_t ilen, uint8_t *out, size_t *olen)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
uint32_t bits;
|
int bits, shift, padding;
|
||||||
int shift;
|
|
||||||
|
|
||||||
for (len = 0, bits = 0, shift = 24; ilen && *in; --ilen, ++in) {
|
for (bits = shift = padding = len = 0; ilen && *in; --ilen, ++in) {
|
||||||
if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n') {
|
if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n' ||
|
||||||
|
(padding && *in == '=')) {
|
||||||
|
/* consume */
|
||||||
continue;
|
continue;
|
||||||
} else if (*in >= 'A' && *in <= 'Z') {
|
} else if (!padding && b64dec[(int)*in]) {
|
||||||
shift -= 6;
|
/* shift into accumulator */
|
||||||
bits |= (uint32_t)(*in - 'A') << shift;
|
shift += 6;
|
||||||
} else if (*in >= 'a' && *in <= 'z') {
|
bits = bits << 6 | b64dec[(int)*in];
|
||||||
shift -= 6;
|
} else if (!padding && shift && *in == '=') {
|
||||||
bits |= (uint32_t)(*in - 'a' + 26) << shift;
|
/* final byte */
|
||||||
} else if (*in >= '0' && *in <= '9') {
|
shift = 0;
|
||||||
shift -= 6;
|
padding = 1;
|
||||||
bits |= (uint32_t)(*in - '0' + 52) << shift;
|
|
||||||
} else if (*in == '+') {
|
|
||||||
shift -= 6;
|
|
||||||
bits |= (uint32_t)62 << shift;
|
|
||||||
} else if (*in == '/') {
|
|
||||||
shift -= 6;
|
|
||||||
bits |= (uint32_t)63 << shift;
|
|
||||||
} else if (*in == '=') {
|
|
||||||
/* handled below */
|
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
goto bad;
|
/* error */
|
||||||
|
*olen = 0;
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
}
|
}
|
||||||
if (shift == 0) {
|
if (shift >= 8) {
|
||||||
if ((len += 3) <= *olen) {
|
/* output accumulated byte */
|
||||||
*out++ = (bits >> 16) & 0xff;
|
shift -= 8;
|
||||||
*out++ = (bits >> 8) & 0xff;
|
if (len++ < *olen)
|
||||||
*out++ = bits & 0xff;
|
*out++ = (bits >> shift) & 0xff;
|
||||||
}
|
|
||||||
bits = 0;
|
|
||||||
shift = 24;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ilen && *in == '=' && (shift == 12 || shift == 6)) {
|
/* report decoded length */
|
||||||
/*
|
|
||||||
* Padding:
|
|
||||||
*
|
|
||||||
* 00 8 AA== 12
|
|
||||||
* 00 00 16 AAA= 6
|
|
||||||
*
|
|
||||||
* XXX We should check that the last few bits before the
|
|
||||||
* padding starts are zero.
|
|
||||||
*/
|
|
||||||
switch (shift) {
|
|
||||||
case 6:
|
|
||||||
if (++len <= *olen)
|
|
||||||
*out++ = (bits >> 16) & 0xff;
|
|
||||||
bits <<= 8;
|
|
||||||
case 12:
|
|
||||||
if (++len <= *olen)
|
|
||||||
*out++ = (bits >> 16) & 0xff;
|
|
||||||
bits <<= 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
/* consume remaining padding and whitespace */
|
|
||||||
for (; ilen && *in; --ilen, ++in) {
|
|
||||||
if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n')
|
|
||||||
continue;
|
|
||||||
else if (*in == '=' && shift)
|
|
||||||
shift -= 6;
|
|
||||||
else
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ilen)
|
|
||||||
goto bad;
|
|
||||||
*olen = len;
|
*olen = len;
|
||||||
if (len > *olen)
|
if (len > *olen) {
|
||||||
|
/* overflow */
|
||||||
|
errno = ENOSPC;
|
||||||
return (-1);
|
return (-1);
|
||||||
|
}
|
||||||
return (0);
|
return (0);
|
||||||
bad:
|
|
||||||
*olen = 0;
|
|
||||||
return (-1);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue