initial GNU TLS import - this should reduce in size considerable

This commit is contained in:
lv-426 committed 2008-06-22 18:20:35 +00:00
1 parent 97c026da05
commit a0339d2458
257 files changed
+106595 -23

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
SUBDIRS = .
AM_CPPFLAGS = -std=c99 \
-I$(GCRYPT_CPPFLAGS)
# gc-gnulib.c
noinst_LTLIBRARIES = liblgl.la
liblgl_la_LDFLAGS = -lgcrypt
# liblgl_la_LIBADD = ./gc-libgcrypt.lo
liblgl_la_SOURCES = \
asnprintf.c \
sha1.c \
gc-libgcrypt.c \
time_r.c \
rijndael-api-fst.c \
gc-pbkdf2-sha1.c \
read-file.c \
rijndael-alg-fst.c \
hmac-md5.c \
hmac-sha1.c \
realloc.c \
memmem.c \
memmove.c \
memxor.c \
printf-args.c \
strverscmp.c \
snprintf.c \
asprintf.c \
vasprintf.c \
vasnprintf.c \
md5.c \
printf-parse.c \
des.c
+35
View File
@@ -0,0 +1,35 @@
/* Formatted output to strings.
Copyright (C) 1999, 2002, 2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <config.h>
/* Specification. */
#include "vasnprintf.h"
#include <stdarg.h>
char *
asnprintf (char *resultbuf, size_t * lengthp, const char *format, ...)
{
va_list args;
char *result;
va_start (args, format);
result = vasnprintf (resultbuf, lengthp, format, args);
va_end (args);
return result;
}
+39
View File
@@ -0,0 +1,39 @@
/* Formatted output to strings.
Copyright (C) 1999, 2002, 2006-2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <config.h>
/* Specification. */
#ifdef IN_LIBASPRINTF
# include "vasprintf.h"
#else
# include <stdio.h>
#endif
#include <stdarg.h>
int
asprintf (char **resultp, const char *format, ...)
{
va_list args;
int result;
va_start (args, format);
result = vasprintf (resultp, format, args);
va_end (args);
return result;
}
+662
View File
@@ -0,0 +1,662 @@
/* des.c --- DES and Triple-DES encryption/decryption Algorithm
* Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007
* Free Software Foundation, Inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Adapted for gnulib by Simon Josefsson, based on Libgcrypt. */
/*
* For a description of triple encryption, see:
* Bruce Schneier: Applied Cryptography. Second Edition.
* John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
* This implementation is according to the definition of DES in FIPS
* PUB 46-2 from December 1993.
*
* Written by Michael Roth <mroth@nessie.de>, September 1998
*/
/*
* U S A G E
* ===========
*
* For DES or Triple-DES encryption/decryption you must initialize a proper
* encryption context with a key.
*
* A DES key is 64bit wide but only 56bits of the key are used. The remaining
* bits are parity bits and they will _not_ checked in this implementation, but
* simply ignored.
*
* For Triple-DES you could use either two 64bit keys or three 64bit keys.
* The parity bits will _not_ checked, too.
*
* After initializing a context with a key you could use this context to
* encrypt or decrypt data in 64bit blocks in Electronic Codebook Mode.
*
* DES Example
* -----------
* unsigned char key[8];
* unsigned char plaintext[8];
* unsigned char ciphertext[8];
* unsigned char recoverd[8];
* gl_des_ctx context;
*
* // Fill 'key' and 'plaintext' with some data
* ....
*
* // Set up the DES encryption context
* gl_des_setkey(&context, key);
*
* // Encrypt the plaintext
* des_ecb_encrypt(&context, plaintext, ciphertext);
*
* // To recover the orginal plaintext from ciphertext use:
* des_ecb_decrypt(&context, ciphertext, recoverd);
*
*
* Triple-DES Example
* ------------------
* unsigned char key1[8];
* unsigned char key2[8];
* unsigned char key3[8];
* unsigned char plaintext[8];
* unsigned char ciphertext[8];
* unsigned char recoverd[8];
* gl_3des_ctx context;
*
* // If you would like to use two 64bit keys, fill 'key1' and'key2'
* // then setup the encryption context:
* gl_3des_set2keys(&context, key1, key2);
*
* // To use three 64bit keys with Triple-DES use:
* gl_3des_set3keys(&context, key1, key2, key3);
*
* // Encrypting plaintext with Triple-DES
* gl_3des_ecb_encrypt(&context, plaintext, ciphertext);
*
* // Decrypting ciphertext to recover the plaintext with Triple-DES
* gl_3des_ecb_decrypt(&context, ciphertext, recoverd);
*/
#include <config.h>
#include "des.h"
#include <stdio.h>
#include <string.h> /* memcpy, memcmp */
/*
* The s-box values are permuted according to the 'primitive function P'
* and are rotated one bit to the left.
*/
static const uint32_t sbox1[64] = {
0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404,
0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400,
0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400,
0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404,
0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404,
0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000,
0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000,
0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404,
0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404,
0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000,
0x00010004, 0x00010400, 0x00000000, 0x01010004
};
static const uint32_t sbox2[64] = {
0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020,
0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000,
0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020,
0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000,
0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000,
0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000,
0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000,
0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000,
0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020,
0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020,
0x80000000, 0x80100020, 0x80108020, 0x00108000
};
static const uint32_t sbox3[64] = {
0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000,
0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000,
0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008,
0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208,
0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208,
0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208,
0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008,
0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008,
0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208,
0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000,
0x00020208, 0x00000008, 0x08020008, 0x00020200
};
static const uint32_t sbox4[64] = {
0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081,
0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000,
0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080,
0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080,
0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080,
0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001,
0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002000, 0x00802080
};
static const uint32_t sbox5[64] = {
0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100,
0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100,
0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000,
0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100,
0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000,
0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000,
0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000,
0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000,
0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000,
0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000,
0x00000000, 0x40080000, 0x02080100, 0x40000100
};
static const uint32_t sbox6[64] = {
0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010,
0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010,
0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010,
0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010,
0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000,
0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000,
0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000,
0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000,
0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000,
0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000,
0x20404000, 0x20000000, 0x00400010, 0x20004010
};
static const uint32_t sbox7[64] = {
0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802,
0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002,
0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802,
0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002,
0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002,
0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802,
0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000,
0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800,
0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000,
0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800,
0x04000002, 0x04000800, 0x00000800, 0x00200002
};
static const uint32_t sbox8[64] = {
0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040,
0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000,
0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040,
0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000,
0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000,
0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000,
0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040,
0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040,
0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000,
0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040,
0x00001040, 0x00040040, 0x10000000, 0x10041000
};
/*
* These two tables are part of the 'permuted choice 1' function.
* In this implementation several speed improvements are done.
*/
static const uint32_t leftkey_swap[16] = {
0x00000000, 0x00000001, 0x00000100, 0x00000101,
0x00010000, 0x00010001, 0x00010100, 0x00010101,
0x01000000, 0x01000001, 0x01000100, 0x01000101,
0x01010000, 0x01010001, 0x01010100, 0x01010101
};
static const uint32_t rightkey_swap[16] = {
0x00000000, 0x01000000, 0x00010000, 0x01010000,
0x00000100, 0x01000100, 0x00010100, 0x01010100,
0x00000001, 0x01000001, 0x00010001, 0x01010001,
0x00000101, 0x01000101, 0x00010101, 0x01010101,
};
/*
* Numbers of left shifts per round for encryption subkeys. To
* calculate the decryption subkeys we just reverse the ordering of
* the calculated encryption subkeys, so there is no need for a
* decryption rotate tab.
*/
static const unsigned char encrypt_rotate_tab[16] = {
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
/*
* Table with weak DES keys sorted in ascending order. In DES there
* are 64 known keys which are weak. They are weak because they
* produce only one, two or four different subkeys in the subkey
* scheduling process. The keys in this table have all their parity
* bits cleared.
*/
static const unsigned char weak_keys[64][8] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*w */
{0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e},
{0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0},
{0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe},
{0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e}, /*sw */
{0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00},
{0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe},
{0x00, 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0},
{0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0}, /*sw */
{0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe},
{0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00},
{0x00, 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e},
{0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe}, /*sw */
{0x00, 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0},
{0x00, 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e},
{0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00},
{0x1e, 0x00, 0x00, 0x1e, 0x0e, 0x00, 0x00, 0x0e},
{0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00}, /*sw */
{0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0, 0xfe},
{0x1e, 0x00, 0xfe, 0xe0, 0x0e, 0x00, 0xfe, 0xf0},
{0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00},
{0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e}, /*w */
{0x1e, 0x1e, 0xe0, 0xe0, 0x0e, 0x0e, 0xf0, 0xf0},
{0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe, 0xfe},
{0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00, 0xfe},
{0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0}, /*sw */
{0x1e, 0xe0, 0xe0, 0x1e, 0x0e, 0xf0, 0xf0, 0x0e},
{0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe, 0x00},
{0x1e, 0xfe, 0x00, 0xe0, 0x0e, 0xfe, 0x00, 0xf0},
{0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe}, /*sw */
{0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0, 0x00},
{0x1e, 0xfe, 0xfe, 0x1e, 0x0e, 0xfe, 0xfe, 0x0e},
{0xe0, 0x00, 0x00, 0xe0, 0xf0, 0x00, 0x00, 0xf0},
{0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e, 0xfe},
{0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00}, /*sw */
{0xe0, 0x00, 0xfe, 0x1e, 0xf0, 0x00, 0xfe, 0x0e},
{0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00, 0xfe},
{0xe0, 0x1e, 0x1e, 0xe0, 0xf0, 0x0e, 0x0e, 0xf0},
{0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e}, /*sw */
{0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe, 0x00},
{0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00},
{0xe0, 0xe0, 0x1e, 0x1e, 0xf0, 0xf0, 0x0e, 0x0e},
{0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0}, /*w */
{0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe, 0xfe},
{0xe0, 0xfe, 0x00, 0x1e, 0xf0, 0xfe, 0x00, 0x0e},
{0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e, 0x00},
{0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe}, /*sw */
{0xe0, 0xfe, 0xfe, 0xe0, 0xf0, 0xfe, 0xfe, 0xf0},
{0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe},
{0xfe, 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0},
{0xfe, 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e},
{0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00}, /*sw */
{0xfe, 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0},
{0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe},
{0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00},
{0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e}, /*sw */
{0xfe, 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e},
{0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00},
{0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe},
{0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0}, /*sw */
{0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00},
{0xfe, 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e},
{0xfe, 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0},
{0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe} /*w */
};
bool
gl_des_is_weak_key (const char *key)
{
char work[8];
int i, left, right, middle, cmp_result;
/* clear parity bits */
for (i = 0; i < 8; ++i)
work[i] = ((unsigned char) key[i]) & 0xfe;
/* binary search in the weak key table */
left = 0;
right = 63;
while (left <= right)
{
middle = (left + right) / 2;
if (!(cmp_result = memcmp (work, weak_keys[middle], 8)))
return -1;
if (cmp_result > 0)
left = middle + 1;
else
right = middle - 1;
}
return 0;
}
/*
* Macro to swap bits across two words.
*/
#define DO_PERMUTATION(a, temp, b, offset, mask) \
temp = ((a>>offset) ^ b) & mask; \
b ^= temp; \
a ^= temp<<offset;
/*
* This performs the 'initial permutation' of the data to be encrypted
* or decrypted. Additionally the resulting two words are rotated one bit
* to the left.
*/
#define INITIAL_PERMUTATION(left, temp, right) \
DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f) \
DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
right = (right << 1) | (right >> 31); \
temp = (left ^ right) & 0xaaaaaaaa; \
right ^= temp; \
left ^= temp; \
left = (left << 1) | (left >> 31);
/*
* The 'inverse initial permutation'.
*/
#define FINAL_PERMUTATION(left, temp, right) \
left = (left << 31) | (left >> 1); \
temp = (left ^ right) & 0xaaaaaaaa; \
left ^= temp; \
right ^= temp; \
right = (right << 31) | (right >> 1); \
DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)
/*
* A full DES round including 'expansion function', 'sbox substitution'
* and 'primitive function P' but without swapping the left and right word.
* Please note: The data in 'from' and 'to' is already rotated one bit to
* the left, done in the initial permutation.
*/
#define DES_ROUND(from, to, work, subkey) \
work = from ^ *subkey++; \
to ^= sbox8[ work & 0x3f ]; \
to ^= sbox6[ (work>>8) & 0x3f ]; \
to ^= sbox4[ (work>>16) & 0x3f ]; \
to ^= sbox2[ (work>>24) & 0x3f ]; \
work = ((from << 28) | (from >> 4)) ^ *subkey++; \
to ^= sbox7[ work & 0x3f ]; \
to ^= sbox5[ (work>>8) & 0x3f ]; \
to ^= sbox3[ (work>>16) & 0x3f ]; \
to ^= sbox1[ (work>>24) & 0x3f ];
/*
* Macros to convert 8 bytes from/to 32bit words.
*/
#define READ_64BIT_DATA(data, left, right) \
left = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \
right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
#define WRITE_64BIT_DATA(data, left, right) \
data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff; \
data[2] = (left >> 8) &0xff; data[3] = left &0xff; \
data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff; \
data[6] = (right >> 8) &0xff; data[7] = right &0xff;
/*
* des_key_schedule(): Calculate 16 subkeys pairs (even/odd) for
* 16 encryption rounds.
* To calculate subkeys for decryption the caller
* have to reorder the generated subkeys.
*
* rawkey: 8 Bytes of key data
* subkey: Array of at least 32 uint32_ts. Will be filled
* with calculated subkeys.
*
*/
static void
des_key_schedule (const char *_rawkey, uint32_t * subkey)
{
const unsigned char *rawkey = (const unsigned char *) _rawkey;
uint32_t left, right, work;
int round;
READ_64BIT_DATA (rawkey, left, right)
DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f)
DO_PERMUTATION (right, work, left, 0, 0x10101010)
left = ((leftkey_swap[(left >> 0) & 0xf] << 3)
| (leftkey_swap[(left >> 8) & 0xf] << 2)
| (leftkey_swap[(left >> 16) & 0xf] << 1)
| (leftkey_swap[(left >> 24) & 0xf])
| (leftkey_swap[(left >> 5) & 0xf] << 7)
| (leftkey_swap[(left >> 13) & 0xf] << 6)
| (leftkey_swap[(left >> 21) & 0xf] << 5)
| (leftkey_swap[(left >> 29) & 0xf] << 4));
left &= 0x0fffffff;
right = ((rightkey_swap[(right >> 1) & 0xf] << 3)
| (rightkey_swap[(right >> 9) & 0xf] << 2)
| (rightkey_swap[(right >> 17) & 0xf] << 1)
| (rightkey_swap[(right >> 25) & 0xf])
| (rightkey_swap[(right >> 4) & 0xf] << 7)
| (rightkey_swap[(right >> 12) & 0xf] << 6)
| (rightkey_swap[(right >> 20) & 0xf] << 5)
| (rightkey_swap[(right >> 28) & 0xf] << 4));
right &= 0x0fffffff;
for (round = 0; round < 16; ++round)
{
left = ((left << encrypt_rotate_tab[round])
| (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
right = ((right << encrypt_rotate_tab[round])
| (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
*subkey++ = (((left << 4) & 0x24000000)
| ((left << 28) & 0x10000000)
| ((left << 14) & 0x08000000)
| ((left << 18) & 0x02080000)
| ((left << 6) & 0x01000000)
| ((left << 9) & 0x00200000)
| ((left >> 1) & 0x00100000)
| ((left << 10) & 0x00040000)
| ((left << 2) & 0x00020000)
| ((left >> 10) & 0x00010000)
| ((right >> 13) & 0x00002000)
| ((right >> 4) & 0x00001000)
| ((right << 6) & 0x00000800)
| ((right >> 1) & 0x00000400)
| ((right >> 14) & 0x00000200)
| (right & 0x00000100)
| ((right >> 5) & 0x00000020)
| ((right >> 10) & 0x00000010)
| ((right >> 3) & 0x00000008)
| ((right >> 18) & 0x00000004)
| ((right >> 26) & 0x00000002)
| ((right >> 24) & 0x00000001));
*subkey++ = (((left << 15) & 0x20000000)
| ((left << 17) & 0x10000000)
| ((left << 10) & 0x08000000)
| ((left << 22) & 0x04000000)
| ((left >> 2) & 0x02000000)
| ((left << 1) & 0x01000000)
| ((left << 16) & 0x00200000)
| ((left << 11) & 0x00100000)
| ((left << 3) & 0x00080000)
| ((left >> 6) & 0x00040000)
| ((left << 15) & 0x00020000)
| ((left >> 4) & 0x00010000)
| ((right >> 2) & 0x00002000)
| ((right << 8) & 0x00001000)
| ((right >> 14) & 0x00000808)
| ((right >> 9) & 0x00000400)
| ((right) & 0x00000200)
| ((right << 7) & 0x00000100)
| ((right >> 7) & 0x00000020)
| ((right >> 3) & 0x00000011)
| ((right << 2) & 0x00000004)
| ((right >> 21) & 0x00000002));
}
}
void
gl_des_setkey (gl_des_ctx * ctx, const char *key)
{
int i;
des_key_schedule (key, ctx->encrypt_subkeys);
for (i = 0; i < 32; i += 2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30 - i];
ctx->decrypt_subkeys[i + 1] = ctx->encrypt_subkeys[31 - i];
}
}
bool
gl_des_makekey (gl_des_ctx * ctx, const char *key, size_t keylen)
{
if (keylen != 8)
return false;
gl_des_setkey (ctx, key);
return !gl_des_is_weak_key (key);
}
void
gl_des_ecb_crypt (gl_des_ctx * ctx, const char *_from, char *_to, int mode)
{
const unsigned char *from = (const unsigned char *) _from;
unsigned char *to = (unsigned char *) _to;
uint32_t left, right, work;
uint32_t *keys;
keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
READ_64BIT_DATA (from, left, right)
INITIAL_PERMUTATION (left, work, right)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
FINAL_PERMUTATION (right, work, left) WRITE_64BIT_DATA (to, right, left)}
void
gl_3des_set2keys (gl_3des_ctx * ctx, const char *key1, const char *key2)
{
int i;
des_key_schedule (key1, ctx->encrypt_subkeys);
des_key_schedule (key2, &(ctx->decrypt_subkeys[32]));
for (i = 0; i < 32; i += 2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30 - i];
ctx->decrypt_subkeys[i + 1] = ctx->encrypt_subkeys[31 - i];
ctx->encrypt_subkeys[i + 32] = ctx->decrypt_subkeys[62 - i];
ctx->encrypt_subkeys[i + 33] = ctx->decrypt_subkeys[63 - i];
ctx->encrypt_subkeys[i + 64] = ctx->encrypt_subkeys[i];
ctx->encrypt_subkeys[i + 65] = ctx->encrypt_subkeys[i + 1];
ctx->decrypt_subkeys[i + 64] = ctx->decrypt_subkeys[i];
ctx->decrypt_subkeys[i + 65] = ctx->decrypt_subkeys[i + 1];
}
}
void
gl_3des_set3keys (gl_3des_ctx * ctx, const char *key1,
const char *key2, const char *key3)
{
int i;
des_key_schedule (key1, ctx->encrypt_subkeys);
des_key_schedule (key2, &(ctx->decrypt_subkeys[32]));
des_key_schedule (key3, &(ctx->encrypt_subkeys[64]));
for (i = 0; i < 32; i += 2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[94 - i];
ctx->decrypt_subkeys[i + 1] = ctx->encrypt_subkeys[95 - i];
ctx->encrypt_subkeys[i + 32] = ctx->decrypt_subkeys[62 - i];
ctx->encrypt_subkeys[i + 33] = ctx->decrypt_subkeys[63 - i];
ctx->decrypt_subkeys[i + 64] = ctx->encrypt_subkeys[30 - i];
ctx->decrypt_subkeys[i + 65] = ctx->encrypt_subkeys[31 - i];
}
}
void
gl_3des_ecb_crypt (gl_3des_ctx * ctx, const char *_from, char *_to, int mode)
{
const unsigned char *from = (const unsigned char *) _from;
unsigned char *to = (unsigned char *) _to;
uint32_t left, right, work;
uint32_t *keys;
keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
READ_64BIT_DATA (from, left, right)
INITIAL_PERMUTATION (left, work, right)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
FINAL_PERMUTATION (right, work, left) WRITE_64BIT_DATA (to, right, left)}
bool
gl_3des_makekey (gl_3des_ctx * ctx, const char *key, size_t keylen)
{
if (keylen != 24)
return false;
gl_3des_set3keys (ctx, key, key + 8, key + 16);
return !(gl_des_is_weak_key (key)
|| gl_des_is_weak_key (key + 8) || gl_des_is_weak_key (key + 16));
}
+121
View File
@@ -0,0 +1,121 @@
/* des.h --- DES cipher implementation.
* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Adapted for gnulib by Simon Josefsson, based on Libgcrypt. */
#ifndef DES_H
# define DES_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/*
* Encryption/Decryption context of DES
*/
typedef struct
{
uint32_t encrypt_subkeys[32];
uint32_t decrypt_subkeys[32];
} gl_des_ctx;
/*
* Encryption/Decryption context of Triple-DES
*/
typedef struct
{
uint32_t encrypt_subkeys[96];
uint32_t decrypt_subkeys[96];
} gl_3des_ctx;
/* Check whether the 8 byte key is weak. Does not check the parity
* bits of the key but simple ignore them. */
extern bool
gl_des_is_weak_key (const char * key);
/*
* DES
* ---
*/
/* Fill a DES context CTX with subkeys calculated from 64bit KEY.
* Does not check parity bits, but simply ignore them. Does not check
* for weak keys. */
extern void
gl_des_setkey (gl_des_ctx *ctx, const char * key);
/* Fill a DES context CTX with subkeys calculated from 64bit KEY, with
* weak key checking. Does not check parity bits, but simply ignore
* them. */
extern bool
gl_des_makekey (gl_des_ctx *ctx, const char * key, size_t keylen);
/* Electronic Codebook Mode DES encryption/decryption of data
* according to 'mode'. */
extern void
gl_des_ecb_crypt (gl_des_ctx *ctx, const char * from, char * to, int mode);
#define gl_des_ecb_encrypt(ctx, from, to) gl_des_ecb_crypt(ctx, from, to, 0)
#define gl_des_ecb_decrypt(ctx, from, to) gl_des_ecb_crypt(ctx, from, to, 1)
/* Triple-DES
* ----------
*/
/* Fill a Triple-DES context CTX with subkeys calculated from two
* 64bit keys in KEY1 and KEY2. Does not check the parity bits of the
* keys, but simply ignore them. Does not check for weak keys. */
extern void
gl_3des_set2keys (gl_3des_ctx *ctx,
const char * key1,
const char * key2);
/*
* Fill a Triple-DES context CTX with subkeys calculated from three
* 64bit keys in KEY1, KEY2 and KEY3. Does not check the parity bits
* of the keys, but simply ignore them. Does not check for weak
* keys. */
extern void
gl_3des_set3keys (gl_3des_ctx *ctx,
const char * key1,
const char * key2,
const char * key3);
/* Fill a Triple-DES context CTX with subkeys calculated from three
* concatenated 64bit keys in KEY, with weak key checking. Does not
* check the parity bits of the keys, but simply ignore them. */
extern bool
gl_3des_makekey (gl_3des_ctx *ctx,
const char * key,
size_t keylen);
/* Electronic Codebook Mode Triple-DES encryption/decryption of data
* according to 'mode'. Sometimes this mode is named 'EDE' mode
* (Encryption-Decryption-Encryption). */
extern void
gl_3des_ecb_crypt (gl_3des_ctx *ctx,
const char * from,
char * to,
int mode);
#define gl_3des_ecb_encrypt(ctx, from, to) gl_3des_ecb_crypt(ctx,from,to,0)
#define gl_3des_ecb_decrypt(ctx, from, to) gl_3des_ecb_crypt(ctx,from,to,1)
#endif /* DES_H */
+148
View File
@@ -0,0 +1,148 @@
/* Supplemental information about the floating-point formats.
Copyright (C) 2007 Free Software Foundation, Inc.
Written by Bruno Haible <bruno@clisp.org>, 2007.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _FLOATPLUS_H
#define _FLOATPLUS_H
#include <float.h>
#include <limits.h>
/* Number of bits in the mantissa of a floating-point number, including the
"hidden bit". */
#if FLT_RADIX == 2
# define FLT_MANT_BIT FLT_MANT_DIG
# define DBL_MANT_BIT DBL_MANT_DIG
# define LDBL_MANT_BIT LDBL_MANT_DIG
#elif FLT_RADIX == 4
# define FLT_MANT_BIT (FLT_MANT_DIG * 2)
# define DBL_MANT_BIT (DBL_MANT_DIG * 2)
# define LDBL_MANT_BIT (LDBL_MANT_DIG * 2)
#elif FLT_RADIX == 16
# define FLT_MANT_BIT (FLT_MANT_DIG * 4)
# define DBL_MANT_BIT (DBL_MANT_DIG * 4)
# define LDBL_MANT_BIT (LDBL_MANT_DIG * 4)
#endif
/* Bit mask that can be used to mask the exponent, as an unsigned number. */
#define FLT_EXP_MASK ((FLT_MAX_EXP - FLT_MIN_EXP) | 7)
#define DBL_EXP_MASK ((DBL_MAX_EXP - DBL_MIN_EXP) | 7)
#define LDBL_EXP_MASK ((LDBL_MAX_EXP - LDBL_MIN_EXP) | 7)
/* Number of bits used for the exponent of a floating-point number, including
the exponent's sign. */
#define FLT_EXP_BIT \
(FLT_EXP_MASK < 0x100 ? 8 : \
FLT_EXP_MASK < 0x200 ? 9 : \
FLT_EXP_MASK < 0x400 ? 10 : \
FLT_EXP_MASK < 0x800 ? 11 : \
FLT_EXP_MASK < 0x1000 ? 12 : \
FLT_EXP_MASK < 0x2000 ? 13 : \
FLT_EXP_MASK < 0x4000 ? 14 : \
FLT_EXP_MASK < 0x8000 ? 15 : \
FLT_EXP_MASK < 0x10000 ? 16 : \
FLT_EXP_MASK < 0x20000 ? 17 : \
FLT_EXP_MASK < 0x40000 ? 18 : \
FLT_EXP_MASK < 0x80000 ? 19 : \
FLT_EXP_MASK < 0x100000 ? 20 : \
FLT_EXP_MASK < 0x200000 ? 21 : \
FLT_EXP_MASK < 0x400000 ? 22 : \
FLT_EXP_MASK < 0x800000 ? 23 : \
FLT_EXP_MASK < 0x1000000 ? 24 : \
FLT_EXP_MASK < 0x2000000 ? 25 : \
FLT_EXP_MASK < 0x4000000 ? 26 : \
FLT_EXP_MASK < 0x8000000 ? 27 : \
FLT_EXP_MASK < 0x10000000 ? 28 : \
FLT_EXP_MASK < 0x20000000 ? 29 : \
FLT_EXP_MASK < 0x40000000 ? 30 : \
FLT_EXP_MASK <= 0x7fffffff ? 31 : \
32)
#define DBL_EXP_BIT \
(DBL_EXP_MASK < 0x100 ? 8 : \
DBL_EXP_MASK < 0x200 ? 9 : \
DBL_EXP_MASK < 0x400 ? 10 : \
DBL_EXP_MASK < 0x800 ? 11 : \
DBL_EXP_MASK < 0x1000 ? 12 : \
DBL_EXP_MASK < 0x2000 ? 13 : \
DBL_EXP_MASK < 0x4000 ? 14 : \
DBL_EXP_MASK < 0x8000 ? 15 : \
DBL_EXP_MASK < 0x10000 ? 16 : \
DBL_EXP_MASK < 0x20000 ? 17 : \
DBL_EXP_MASK < 0x40000 ? 18 : \
DBL_EXP_MASK < 0x80000 ? 19 : \
DBL_EXP_MASK < 0x100000 ? 20 : \
DBL_EXP_MASK < 0x200000 ? 21 : \
DBL_EXP_MASK < 0x400000 ? 22 : \
DBL_EXP_MASK < 0x800000 ? 23 : \
DBL_EXP_MASK < 0x1000000 ? 24 : \
DBL_EXP_MASK < 0x2000000 ? 25 : \
DBL_EXP_MASK < 0x4000000 ? 26 : \
DBL_EXP_MASK < 0x8000000 ? 27 : \
DBL_EXP_MASK < 0x10000000 ? 28 : \
DBL_EXP_MASK < 0x20000000 ? 29 : \
DBL_EXP_MASK < 0x40000000 ? 30 : \
DBL_EXP_MASK <= 0x7fffffff ? 31 : \
32)
#define LDBL_EXP_BIT \
(LDBL_EXP_MASK < 0x100 ? 8 : \
LDBL_EXP_MASK < 0x200 ? 9 : \
LDBL_EXP_MASK < 0x400 ? 10 : \
LDBL_EXP_MASK < 0x800 ? 11 : \
LDBL_EXP_MASK < 0x1000 ? 12 : \
LDBL_EXP_MASK < 0x2000 ? 13 : \
LDBL_EXP_MASK < 0x4000 ? 14 : \
LDBL_EXP_MASK < 0x8000 ? 15 : \
LDBL_EXP_MASK < 0x10000 ? 16 : \
LDBL_EXP_MASK < 0x20000 ? 17 : \
LDBL_EXP_MASK < 0x40000 ? 18 : \
LDBL_EXP_MASK < 0x80000 ? 19 : \
LDBL_EXP_MASK < 0x100000 ? 20 : \
LDBL_EXP_MASK < 0x200000 ? 21 : \
LDBL_EXP_MASK < 0x400000 ? 22 : \
LDBL_EXP_MASK < 0x800000 ? 23 : \
LDBL_EXP_MASK < 0x1000000 ? 24 : \
LDBL_EXP_MASK < 0x2000000 ? 25 : \
LDBL_EXP_MASK < 0x4000000 ? 26 : \
LDBL_EXP_MASK < 0x8000000 ? 27 : \
LDBL_EXP_MASK < 0x10000000 ? 28 : \
LDBL_EXP_MASK < 0x20000000 ? 29 : \
LDBL_EXP_MASK < 0x40000000 ? 30 : \
LDBL_EXP_MASK <= 0x7fffffff ? 31 : \
32)
/* Number of bits used for a floating-point number: the mantissa (not
counting the "hidden bit", since it may or may not be explicit), the
exponent, and the sign. */
#define FLT_TOTAL_BIT ((FLT_MANT_BIT - 1) + FLT_EXP_BIT + 1)
#define DBL_TOTAL_BIT ((DBL_MANT_BIT - 1) + DBL_EXP_BIT + 1)
#define LDBL_TOTAL_BIT ((LDBL_MANT_BIT - 1) + LDBL_EXP_BIT + 1)
/* Number of bytes used for a floating-point number.
This can be smaller than the 'sizeof'. For example, on i386 systems,
'long double' most often have LDBL_MANT_BIT = 64, LDBL_EXP_BIT = 16, hence
LDBL_TOTAL_BIT = 80 bits, i.e. 10 bytes of consecutive memory, but
sizeof (long double) = 12 or = 16. */
#define SIZEOF_FLT ((FLT_TOTAL_BIT + CHAR_BIT - 1) / CHAR_BIT)
#define SIZEOF_DBL ((DBL_TOTAL_BIT + CHAR_BIT - 1) / CHAR_BIT)
#define SIZEOF_LDBL ((LDBL_TOTAL_BIT + CHAR_BIT - 1) / CHAR_BIT)
/* Verify that SIZEOF_FLT <= sizeof (float) etc. */
typedef int verify_sizeof_flt[2 * (SIZEOF_FLT <= sizeof (float)) - 1];
typedef int verify_sizeof_dbl[2 * (SIZEOF_DBL <= sizeof (double)) - 1];
typedef int verify_sizeof_ldbl[2 * (SIZEOF_LDBL <= sizeof (long double)) - 1];
#endif /* _FLOATPLUS_H */
+791
View File
@@ -0,0 +1,791 @@
/* gc-gnulib.c --- Common gnulib internal crypto interface functions
* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Simon Josefsson
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Note: This file is only built if GC uses internal functions. */
#include <config.h>
/* Get prototype. */
#include "gc.h"
#include <stdlib.h>
#include <string.h>
/* For randomize. */
#ifdef GNULIB_GC_RANDOM
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <errno.h>
#endif
/* Hashes. */
#ifdef GNULIB_GC_MD5
# include "md5.h"
#endif
#ifdef GNULIB_GC_SHA1
# include "sha1.h"
#endif
#if defined(GNULIB_GC_HMAC_MD5) || defined(GNULIB_GC_HMAC_SHA1)
# include "hmac.h"
#endif
/* Ciphers. */
#ifdef GNULIB_GC_ARCFOUR
# include "arcfour.h"
#endif
#ifdef GNULIB_GC_ARCTWO
# include "arctwo.h"
#endif
#ifdef GNULIB_GC_DES
# include "des.h"
#endif
#ifdef GNULIB_GC_RIJNDAEL
# include "rijndael-api-fst.h"
#endif
/* The results of open() in this file are not used with fchdir,
therefore save some unnecessary work in fchdir.c. */
#undef open
#undef close
Gc_rc gc_init(void)
{
return GC_OK;
}
void gc_done(void)
{
return;
}
#ifdef GNULIB_GC_RANDOM
/* Randomness. */
static Gc_rc
randomize (int level, char *data, size_t datalen)
{
int fd;
const char *device;
size_t len = 0;
int rc;
switch (level)
{
case 0:
device = NAME_OF_NONCE_DEVICE;
break;
case 1:
device = NAME_OF_PSEUDO_RANDOM_DEVICE;
break;
default:
device = NAME_OF_RANDOM_DEVICE;
break;
}
if (strcmp (device, "no") == 0)
return GC_RANDOM_ERROR;
fd = open (device, O_RDONLY);
if (fd < 0)
return GC_RANDOM_ERROR;
do
{
ssize_t tmp;
tmp = read (fd, data, datalen);
if (tmp < 0)
{
int save_errno = errno;
close (fd);
errno = save_errno;
return GC_RANDOM_ERROR;
}
len += tmp;
}
while (len < datalen);
rc = close (fd);
if (rc < 0)
return GC_RANDOM_ERROR;
return GC_OK;
}
Gc_rc
gc_nonce (char *data, size_t datalen)
{
return randomize (0, data, datalen);
}
Gc_rc
gc_pseudo_random (char *data, size_t datalen)
{
return randomize (1, data, datalen);
}
Gc_rc
gc_random (char *data, size_t datalen)
{
return randomize (2, data, datalen);
}
#endif
/* Memory allocation. */
void gc_set_allocators(gc_malloc_t func_malloc,
gc_malloc_t secure_malloc,
gc_secure_check_t secure_check,
gc_realloc_t func_realloc,
gc_free_t func_free)
{
return;
}
/* Ciphers. */
typedef struct _gc_cipher_ctx
{
Gc_cipher alg;
Gc_cipher_mode mode;
#ifdef GNULIB_GC_ARCTWO
arctwo_context arctwoContext;
char arctwoIV[ARCTWO_BLOCK_SIZE];
#endif
#ifdef GNULIB_GC_ARCFOUR
arcfour_context arcfourContext;
#endif
#ifdef GNULIB_GC_DES
gl_des_ctx desContext;
#endif
#ifdef GNULIB_GC_RIJNDAEL
rijndaelKeyInstance aesEncKey;
rijndaelKeyInstance aesDecKey;
rijndaelCipherInstance aesContext;
#endif
} _gc_cipher_ctx;
Gc_rc gc_cipher_open(Gc_cipher alg,
Gc_cipher_mode mode,
gc_cipher_handle * outhandle)
{
_gc_cipher_ctx *ctx;
Gc_rc rc = GC_OK;
ctx = calloc(sizeof (*ctx), 1);
if (!ctx)
return GC_MALLOC_ERROR;
ctx->alg = alg;
ctx->mode = mode;
switch (alg)
{
#ifdef GNULIB_GC_ARCTWO
case GC_ARCTWO40:
switch (mode)
{
case GC_ECB:
case GC_CBC:
break;
default:
rc = GC_INVALID_CIPHER;
}
break;
#endif
#ifdef GNULIB_GC_ARCFOUR
case GC_ARCFOUR128:
case GC_ARCFOUR40:
switch (mode)
{
case GC_STREAM:
break;
default:
rc = GC_INVALID_CIPHER;
}
break;
#endif
#ifdef GNULIB_GC_DES
case GC_DES:
switch (mode)
{
case GC_ECB:
break;
default:
rc = GC_INVALID_CIPHER;
}
break;
#endif
#ifdef GNULIB_GC_RIJNDAEL
case GC_AES128:
case GC_AES192:
case GC_AES256:
switch (mode)
{
case GC_ECB:
case GC_CBC:
break;
default:
rc = GC_INVALID_CIPHER;
}
break;
#endif
default:
rc = GC_INVALID_CIPHER;
}
if (rc == GC_OK)
*outhandle = ctx;
else
free(ctx);
return rc;
}
Gc_rc gc_cipher_setkey(gc_cipher_handle handle,
size_t keylen,
const char *key)
{
_gc_cipher_ctx *ctx = handle;
switch (ctx->alg)
{
#ifdef GNULIB_GC_ARCTWO
case GC_ARCTWO40:
arctwo_setkey (&ctx->arctwoContext, keylen, key);
break;
#endif
#ifdef GNULIB_GC_ARCFOUR
case GC_ARCFOUR128:
case GC_ARCFOUR40:
arcfour_setkey (&ctx->arcfourContext, key, keylen);
break;
#endif
#ifdef GNULIB_GC_DES
case GC_DES:
if (keylen != 8)
return GC_INVALID_CIPHER;
gl_des_setkey (&ctx->desContext, key);
break;
#endif
#ifdef GNULIB_GC_RIJNDAEL
case GC_AES128:
case GC_AES192:
case GC_AES256:
{
rijndael_rc rc;
size_t i;
char keyMaterial[RIJNDAEL_MAX_KEY_SIZE + 1];
for (i = 0; i < keylen; i++)
sprintf (&keyMaterial[2 * i], "%02x", key[i] & 0xFF);
rc = rijndaelMakeKey (&ctx->aesEncKey, RIJNDAEL_DIR_ENCRYPT,
keylen * 8, keyMaterial);
if (rc < 0)
return GC_INVALID_CIPHER;
rc = rijndaelMakeKey (&ctx->aesDecKey, RIJNDAEL_DIR_DECRYPT,
keylen * 8, keyMaterial);
if (rc < 0)
return GC_INVALID_CIPHER;
rc = rijndaelCipherInit (&ctx->aesContext, RIJNDAEL_MODE_ECB, NULL);
if (rc < 0)
return GC_INVALID_CIPHER;
}
break;
#endif
default:
return GC_INVALID_CIPHER;
}
return GC_OK;
}
Gc_rc gc_cipher_setiv(gc_cipher_handle handle,
size_t ivlen,
const char *iv)
{
_gc_cipher_ctx *ctx = handle;
switch (ctx->alg)
{
#ifdef GNULIB_GC_ARCTWO
case GC_ARCTWO40:
if (ivlen != ARCTWO_BLOCK_SIZE)
return GC_INVALID_CIPHER;
memcpy (ctx->arctwoIV, iv, ivlen);
break;
#endif
#ifdef GNULIB_GC_RIJNDAEL
case GC_AES128:
case GC_AES192:
case GC_AES256:
switch (ctx->mode)
{
case GC_ECB:
/* Doesn't use IV. */
break;
case GC_CBC:
{
rijndael_rc rc;
size_t i;
char ivMaterial[2 * RIJNDAEL_MAX_IV_SIZE + 1];
for (i = 0; i < ivlen; i++)
sprintf (&ivMaterial[2 * i], "%02x", iv[i] & 0xFF);
rc = rijndaelCipherInit (&ctx->aesContext, RIJNDAEL_MODE_CBC,
ivMaterial);
if (rc < 0)
return GC_INVALID_CIPHER;
}
break;
default:
return GC_INVALID_CIPHER;
}
break;
#endif
default:
return GC_INVALID_CIPHER;
}
return GC_OK;
}
Gc_rc gc_cipher_encrypt_inline(gc_cipher_handle handle,
size_t len,
char *data)
{
_gc_cipher_ctx *ctx = handle;
switch (ctx->alg)
{
#ifdef GNULIB_GC_ARCTWO
case GC_ARCTWO40:
switch (ctx->mode)
{
case GC_ECB:
arctwo_encrypt (&ctx->arctwoContext, data, data, len);
break;
case GC_CBC:
for (; len >= ARCTWO_BLOCK_SIZE; len -= ARCTWO_BLOCK_SIZE,
data += ARCTWO_BLOCK_SIZE)
{
size_t i;
for (i = 0; i < ARCTWO_BLOCK_SIZE; i++)
data[i] ^= ctx->arctwoIV[i];
arctwo_encrypt (&ctx->arctwoContext, data, data,
ARCTWO_BLOCK_SIZE);
memcpy (ctx->arctwoIV, data, ARCTWO_BLOCK_SIZE);
}
break;
default:
return GC_INVALID_CIPHER;
}
break;
#endif
#ifdef GNULIB_GC_ARCFOUR
case GC_ARCFOUR128:
case GC_ARCFOUR40:
arcfour_stream (&ctx->arcfourContext, data, data, len);
break;
#endif
#ifdef GNULIB_GC_DES
case GC_DES:
for (; len >= 8; len -= 8, data += 8)
gl_des_ecb_encrypt (&ctx->desContext, data, data);
break;
#endif
#ifdef GNULIB_GC_RIJNDAEL
case GC_AES128:
case GC_AES192:
case GC_AES256:
{
int nblocks;
nblocks = rijndaelBlockEncrypt (&ctx->aesContext, &ctx->aesEncKey,
data, 8 * len, data);
if (nblocks < 0)
return GC_INVALID_CIPHER;
}
break;
#endif
default:
return GC_INVALID_CIPHER;
}
return GC_OK;
}
Gc_rc gc_cipher_decrypt_inline(gc_cipher_handle handle,
size_t len,
char *data)
{
_gc_cipher_ctx *ctx = handle;
switch (ctx->alg)
{
#ifdef GNULIB_GC_ARCTWO
case GC_ARCTWO40:
switch (ctx->mode)
{
case GC_ECB:
arctwo_decrypt (&ctx->arctwoContext, data, data, len);
break;
case GC_CBC:
for (; len >= ARCTWO_BLOCK_SIZE; len -= ARCTWO_BLOCK_SIZE,
data += ARCTWO_BLOCK_SIZE)
{
char tmpIV[ARCTWO_BLOCK_SIZE];
size_t i;
memcpy (tmpIV, data, ARCTWO_BLOCK_SIZE);
arctwo_decrypt (&ctx->arctwoContext, data, data,
ARCTWO_BLOCK_SIZE);
for (i = 0; i < ARCTWO_BLOCK_SIZE; i++)
data[i] ^= ctx->arctwoIV[i];
memcpy (ctx->arctwoIV, tmpIV, ARCTWO_BLOCK_SIZE);
}
break;
default:
return GC_INVALID_CIPHER;
}
break;
#endif
#ifdef GNULIB_GC_ARCFOUR
case GC_ARCFOUR128:
case GC_ARCFOUR40:
arcfour_stream (&ctx->arcfourContext, data, data, len);
break;
#endif
#ifdef GNULIB_GC_DES
case GC_DES:
for (; len >= 8; len -= 8, data += 8)
gl_des_ecb_decrypt (&ctx->desContext, data, data);
break;
#endif
#ifdef GNULIB_GC_RIJNDAEL
case GC_AES128:
case GC_AES192:
case GC_AES256:
{
int nblocks;
nblocks = rijndaelBlockDecrypt (&ctx->aesContext, &ctx->aesDecKey,
data, 8 * len, data);
if (nblocks < 0)
return GC_INVALID_CIPHER;
}
break;
#endif
default:
return GC_INVALID_CIPHER;
}
return GC_OK;
}
Gc_rc gc_cipher_close(gc_cipher_handle handle)
{
_gc_cipher_ctx *ctx = handle;
if (ctx)
free(ctx);
return GC_OK;
}
/* Hashes. */
#define MAX_DIGEST_SIZE 20
typedef struct _gc_hash_ctx
{
Gc_hash alg;
Gc_hash_mode mode;
char hash[MAX_DIGEST_SIZE];
#ifdef GNULIB_GC_MD5
struct md5_ctx md5Context;
#endif
#ifdef GNULIB_GC_SHA1
struct sha1_ctx sha1Context;
#endif
} _gc_hash_ctx;
Gc_rc gc_hash_open(Gc_hash hash,
Gc_hash_mode mode,
gc_hash_handle * outhandle)
{
_gc_hash_ctx *ctx;
Gc_rc rc = GC_OK;
ctx = calloc(sizeof (*ctx), 1);
if (!ctx)
return GC_MALLOC_ERROR;
ctx->alg = hash;
ctx->mode = mode;
switch (hash)
{
#ifdef GNULIB_GC_MD5
case GC_MD5:
md5_init_ctx (&ctx->md5Context);
break;
#endif
#ifdef GNULIB_GC_SHA1
case GC_SHA1:
sha1_init_ctx (&ctx->sha1Context);
break;
#endif
default:
rc = GC_INVALID_HASH;
break;
}
switch (mode)
{
case 0:
break;
default:
rc = GC_INVALID_HASH;
break;
}
if (rc == GC_OK)
*outhandle = ctx;
else
free(ctx);
return rc;
}
Gc_rc gc_hash_clone(gc_hash_handle handle,
gc_hash_handle * outhandle)
{
_gc_hash_ctx *in = handle;
_gc_hash_ctx *out;
*outhandle = out = calloc(sizeof (*out), 1);
if (!out)
return GC_MALLOC_ERROR;
memcpy(out, in, sizeof (*out));
return GC_OK;
}
size_t gc_hash_digest_length(Gc_hash hash)
{
size_t len;
switch (hash)
{
case GC_MD2:
len = GC_MD2_DIGEST_SIZE;
break;
case GC_MD4:
len = GC_MD4_DIGEST_SIZE;
break;
case GC_MD5:
len = GC_MD5_DIGEST_SIZE;
break;
case GC_RMD160:
len = GC_RMD160_DIGEST_SIZE;
break;
case GC_SHA1:
len = GC_SHA1_DIGEST_SIZE;
break;
default:
return 0;
}
return len;
}
void gc_hash_write(gc_hash_handle handle,
size_t len,
const char *data)
{
_gc_hash_ctx *ctx = handle;
switch (ctx->alg)
{
#ifdef GNULIB_GC_MD5
case GC_MD5:
md5_process_bytes (data, len, &ctx->md5Context);
break;
#endif
#ifdef GNULIB_GC_SHA1
case GC_SHA1:
sha1_process_bytes (data, len, &ctx->sha1Context);
break;
#endif
default:
break;
}
}
const char * gc_hash_read(gc_hash_handle handle)
{
_gc_hash_ctx *ctx = handle;
const char *ret= NULL;
switch (ctx->alg)
{
#ifdef GNULIB_GC_MD5
case GC_MD5:
md5_finish_ctx (&ctx->md5Context, ctx->hash);
ret = ctx->hash;
break;
#endif
#ifdef GNULIB_GC_SHA1
case GC_SHA1:
sha1_finish_ctx (&ctx->sha1Context, ctx->hash);
ret = ctx->hash;
break;
#endif
default:
return NULL;
}
return ret;
}
void gc_hash_close(gc_hash_handle handle)
{
_gc_hash_ctx *ctx = handle;
free(ctx);
}
Gc_rc gc_hash_buffer(Gc_hash hash,
const void *in,
size_t inlen,
char *resbuf)
{
switch (hash)
{
#ifdef GNULIB_GC_MD5
case GC_MD5:
md5_buffer (in, inlen, resbuf);
break;
#endif
#ifdef GNULIB_GC_SHA1
case GC_SHA1:
sha1_buffer (in, inlen, resbuf);
break;
#endif
default:
return GC_INVALID_HASH;
}
return GC_OK;
}
#ifdef GNULIB_GC_MD5
Gc_rc
gc_md5 (const void *in, size_t inlen, void *resbuf)
{
md5_buffer (in, inlen, resbuf);
return GC_OK;
}
#endif
#ifdef GNULIB_GC_SHA1
Gc_rc
gc_sha1 (const void *in, size_t inlen, void *resbuf)
{
sha1_buffer (in, inlen, resbuf);
return GC_OK;
}
#endif
#ifdef GNULIB_GC_HMAC_MD5
Gc_rc
gc_hmac_md5 (const void *key, size_t keylen,
const void *in, size_t inlen, char *resbuf)
{
hmac_md5 (key, keylen, in, inlen, resbuf);
return GC_OK;
}
#endif
#ifdef GNULIB_GC_HMAC_SHA1
Gc_rc gc_hmac_sha1(const void *key,
size_t keylen,
const void *in,
size_t inlen,
char *resbuf)
{
hmac_sha1(key, keylen, in, inlen, resbuf);
return GC_OK;
}
#endif
+627
View File
@@ -0,0 +1,627 @@
/* gc-libgcrypt.c --- Crypto wrappers around Libgcrypt for GC.
* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Simon Josefsson
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Note: This file is only built if GC uses Libgcrypt. */
#include "config.h"
/* Get prototype. */
#include "gc.h"
#include <stdlib.h>
#include <string.h>
/* Get libgcrypt API. */
#include <gcrypt.h>
#include <assert.h>
/* Initialization. */
Gc_rc gc_init(void)
{
gcry_error_t err;
err = gcry_control(GCRYCTL_ANY_INITIALIZATION_P);
if (err == GPG_ERR_NO_ERROR)
{
if (gcry_check_version(GCRYPT_VERSION) == NULL)
return GC_INIT_ERROR;
err = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, NULL, 0);
if (err != GPG_ERR_NO_ERROR)
return GC_INIT_ERROR;
}
return GC_OK;
}
void gc_done(void)
{
return;
}
#ifdef GNULIB_GC_RANDOM
/* Randomness. */
Gc_rc
gc_nonce (char *data, size_t datalen)
{
gcry_create_nonce ((unsigned char *) data, datalen);
return GC_OK;
}
Gc_rc
gc_pseudo_random (char *data, size_t datalen)
{
gcry_randomize ((unsigned char *) data, datalen, GCRY_STRONG_RANDOM);
return GC_OK;
}
Gc_rc
gc_random (char *data, size_t datalen)
{
gcry_randomize ((unsigned char *) data, datalen, GCRY_VERY_STRONG_RANDOM);
return GC_OK;
}
#endif
/* Memory allocation. */
void gc_set_allocators(gc_malloc_t func_malloc,
gc_malloc_t secure_malloc,
gc_secure_check_t secure_check,
gc_realloc_t func_realloc,
gc_free_t func_free)
{
gcry_set_allocation_handler(func_malloc, secure_malloc, secure_check,
func_realloc, func_free);
}
/* Ciphers. */
Gc_rc gc_cipher_open(Gc_cipher alg,
Gc_cipher_mode mode,
gc_cipher_handle * outhandle)
{
int gcryalg, gcrymode;
gcry_error_t err;
switch (alg)
{
case GC_AES128:
gcryalg = GCRY_CIPHER_RIJNDAEL;
break;
case GC_AES192:
gcryalg = GCRY_CIPHER_RIJNDAEL;
break;
case GC_AES256:
gcryalg = GCRY_CIPHER_RIJNDAEL256;
break;
case GC_3DES:
gcryalg = GCRY_CIPHER_3DES;
break;
case GC_DES:
gcryalg = GCRY_CIPHER_DES;
break;
case GC_ARCFOUR128:
case GC_ARCFOUR40:
gcryalg = GCRY_CIPHER_ARCFOUR;
break;
case GC_ARCTWO40:
gcryalg = GCRY_CIPHER_RFC2268_40;
break;
#ifdef ENABLE_CAMELLIA
case GC_CAMELLIA128:
gcryalg = GCRY_CIPHER_CAMELLIA128;
break;
case GC_CAMELLIA256:
gcryalg = GCRY_CIPHER_CAMELLIA256;
break;
#endif
default:
return GC_INVALID_CIPHER;
}
switch (mode)
{
case GC_ECB:
gcrymode = GCRY_CIPHER_MODE_ECB;
break;
case GC_CBC:
gcrymode = GCRY_CIPHER_MODE_CBC;
break;
case GC_STREAM:
gcrymode = GCRY_CIPHER_MODE_STREAM;
break;
default:
return GC_INVALID_CIPHER;
}
err = gcry_cipher_open((gcry_cipher_hd_t *) outhandle, gcryalg, gcrymode, 0);
if (gcry_err_code(err))
return GC_INVALID_CIPHER;
return GC_OK;
}
Gc_rc gc_cipher_setkey(gc_cipher_handle handle,
size_t keylen,
const char *key)
{
gcry_error_t err;
err = gcry_cipher_setkey ((gcry_cipher_hd_t) handle, key, keylen);
if (gcry_err_code(err))
return GC_INVALID_CIPHER;
return GC_OK;
}
Gc_rc gc_cipher_setiv(gc_cipher_handle handle,
size_t ivlen,
const char *iv)
{
gcry_error_t err;
err = gcry_cipher_setiv ((gcry_cipher_hd_t) handle, iv, ivlen);
if (gcry_err_code(err))
return GC_INVALID_CIPHER;
return GC_OK;
}
Gc_rc gc_cipher_encrypt_inline(gc_cipher_handle handle,
size_t len,
char *data)
{
if (gcry_cipher_encrypt((gcry_cipher_hd_t) handle, data, len, NULL, len) != 0)
return GC_INVALID_CIPHER;
return GC_OK;
}
Gc_rc gc_cipher_decrypt_inline(gc_cipher_handle handle,
size_t len,
char *data)
{
if (gcry_cipher_decrypt((gcry_cipher_hd_t) handle, data, len, NULL, len) != 0)
return GC_INVALID_CIPHER;
return GC_OK;
}
Gc_rc gc_cipher_close(gc_cipher_handle handle)
{
gcry_cipher_close(handle);
return GC_OK;
}
/* Hashes. */
typedef struct _gc_hash_ctx
{
Gc_hash alg;
Gc_hash_mode mode;
gcry_md_hd_t gch;
} _gc_hash_ctx;
Gc_rc gc_hash_open(Gc_hash hash,
Gc_hash_mode mode,
gc_hash_handle * outhandle)
{
_gc_hash_ctx *ctx;
int gcryalg = 0, gcrymode = 0;
gcry_error_t err;
Gc_rc rc = GC_OK;
ctx = calloc(sizeof (*ctx), 1);
if (!ctx)
return GC_MALLOC_ERROR;
ctx->alg = hash;
ctx->mode = mode;
switch (hash)
{
case GC_MD2:
gcryalg = GCRY_MD_NONE;
break;
case GC_MD4:
gcryalg = GCRY_MD_MD4;
break;
case GC_MD5:
gcryalg = GCRY_MD_MD5;
break;
case GC_SHA1:
gcryalg = GCRY_MD_SHA1;
break;
case GC_SHA256:
gcryalg = GCRY_MD_SHA256;
break;
case GC_SHA384:
gcryalg = GCRY_MD_SHA384;
break;
case GC_SHA512:
gcryalg = GCRY_MD_SHA512;
break;
case GC_RMD160:
gcryalg = GCRY_MD_RMD160;
break;
default:
rc = GC_INVALID_HASH;
}
switch (mode)
{
case 0:
gcrymode = 0;
break;
case GC_HMAC:
gcrymode = GCRY_MD_FLAG_HMAC;
break;
default:
rc = GC_INVALID_HASH;
}
if (rc == GC_OK && gcryalg != GCRY_MD_NONE)
{
err = gcry_md_open(&ctx->gch, gcryalg, gcrymode);
if (gcry_err_code(err))
rc = GC_INVALID_HASH;
}
if (rc == GC_OK)
*outhandle = ctx;
else
free(ctx);
return rc;
}
Gc_rc gc_hash_clone(gc_hash_handle handle,
gc_hash_handle * outhandle)
{
_gc_hash_ctx *in = handle;
_gc_hash_ctx *out;
int err;
*outhandle = out = calloc(sizeof (*out), 1);
if (!out)
return GC_MALLOC_ERROR;
memcpy(out, in, sizeof (*out));
err = gcry_md_copy(&out->gch, in->gch);
if (err)
{
free(out);
return GC_INVALID_HASH;
}
return GC_OK;
}
size_t gc_hash_digest_length(Gc_hash hash)
{
size_t len;
switch (hash)
{
case GC_MD2:
len = GC_MD2_DIGEST_SIZE;
break;
case GC_MD4:
len = GC_MD4_DIGEST_SIZE;
break;
case GC_MD5:
len = GC_MD5_DIGEST_SIZE;
break;
case GC_RMD160:
len = GC_RMD160_DIGEST_SIZE;
break;
case GC_SHA1:
len = GC_SHA1_DIGEST_SIZE;
break;
case GC_SHA256:
len = GC_SHA256_DIGEST_SIZE;
break;
case GC_SHA384:
len = GC_SHA384_DIGEST_SIZE;
break;
case GC_SHA512:
len = GC_SHA512_DIGEST_SIZE;
break;
default:
return 0;
}
return len;
}
void gc_hash_hmac_setkey(gc_hash_handle handle,
size_t len,
const char *key)
{
_gc_hash_ctx *ctx = handle;
gcry_md_setkey(ctx->gch, key, len);
}
void gc_hash_write(gc_hash_handle handle,
size_t len,
const char *data)
{
_gc_hash_ctx *ctx = handle;
gcry_md_write(ctx->gch, data, len);
}
const char * gc_hash_read(gc_hash_handle handle)
{
_gc_hash_ctx *ctx = handle;
const char *digest;
{
gcry_md_final (ctx->gch);
digest = gcry_md_read(ctx->gch, 0);
}
return digest;
}
void gc_hash_close(gc_hash_handle handle)
{
_gc_hash_ctx *ctx = handle;
gcry_md_close(ctx->gch);
free(ctx);
}
Gc_rc gc_hash_buffer(Gc_hash hash,
const void *in,
size_t inlen,
char *resbuf)
{
int gcryalg;
switch (hash)
{
#ifdef GNULIB_GC_MD5
case GC_MD5:
gcryalg = GCRY_MD_MD5;
break;
#endif
#ifdef GNULIB_GC_SHA1
case GC_SHA1:
gcryalg = GCRY_MD_SHA1;
break;
#endif
#ifdef GNULIB_GC_SHA256
case GC_SHA256:
gcryalg = GCRY_MD_SHA256;
break;
#endif
#ifdef GNULIB_GC_SHA384
case GC_SHA384:
gcryalg = GCRY_MD_SHA384;
break;
#endif
#ifdef GNULIB_GC_SHA512
case GC_SHA512:
gcryalg = GCRY_MD_SHA512;
break;
#endif
#ifdef GNULIB_GC_RMD160
case GC_RMD160:
gcryalg = GCRY_MD_RMD160;
break;
#endif
default:
return GC_INVALID_HASH;
}
gcry_md_hash_buffer(gcryalg, resbuf, in, inlen);
return GC_OK;
}
/* One-call interface. */
#ifdef GNULIB_GC_MD5
Gc_rc
gc_md5 (const void *in, size_t inlen, void *resbuf)
{
size_t outlen = gcry_md_get_algo_dlen (GCRY_MD_MD5);
gcry_md_hd_t hd;
gpg_error_t err;
unsigned char *p;
assert (outlen == GC_MD5_DIGEST_SIZE);
err = gcry_md_open (&hd, GCRY_MD_MD5, 0);
if (err != GPG_ERR_NO_ERROR)
return GC_INVALID_HASH;
gcry_md_write (hd, in, inlen);
p = gcry_md_read (hd, GCRY_MD_MD5);
if (p == NULL)
{
gcry_md_close (hd);
return GC_INVALID_HASH;
}
memcpy (resbuf, p, outlen);
gcry_md_close (hd);
return GC_OK;
}
#endif
#ifdef GNULIB_GC_SHA1
Gc_rc
gc_sha1 (const void *in, size_t inlen, void *resbuf)
{
size_t outlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
gcry_md_hd_t hd;
gpg_error_t err;
unsigned char *p;
assert (outlen == GC_SHA1_DIGEST_SIZE);
err = gcry_md_open (&hd, GCRY_MD_SHA1, 0);
if (err != GPG_ERR_NO_ERROR)
return GC_INVALID_HASH;
gcry_md_write (hd, in, inlen);
p = gcry_md_read (hd, GCRY_MD_SHA1);
if (p == NULL)
{
gcry_md_close (hd);
return GC_INVALID_HASH;
}
memcpy (resbuf, p, outlen);
gcry_md_close (hd);
return GC_OK;
}
#endif
#ifdef GNULIB_GC_HMAC_MD5
Gc_rc
gc_hmac_md5 (const void *key, size_t keylen,
const void *in, size_t inlen, char *resbuf)
{
size_t hlen = gcry_md_get_algo_dlen (GCRY_MD_MD5);
gcry_md_hd_t mdh;
unsigned char *hash;
gpg_error_t err;
assert (hlen == 16);
err = gcry_md_open (&mdh, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
if (err != GPG_ERR_NO_ERROR)
return GC_INVALID_HASH;
err = gcry_md_setkey (mdh, key, keylen);
if (err != GPG_ERR_NO_ERROR)
{
gcry_md_close (mdh);
return GC_INVALID_HASH;
}
gcry_md_write (mdh, in, inlen);
hash = gcry_md_read (mdh, GCRY_MD_MD5);
if (hash == NULL)
{
gcry_md_close (mdh);
return GC_INVALID_HASH;
}
memcpy (resbuf, hash, hlen);
gcry_md_close (mdh);
return GC_OK;
}
#endif
#ifdef GNULIB_GC_HMAC_SHA1
Gc_rc gc_hmac_sha1(const void *key,
size_t keylen,
const void *in,
size_t inlen,
char *resbuf)
{
size_t hlen = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
gcry_md_hd_t mdh;
unsigned char *hash;
gpg_error_t err;
assert (hlen == GC_SHA1_DIGEST_SIZE);
err = gcry_md_open(&mdh, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
if (err != GPG_ERR_NO_ERROR)
return GC_INVALID_HASH;
err = gcry_md_setkey(mdh, key, keylen);
if (err != GPG_ERR_NO_ERROR)
{
gcry_md_close(mdh);
return GC_INVALID_HASH;
}
gcry_md_write(mdh, in, inlen);
hash = gcry_md_read(mdh, GCRY_MD_SHA1);
if (hash == NULL)
{
gcry_md_close(mdh);
return GC_INVALID_HASH;
}
memcpy(resbuf, hash, hlen);
gcry_md_close(mdh);
return GC_OK;
}
#endif
+185
View File
@@ -0,0 +1,185 @@
/* gc-pbkdf2-sha1.c --- Password-Based Key Derivation Function a'la PKCS#5
Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. The comments in this file are taken
from RFC 2898. */
#include <config.h>
#include "gc.h"
#include <stdlib.h>
#include <string.h>
/*
* 5.2 PBKDF2
*
* PBKDF2 applies a pseudorandom function (see Appendix B.1 for an
* example) to derive keys. The length of the derived key is essentially
* unbounded. (However, the maximum effective search space for the
* derived key may be limited by the structure of the underlying
* pseudorandom function. See Appendix B.1 for further discussion.)
* PBKDF2 is recommended for new applications.
*
* PBKDF2 (P, S, c, dkLen)
*
* Options: PRF underlying pseudorandom function (hLen
* denotes the length in octets of the
* pseudorandom function output)
*
* Input: P password, an octet string (ASCII or UTF-8)
* S salt, an octet string
* c iteration count, a positive integer
* dkLen intended length in octets of the derived
* key, a positive integer, at most
* (2^32 - 1) * hLen
*
* Output: DK derived key, a dkLen-octet string
*/
Gc_rc
gc_pbkdf2_sha1 (const char *P, size_t Plen,
const char *S, size_t Slen,
unsigned int c, char *DK, size_t dkLen)
{
unsigned int hLen = 20;
char U[20];
char T[20];
unsigned int u;
unsigned int l;
unsigned int r;
unsigned int i;
unsigned int k;
int rc;
char *tmp;
size_t tmplen = Slen + 4;
if (c == 0)
return GC_PKCS5_INVALID_ITERATION_COUNT;
if (dkLen == 0)
return GC_PKCS5_INVALID_DERIVED_KEY_LENGTH;
/*
*
* Steps:
*
* 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
* stop.
*/
if (dkLen > 4294967295U)
return GC_PKCS5_DERIVED_KEY_TOO_LONG;
/*
* 2. Let l be the number of hLen-octet blocks in the derived key,
* rounding up, and let r be the number of octets in the last
* block:
*
* l = CEIL (dkLen / hLen) ,
* r = dkLen - (l - 1) * hLen .
*
* Here, CEIL (x) is the "ceiling" function, i.e. the smallest
* integer greater than, or equal to, x.
*/
l = ((dkLen - 1) / hLen) + 1;
r = dkLen - (l - 1) * hLen;
/*
* 3. For each block of the derived key apply the function F defined
* below to the password P, the salt S, the iteration count c, and
* the block index to compute the block:
*
* T_1 = F (P, S, c, 1) ,
* T_2 = F (P, S, c, 2) ,
* ...
* T_l = F (P, S, c, l) ,
*
* where the function F is defined as the exclusive-or sum of the
* first c iterates of the underlying pseudorandom function PRF
* applied to the password P and the concatenation of the salt S
* and the block index i:
*
* F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
*
* where
*
* U_1 = PRF (P, S || INT (i)) ,
* U_2 = PRF (P, U_1) ,
* ...
* U_c = PRF (P, U_{c-1}) .
*
* Here, INT (i) is a four-octet encoding of the integer i, most
* significant octet first.
*
* 4. Concatenate the blocks and extract the first dkLen octets to
* produce a derived key DK:
*
* DK = T_1 || T_2 || ... || T_l<0..r-1>
*
* 5. Output the derived key DK.
*
* Note. The construction of the function F follows a "belt-and-
* suspenders" approach. The iterates U_i are computed recursively to
* remove a degree of parallelism from an opponent; they are exclusive-
* ored together to reduce concerns about the recursion degenerating
* into a small set of values.
*
*/
tmp = malloc (tmplen);
if (tmp == NULL)
return GC_MALLOC_ERROR;
memcpy (tmp, S, Slen);
for (i = 1; i <= l; i++)
{
memset (T, 0, hLen);
for (u = 1; u <= c; u++)
{
if (u == 1)
{
tmp[Slen + 0] = (i & 0xff000000) >> 24;
tmp[Slen + 1] = (i & 0x00ff0000) >> 16;
tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
tmp[Slen + 3] = (i & 0x000000ff) >> 0;
rc = gc_hmac_sha1 (P, Plen, tmp, tmplen, U);
}
else
rc = gc_hmac_sha1 (P, Plen, U, hLen, U);
if (rc != GC_OK)
{
free (tmp);
return rc;
}
for (k = 0; k < hLen; k++)
T[k] ^= U[k];
}
memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
}
free (tmp);
return GC_OK;
}
+347
View File
@@ -0,0 +1,347 @@
/* gc.h --- Header file for implementation agnostic crypto wrapper API.
* Copyright (C) 2002, 2003, 2004, 2005, 2007 Simon Josefsson
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
#ifndef GC_H
#define GC_H
/* Get size_t. */
# include <stddef.h>
enum Gc_rc
{
GC_OK = 0,
GC_MALLOC_ERROR,
GC_INIT_ERROR,
GC_RANDOM_ERROR,
GC_INVALID_CIPHER,
GC_INVALID_HASH,
GC_PKCS5_INVALID_ITERATION_COUNT,
GC_PKCS5_INVALID_DERIVED_KEY_LENGTH,
GC_PKCS5_DERIVED_KEY_TOO_LONG
};
typedef enum Gc_rc Gc_rc;
/* Hash types. */
enum Gc_hash
{
GC_MD4,
GC_MD5,
GC_SHA1,
GC_MD2,
GC_RMD160,
GC_SHA256,
GC_SHA384,
GC_SHA512
};
typedef enum Gc_hash Gc_hash;
enum Gc_hash_mode
{
GC_HMAC = 1
};
typedef enum Gc_hash_mode Gc_hash_mode;
typedef void *gc_hash_handle;
#define GC_MD2_DIGEST_SIZE 16
#define GC_MD4_DIGEST_SIZE 16
#define GC_MD5_DIGEST_SIZE 16
#define GC_RMD160_DIGEST_SIZE 20
#define GC_SHA1_DIGEST_SIZE 20
#define GC_SHA256_DIGEST_SIZE 32
#define GC_SHA384_DIGEST_SIZE 48
#define GC_SHA512_DIGEST_SIZE 64
/* Cipher types. */
enum Gc_cipher
{
GC_AES128,
GC_AES192,
GC_AES256,
GC_3DES,
GC_DES,
GC_ARCFOUR128,
GC_ARCFOUR40,
GC_ARCTWO40,
GC_CAMELLIA128,
GC_CAMELLIA256
};
typedef enum Gc_cipher Gc_cipher;
enum Gc_cipher_mode
{
GC_ECB,
GC_CBC,
GC_STREAM
};
typedef enum Gc_cipher_mode Gc_cipher_mode;
typedef void * gc_cipher_handle;
/* Call before respectively after any other functions. */
Gc_rc gc_init(void);
void gc_done(void);
/* Memory allocation (avoid). */
typedef void *(*gc_malloc_t)(size_t n);
typedef int (*gc_secure_check_t)(const void *);
typedef void *(*gc_realloc_t)(void *p,
size_t n);
typedef void (*gc_free_t)(void *);
void gc_set_allocators(gc_malloc_t func_malloc,
gc_malloc_t secure_malloc,
gc_secure_check_t secure_check,
gc_realloc_t func_realloc,
gc_free_t func_free);
/* Randomness. */
Gc_rc gc_nonce(char *data,
size_t datalen);
Gc_rc gc_pseudo_random(char *data,
size_t datalen);
Gc_rc gc_random(char *data,
size_t datalen);
/* Ciphers. */
Gc_rc gc_cipher_open(Gc_cipher cipher,
Gc_cipher_mode mode,
gc_cipher_handle *outhandle);
Gc_rc gc_cipher_setkey(gc_cipher_handle handle,
size_t keylen,
const char *key);
Gc_rc gc_cipher_setiv(gc_cipher_handle handle,
size_t ivlen,
const char *iv);
Gc_rc gc_cipher_encrypt_inline(gc_cipher_handle handle,
size_t len,
char *data);
Gc_rc gc_cipher_decrypt_inline(gc_cipher_handle handle,
size_t len,
char *data);
Gc_rc gc_cipher_close(gc_cipher_handle handle);
/* Hashes. */
Gc_rc gc_hash_open(Gc_hash hash,
Gc_hash_mode mode,
gc_hash_handle *outhandle);
Gc_rc gc_hash_clone(gc_hash_handle handle,
gc_hash_handle *outhandle);
size_t gc_hash_digest_length(Gc_hash hash);
void gc_hash_hmac_setkey(gc_hash_handle handle,
size_t len,
const char *key);
void gc_hash_write(gc_hash_handle handle,
size_t len,
const char *data);
const char *gc_hash_read(gc_hash_handle handle);
void gc_hash_close(gc_hash_handle handle);
/* Compute a hash value over buffer IN of INLEN bytes size using the
algorithm HASH, placing the result in the pre-allocated buffer OUT.
The required size of OUT depends on HASH, and is generally
GC_<HASH>_DIGEST_SIZE. For example, for GC_MD5 the output buffer
must be 16 bytes. The return value is 0 (GC_OK) on success, or
another Gc_rc error code. */
Gc_rc gc_hash_buffer(Gc_hash hash,
const void *in,
size_t inlen,
char *out);
/* One-call interface. */
Gc_rc gc_md2(const void *in,
size_t inlen,
void *resbuf);
Gc_rc gc_md4(const void *in,
size_t inlen,
void *resbuf);
Gc_rc gc_md5(const void *in,
size_t inlen,
void *resbuf);
Gc_rc gc_sha1(const void *in,
size_t inlen,
void *resbuf);
Gc_rc gc_hmac_md5(const void *key,
size_t keylen,
const void *in,
size_t inlen,
char *resbuf);
Gc_rc gc_hmac_sha1(const void *key,
size_t keylen,
const void *in,
size_t inlen,
char *resbuf);
/* Derive cryptographic keys from a password P of length PLEN, with
salt S of length SLEN, placing the result in pre-allocated buffer
DK of length DKLEN. An iteration count is specified in C, where a
larger value means this function take more time (typical iteration
counts are 1000-20000). This function "stretches" the key to be
exactly dkLen bytes long. GC_OK is returned on success, otherwise
an Gc_rc error code is returned. */
Gc_rc gc_pbkdf2_sha1(const char *P,
size_t Plen,
const char *S,
size_t Slen,
unsigned int c,
char *DK,
size_t dkLen);
/*
TODO:
From: Simon Josefsson <jas@extundo.com>
Subject: Re: generic crypto
Newsgroups: gmane.comp.lib.gnulib.bugs
Cc: bug-gnulib@gnu.org
Date: Fri, 07 Oct 2005 12:50:57 +0200
Mail-Copies-To: nobody
Paul Eggert <eggert@CS.UCLA.EDU> writes:
> Simon Josefsson <jas@extundo.com> writes:
>
>> * Perhaps the /dev/?random reading should be separated into a separate
>> module? It might be useful outside of the gc layer too.
>
> Absolutely. I've been meaning to do that for months (for a "shuffle"
> program I want to add to coreutils), but hadn't gotten around to it.
> It would have to be generalized a bit. I'd like to have the file
> descriptor cached, for example.
I'll write a separate module for that part.
I think we should even add a good PRNG that is re-seeded from
/dev/?random frequently. GnuTLS can need a lot of random data on a
big server, more than /dev/random can supply. And /dev/urandom might
not be strong enough. Further, the security of /dev/?random can also
be questionable.
>> I'm also not sure about the names of those functions, they suggest
>> a more higher-level API than what is really offered (i.e., the
>> names "nonce" and "pseudo_random" and "random" imply certain
>> cryptographic properties).
>
> Could you expand a bit more on that? What is the relationship between
> nonce/pseudorandom/random and the /dev/ values you are using?
There is none, that is the problem.
Applications generally need different kind of "random" numbers.
Sometimes they just need some random data and doesn't care whether it
is possible for an attacker to compute the string (aka a "nonce").
Sometimes they need data that is very difficult to compute (i.e.,
computing it require inverting SHA1 or similar). Sometimes they need
data that is not possible to compute, i.e., it wants real entropy
collected over time on the system. Collecting the last kind of random
data is very expensive, so it must not be used too often. The second
kind of random data ("pseudo random") is typically generated by
seeding a good PRNG with a couple of hundred bytes of real entropy
from the "real random" data pool. The "nonce" is usually computed
using the PRNG as well, because PRNGs are usually fast.
Pseudo-random data is typically used for session keys. Strong random
data is often used to generate long-term keys (e.g., private RSA
keys).
Of course, there are many subtleties. There are several different
kind of nonce:s. Sometimes a nonce is just an ever-increasing
integer, starting from 0. Sometimes it is assumed to be unlikely to
be the same as previous nonces, but without a requirement that the
nonce is possible to guess. MD5(system clock) would thus suffice, if
it isn't called too often. You can guess what the next value will be,
but it will always be different.
The problem is that /dev/?random doesn't offer any kind of semantic
guarantees. But applications need an API that make that promise.
I think we should do this in several steps:
1) Write a module that can read from /dev/?random.
2) Add a module for a known-good PRNG suitable for random number
generation, that can be continuously re-seeded.
3) Add a high-level module that provide various different randomness
functions. One for nonces, perhaps even different kind of nonces,
one for pseudo random data, and one for strong random data. It is
not clear whether we can hope to achieve the last one in a portable
way.
Further, it would be useful to allow users to provide their own
entropy source as a file, used to seed the PRNG or initialize the
strong randomness pool. This is used on embedded platforms that
doesn't have enough interrupts to hope to generate good random data.
> For example, why not use OpenBSD's /dev/arandom?
I don't trust ARC4. For example, recent cryptographic efforts
indicate that you must throw away the first 512 bytes generated from
the PRNG for it to be secure. I don't know whether OpenBSD do this.
Further, I recall some eprint paper on RC4 security that didn't
inspire confidence.
While I trust the random devices in OpenBSD more than
Solaris/AIX/HPUX/etc, I think that since we need something better on
Solaris/AIX/HPUX we'd might as well use it on OpenBSD or even Linux
too.
> Here is one thought. The user could specify a desired quality level
> range, and the implementation then would supply random data that is at
> least as good as the lower bound of the range. I.e., ihe
> implementation refuses to produce any random data if it can't generate
> data that is at least as good as the lower end of the range. The
> upper bound of the range is advice from the user not to be any more
> expensive than that, but the implementation can ignore the advice if
> it doesn't have anything cheaper.
I'm not sure this is a good idea. Users can't really be expected to
understand this. Further, applications need many different kind of
random data. Selecting the randomness level for each by the user will
be too complicated.
I think it is better if the application decide, from its cryptographic
requirement, what entropy quality it require, and call the proper API.
Meeting the implied semantic properties should be the job for gnulib.
>> Perhaps gc_dev_random and gc_dev_urandom?
>
> To some extent. I'd rather insulate the user from the details of
> where the random numbers come from. On the other hand we need to
> provide a way for applications to specify a file that contains
> random bits, so that people can override the defaults.
Agreed.
This may require some thinking before it is finalized. Is it ok to
install the GC module as-is meanwhile? Then I can continue to add the
stuff that GnuTLS need, and then come back to re-working the
randomness module. That way, we have two different projects that use
the code. GnuTLS includes the same randomness code that was in GNU
SASL and that is in the current gc module. I feel much more
comfortable working in small steps at a time, rather then working on
this for a long time in gnulib and only later integrate the stuff in
GnuTLS.
Thanks,
Simon
*/
#endif /* GC_H */
+270
View File
@@ -0,0 +1,270 @@
/* Convenience header for conditional use of GNU <libintl.h>.
Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1
/* NLS can be disabled through the configure --disable-nls option. */
#if ENABLE_NLS
/* Get declarations of GNU message catalog functions. */
# include <libintl.h>
/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
the gettext() and ngettext() macros. This is an alternative to calling
textdomain(), and is useful for libraries. */
# ifdef DEFAULT_TEXT_DOMAIN
# undef gettext
# define gettext(Msgid) \
dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
# undef ngettext
# define ngettext(Msgid1, Msgid2, N) \
dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
# endif
#else
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
chokes if dcgettext is defined as a macro. So include it now, to make
later inclusions of <locale.h> a NOP. We don't include <libintl.h>
as well because people using "gettext.h" will not include <libintl.h>,
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
is OK. */
#if defined(__sun)
# include <locale.h>
#endif
/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
<libintl.h>, which chokes if dcgettext is defined as a macro. So include
it now, to make later inclusions of <libintl.h> a NOP. */
#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
# include <cstdlib>
# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H
# include <libintl.h>
# endif
#endif
/* Disabled NLS.
The casts to 'const char *' serve the purpose of producing warnings
for invalid uses of the value returned from these functions.
On pre-ANSI systems without 'const', the config.h file is supposed to
contain "#define const". */
# define gettext(Msgid) ((const char *) (Msgid))
# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
# define dcgettext(Domainname, Msgid, Category) \
((void) (Category), dgettext (Domainname, Msgid))
# define ngettext(Msgid1, Msgid2, N) \
((N) == 1 \
? ((void) (Msgid2), (const char *) (Msgid1)) \
: ((void) (Msgid1), (const char *) (Msgid2)))
# define dngettext(Domainname, Msgid1, Msgid2, N) \
((void) (Domainname), ngettext (Msgid1, Msgid2, N))
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N))
# define textdomain(Domainname) ((const char *) (Domainname))
# define bindtextdomain(Domainname, Dirname) \
((void) (Domainname), (const char *) (Dirname))
# define bind_textdomain_codeset(Domainname, Codeset) \
((void) (Domainname), (const char *) (Codeset))
#endif
/* A pseudo function call that serves as a marker for the automated
extraction of messages, but does not call gettext(). The run-time
translation is done at a different place in the code.
The argument, String, should be a literal string. Concatenated strings
and other string expressions won't work.
The macro's expansion is not parenthesized, so that it is suitable as
initializer for static 'char[]' or 'const char[]' variables. */
#define gettext_noop(String) String
/* The separator between msgctxt and msgid in a .mo file. */
#define GETTEXT_CONTEXT_GLUE "\004"
/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
short and rarely need to change.
The letter 'p' stands for 'particular' or 'special'. */
#ifdef DEFAULT_TEXT_DOMAIN
# define pgettext(Msgctxt, Msgid) \
pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#else
# define pgettext(Msgctxt, Msgid) \
pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#endif
#define dpgettext(Domainname, Msgctxt, Msgid) \
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
#ifdef DEFAULT_TEXT_DOMAIN
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#else
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#endif
#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
pgettext_aux (const char *domain,
const char *msg_ctxt_id, const char *msgid,
int category)
{
const char *translation = dcgettext (domain, msg_ctxt_id, category);
if (translation == msg_ctxt_id)
return msgid;
else
return translation;
}
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
npgettext_aux (const char *domain,
const char *msg_ctxt_id, const char *msgid,
const char *msgid_plural, unsigned long int n,
int category)
{
const char *translation =
dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
if (translation == msg_ctxt_id || translation == msgid_plural)
return (n == 1 ? msgid : msgid_plural);
else
return translation;
}
/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
can be arbitrary expressions. But for string literals these macros are
less efficient than those above. */
#include <string.h>
#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \
(((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \
/* || __STDC_VERSION__ >= 199901L */ )
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
#include <stdlib.h>
#endif
#define pgettext_expr(Msgctxt, Msgid) \
dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
dcpgettext_expr (const char *domain,
const char *msgctxt, const char *msgid,
int category)
{
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation;
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
char msg_ctxt_id[msgctxt_len + msgid_len];
#else
char buf[1024];
char *msg_ctxt_id =
(msgctxt_len + msgid_len <= sizeof (buf)
? buf
: (char *) malloc (msgctxt_len + msgid_len));
if (msg_ctxt_id != NULL)
#endif
{
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcgettext (domain, msg_ctxt_id, category);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
if (translation != msg_ctxt_id)
return translation;
}
return msgid;
}
#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
dcnpgettext_expr (const char *domain,
const char *msgctxt, const char *msgid,
const char *msgid_plural, unsigned long int n,
int category)
{
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation;
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
char msg_ctxt_id[msgctxt_len + msgid_len];
#else
char buf[1024];
char *msg_ctxt_id =
(msgctxt_len + msgid_len <= sizeof (buf)
? buf
: (char *) malloc (msgctxt_len + msgid_len));
if (msg_ctxt_id != NULL)
#endif
{
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
if (!(translation == msg_ctxt_id || translation == msgid_plural))
return translation;
}
return (n == 1 ? msgid : msgid_plural);
}
#endif /* _LIBGETTEXT_H */
+81
View File
@@ -0,0 +1,81 @@
/* hmac-md5.c -- hashed message authentication codes
Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. */
#include <config.h>
#include "hmac.h"
#include "memxor.h"
#include "md5.h"
#include <string.h>
#define IPAD 0x36
#define OPAD 0x5c
int
hmac_md5 (const void *key, size_t keylen,
const void *in, size_t inlen, void *resbuf)
{
struct md5_ctx inner;
struct md5_ctx outer;
char optkeybuf[16];
char block[64];
char innerhash[16];
/* Reduce the key's size, so that it becomes <= 64 bytes large. */
if (keylen > 64)
{
struct md5_ctx keyhash;
md5_init_ctx (&keyhash);
md5_process_bytes (key, keylen, &keyhash);
md5_finish_ctx (&keyhash, optkeybuf);
key = optkeybuf;
keylen = 16;
}
/* Compute INNERHASH from KEY and IN. */
md5_init_ctx (&inner);
memset (block, IPAD, sizeof (block));
memxor (block, key, keylen);
md5_process_block (block, 64, &inner);
md5_process_bytes (in, inlen, &inner);
md5_finish_ctx (&inner, innerhash);
/* Compute result from KEY and INNERHASH. */
md5_init_ctx (&outer);
memset (block, OPAD, sizeof (block));
memxor (block, key, keylen);
md5_process_block (block, 64, &outer);
md5_process_bytes (innerhash, 16, &outer);
md5_finish_ctx (&outer, resbuf);
return 0;
}
+81
View File
@@ -0,0 +1,81 @@
/* hmac-sha1.c -- hashed message authentication codes
Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. */
#include <config.h>
#include "hmac.h"
#include "memxor.h"
#include "sha1.h"
#include <string.h>
#define IPAD 0x36
#define OPAD 0x5c
int
hmac_sha1 (const void *key, size_t keylen,
const void *in, size_t inlen, void *resbuf)
{
struct sha1_ctx inner;
struct sha1_ctx outer;
char optkeybuf[20];
char block[64];
char innerhash[20];
/* Reduce the key's size, so that it becomes <= 64 bytes large. */
if (keylen > 64)
{
struct sha1_ctx keyhash;
sha1_init_ctx (&keyhash);
sha1_process_bytes (key, keylen, &keyhash);
sha1_finish_ctx (&keyhash, optkeybuf);
key = optkeybuf;
keylen = 20;
}
/* Compute INNERHASH from KEY and IN. */
sha1_init_ctx (&inner);
memset (block, IPAD, sizeof (block));
memxor (block, key, keylen);
sha1_process_block (block, 64, &inner);
sha1_process_bytes (in, inlen, &inner);
sha1_finish_ctx (&inner, innerhash);
/* Compute result from KEY and INNERHASH. */
sha1_init_ctx (&outer);
memset (block, OPAD, sizeof (block));
memxor (block, key, keylen);
sha1_process_block (block, 64, &outer);
sha1_process_bytes (innerhash, 20, &outer);
sha1_finish_ctx (&outer, resbuf);
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
/* hmac.h -- hashed message authentication codes
Copyright (C) 2005 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. */
#ifndef HMAC_H
# define HMAC_H 1
#include <stddef.h>
/* Compute Hashed Message Authentication Code with MD5, as described
in RFC 2104, over BUFFER data of BUFLEN bytes using the KEY of
KEYLEN bytes, writing the output to pre-allocated 16 byte minimum
RESBUF buffer. Return 0 on success. */
int
hmac_md5 (const void *key, size_t keylen,
const void *buffer, size_t buflen, void *resbuf);
/* Compute Hashed Message Authentication Code with SHA-1, over BUFFER
data of BUFLEN bytes using the KEY of KEYLEN bytes, writing the
output to pre-allocated 20 byte minimum RESBUF buffer. Return 0 on
success. */
int
hmac_sha1 (const void *key, size_t keylen,
const void *in, size_t inlen, void *resbuf);
#endif /* HMAC_H */
+451
View File
@@ -0,0 +1,451 @@
/* Functions to compute MD5 message digest of files or memory blocks.
according to the definition of MD5 in RFC 1321 from April 1992.
Copyright (C) 1995,1996,1997,1999,2000,2001,2005,2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
#include <config.h>
#include "md5.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#if USE_UNLOCKED_IO
# include "unlocked-io.h"
#endif
#ifdef _LIBC
# include <endian.h>
# if __BYTE_ORDER == __BIG_ENDIAN
# define WORDS_BIGENDIAN 1
# endif
/* We need to keep the namespace clean so define the MD5 function
protected using leading __ . */
# define md5_init_ctx __md5_init_ctx
# define md5_process_block __md5_process_block
# define md5_process_bytes __md5_process_bytes
# define md5_finish_ctx __md5_finish_ctx
# define md5_read_ctx __md5_read_ctx
# define md5_stream __md5_stream
# define md5_buffer __md5_buffer
#endif
#ifdef WORDS_BIGENDIAN
# define SWAP(n) \
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
#else
# define SWAP(n) (n)
#endif
#define BLOCKSIZE 4096
#if BLOCKSIZE % 64 != 0
# error "invalid BLOCKSIZE"
#endif
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (RFC 1321, 3.1: Step 1) */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/* Initialize structure containing state of computation.
(RFC 1321, 3.3: Step 3) */
void
md5_init_ctx (struct md5_ctx *ctx)
{
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Put result from CTX in first 16 bytes following RESBUF. The result
must be in little endian byte order.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32-bit value. */
void *
md5_read_ctx (const struct md5_ctx *ctx, void *resbuf)
{
((uint32_t *) resbuf)[0] = SWAP (ctx->A);
((uint32_t *) resbuf)[1] = SWAP (ctx->B);
((uint32_t *) resbuf)[2] = SWAP (ctx->C);
((uint32_t *) resbuf)[3] = SWAP (ctx->D);
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32-bit value. */
void *
md5_finish_ctx (struct md5_ctx *ctx, void *resbuf)
{
/* Take yet unprocessed bytes into account. */
uint32_t bytes = ctx->buflen;
size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
/* Put the 64-bit file length in *bits* at the end of the buffer. */
ctx->buffer[size - 2] = SWAP (ctx->total[0] << 3);
ctx->buffer[size - 1] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
/* Process last bytes. */
md5_process_block (ctx->buffer, size * 4, ctx);
return md5_read_ctx (ctx, resbuf);
}
/* Compute MD5 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 16 bytes
beginning at RESBLOCK. */
int
md5_stream (FILE * stream, void *resblock)
{
struct md5_ctx ctx;
char buffer[BLOCKSIZE + 72];
size_t sum;
/* Initialize the computation context. */
md5_init_ctx (&ctx);
/* Iterate over full file contents. */
while (1)
{
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
computation function processes the whole buffer so that with the
next round of the loop another block can be read. */
size_t n;
sum = 0;
/* Read block. Take care for partial reads. */
while (1)
{
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
sum += n;
if (sum == BLOCKSIZE)
break;
if (n == 0)
{
/* Check for the error flag IFF N == 0, so that we don't
exit the loop after a partial read due to e.g., EAGAIN
or EWOULDBLOCK. */
if (ferror (stream))
return 1;
goto process_partial_block;
}
/* We've read at least one byte, so ignore errors. But always
check for EOF, since feof may be true even though N > 0.
Otherwise, we could end up calling fread after EOF. */
if (feof (stream))
goto process_partial_block;
}
/* Process buffer with BLOCKSIZE bytes. Note that
BLOCKSIZE % 64 == 0
*/
md5_process_block (buffer, BLOCKSIZE, &ctx);
}
process_partial_block:
/* Process any remaining bytes. */
if (sum > 0)
md5_process_bytes (buffer, sum, &ctx);
/* Construct result in desired memory. */
md5_finish_ctx (&ctx, resblock);
return 0;
}
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
void *
md5_buffer (const char *buffer, size_t len, void *resblock)
{
struct md5_ctx ctx;
/* Initialize the computation context. */
md5_init_ctx (&ctx);
/* Process whole buffer but last len % 64 bytes. */
md5_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return md5_finish_ctx (&ctx, resblock);
}
void
md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx)
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64)
{
md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer,
&((char *) ctx->buffer)[(left_over + add) & ~63],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64)
{
#if !_STRING_ARCH_unaligned
# define alignof(type) offsetof (struct { char c; type x; }, x)
# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0)
if (UNALIGNED_P (buffer))
while (len > 64)
{
md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
else
#endif
{
md5_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
}
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
size_t left_over = ctx->buflen;
memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
left_over += len;
if (left_over >= 64)
{
md5_process_block (ctx->buffer, 64, ctx);
left_over -= 64;
memcpy (ctx->buffer, &ctx->buffer[16], left_over);
}
ctx->buflen = left_over;
}
}
/* These are the four functions used in the four steps of the MD5 algorithm
and defined in the RFC 1321. The first function is a little bit optimized
(as found in Colin Plumbs public domain implementation). */
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
#define FF(b, c, d) (d ^ (b & (c ^ d)))
#define FG(b, c, d) FF (d, b, c)
#define FH(b, c, d) (b ^ c ^ d)
#define FI(b, c, d) (c ^ (b | ~d))
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0. */
void
md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
{
uint32_t correct_words[16];
const uint32_t *words = buffer;
size_t nwords = len / sizeof (uint32_t);
const uint32_t *endp = words + nwords;
uint32_t A = ctx->A;
uint32_t B = ctx->B;
uint32_t C = ctx->C;
uint32_t D = ctx->D;
/* First increment the byte count. RFC 1321 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
/* Process all bytes in the buffer with 64 bytes in each round of
the loop. */
while (words < endp)
{
uint32_t *cwp = correct_words;
uint32_t A_save = A;
uint32_t B_save = B;
uint32_t C_save = C;
uint32_t D_save = D;
/* First round: using the given function, the context and a constant
the next context is computed. Because the algorithms processing
unit is a 32-bit word and it is determined to work on words in
little endian byte order we perhaps have to change the byte order
before the computation. To reduce the work for the next steps
we store the swapped words in the array CORRECT_WORDS. */
#define OP(a, b, c, d, s, T) \
do \
{ \
a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
++words; \
CYCLIC (a, s); \
a += b; \
} \
while (0)
/* It is unfortunate that C does not provide an operator for
cyclic rotation. Hope the C compiler is smart enough. */
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
/* Before we start, one word to the strange constants.
They are defined in RFC 1321 as
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
Here is an equivalent invocation using Perl:
perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
*/
/* Round 1. */
OP (A, B, C, D, 7, 0xd76aa478);
OP (D, A, B, C, 12, 0xe8c7b756);
OP (C, D, A, B, 17, 0x242070db);
OP (B, C, D, A, 22, 0xc1bdceee);
OP (A, B, C, D, 7, 0xf57c0faf);
OP (D, A, B, C, 12, 0x4787c62a);
OP (C, D, A, B, 17, 0xa8304613);
OP (B, C, D, A, 22, 0xfd469501);
OP (A, B, C, D, 7, 0x698098d8);
OP (D, A, B, C, 12, 0x8b44f7af);
OP (C, D, A, B, 17, 0xffff5bb1);
OP (B, C, D, A, 22, 0x895cd7be);
OP (A, B, C, D, 7, 0x6b901122);
OP (D, A, B, C, 12, 0xfd987193);
OP (C, D, A, B, 17, 0xa679438e);
OP (B, C, D, A, 22, 0x49b40821);
/* For the second to fourth round we have the possibly swapped words
in CORRECT_WORDS. Redefine the macro to take an additional first
argument specifying the function to use. */
#undef OP
#define OP(f, a, b, c, d, k, s, T) \
do \
{ \
a += f (b, c, d) + correct_words[k] + T; \
CYCLIC (a, s); \
a += b; \
} \
while (0)
/* Round 2. */
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
OP (FG, D, A, B, C, 10, 9, 0x02441453);
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
/* Round 3. */
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
/* Round 4. */
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
/* Add the starting values of the context. */
A += A_save;
B += B_save;
C += C_save;
D += D_save;
}
/* Put checksum in context given as argument. */
ctx->A = A;
ctx->B = B;
ctx->C = C;
ctx->D = D;
}
+124
View File
@@ -0,0 +1,124 @@
/* Declaration of functions and data types used for MD5 sum computing
library functions.
Copyright (C) 1995-1997,1999,2000,2001,2004,2005,2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _MD5_H
#define _MD5_H 1
#include <stdio.h>
#include <stdint.h>
#define MD5_DIGEST_SIZE 16
#define MD5_BLOCK_SIZE 64
#ifndef __GNUC_PREREQ
# if defined __GNUC__ && defined __GNUC_MINOR__
# define __GNUC_PREREQ(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
# else
# define __GNUC_PREREQ(maj, min) 0
# endif
#endif
#ifndef __THROW
# if defined __cplusplus && __GNUC_PREREQ (2,8)
# define __THROW throw ()
# else
# define __THROW
# endif
#endif
#ifndef _LIBC
# define __md5_buffer md5_buffer
# define __md5_finish_ctx md5_finish_ctx
# define __md5_init_ctx md5_init_ctx
# define __md5_process_block md5_process_block
# define __md5_process_bytes md5_process_bytes
# define __md5_read_ctx md5_read_ctx
# define __md5_stream md5_stream
#endif
/* Structure to save state of computation between the single steps. */
struct md5_ctx
{
uint32_t A;
uint32_t B;
uint32_t C;
uint32_t D;
uint32_t total[2];
uint32_t buflen;
uint32_t buffer[32];
};
/*
* The following three functions are build up the low level used in
* the functions `md5_stream' and `md5_buffer'.
*/
/* Initialize structure containing state of computation.
(RFC 1321, 3.3: Step 3) */
extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW;
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */
extern void __md5_process_block (const void *buffer, size_t len,
struct md5_ctx *ctx) __THROW;
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */
extern void __md5_process_bytes (const void *buffer, size_t len,
struct md5_ctx *ctx) __THROW;
/* Process the remaining bytes in the buffer and put result from CTX
in first 16 bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest.
IMPORTANT: On some systems, RESBUF must be aligned to a 32-bit
boundary. */
extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW;
/* Put result from CTX in first 16 bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest.
IMPORTANT: On some systems, RESBUF must be aligned to a 32-bit
boundary. */
extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW;
/* Compute MD5 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 16 bytes
beginning at RESBLOCK. */
extern int __md5_stream (FILE *stream, void *resblock) __THROW;
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
extern void *__md5_buffer (const char *buffer, size_t len,
void *resblock) __THROW;
#endif /* md5.h */
+61
View File
@@ -0,0 +1,61 @@
/* Copyright (C) 1991,92,93,94,96,97,98,2000,2004,2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _LIBC
# include <config.h>
#endif
#include <stddef.h>
#include <string.h>
#ifndef _LIBC
# define __builtin_expect(expr, val) (expr)
#endif
#undef memmem
/* Return the first occurrence of NEEDLE in HAYSTACK. */
void *
memmem (haystack, haystack_len, needle, needle_len)
const void *haystack;
size_t haystack_len;
const void *needle;
size_t needle_len;
{
const char *begin;
const char *const last_possible = (const char *) haystack + haystack_len
- needle_len;
if (needle_len == 0)
/* The first occurrence of the empty string is deemed to occur at
the beginning of the string. */
return (void *) haystack;
/* Sanity check, otherwise the loop might search through the whole
memory. */
if (__builtin_expect (haystack_len < needle_len, 0))
return NULL;
for (begin = (const char *) haystack; begin <= last_possible; ++begin)
if (begin[0] == ((const char *) needle)[0]
&& !memcmp ((const void *) &begin[1],
(const void *) ((const char *) needle + 1),
needle_len - 1))
return (void *) begin;
return NULL;
}
+26
View File
@@ -0,0 +1,26 @@
/* memmove.c -- copy memory.
Copy LENGTH bytes from SOURCE to DEST. Does not null-terminate.
In the public domain.
By David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <config.h>
#include <stddef.h>
void *
memmove (void *dest0, void const *source0, size_t length)
{
char *dest = dest0;
char const *source = source0;
if (source < dest)
/* Moving from low mem to hi mem; start at end. */
for (source += length, dest += length; length; --length)
*--dest = *--source;
else if (source != dest)
{
/* Moving from hi mem to low mem; start at beginning. */
for (; length; --length)
*dest++ = *source++;
}
return dest0;
}
+35
View File
@@ -0,0 +1,35 @@
/* memxor.c -- perform binary exclusive OR operation of two memory blocks.
Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. The interface was inspired by memxor
in Niels Möller's Nettle. */
#include <config.h>
#include "memxor.h"
void *
memxor (void *restrict dest, const void *restrict src, size_t n)
{
char const *s = src;
char *d = dest;
for (; n > 0; n--)
*d++ ^= *s++;
return dest;
}
+31
View File
@@ -0,0 +1,31 @@
/* memxor.h -- perform binary exclusive OR operation on memory blocks.
Copyright (C) 2005 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. The interface was inspired by memxor
in Niels Möller's Nettle. */
#ifndef MEMXOR_H
# define MEMXOR_H
#include <stddef.h>
/* Compute binary exclusive OR of memory areas DEST and SRC, putting
the result in DEST, of length N bytes. Returns a pointer to
DEST. */
void *memxor (void *restrict dest, const void *restrict src, size_t n);
#endif /* MEMXOR_H */
+185
View File
@@ -0,0 +1,185 @@
/* Decomposed printf argument list.
Copyright (C) 1999, 2002-2003, 2005-2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* This file can be parametrized with the following macros:
ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions.
PRINTF_FETCHARGS Name of the function to be defined.
STATIC Set to 'static' to declare the function static. */
#ifndef PRINTF_FETCHARGS
# include <config.h>
#endif
/* Specification. */
#ifndef PRINTF_FETCHARGS
# include "printf-args.h"
#endif
#ifdef STATIC
STATIC
#endif
int
PRINTF_FETCHARGS (va_list args, arguments * a)
{
size_t i;
argument *ap;
for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++)
switch (ap->type)
{
case TYPE_SCHAR:
ap->a.a_schar = va_arg (args, /*signed char */ int);
break;
case TYPE_UCHAR:
ap->a.a_uchar = va_arg (args, /*unsigned char */ int);
break;
case TYPE_SHORT:
ap->a.a_short = va_arg (args, /*short */ int);
break;
case TYPE_USHORT:
ap->a.a_ushort = va_arg (args, /*unsigned short */ int);
break;
case TYPE_INT:
ap->a.a_int = va_arg (args, int);
break;
case TYPE_UINT:
ap->a.a_uint = va_arg (args, unsigned int);
break;
case TYPE_LONGINT:
ap->a.a_longint = va_arg (args, long int);
break;
case TYPE_ULONGINT:
ap->a.a_ulongint = va_arg (args, unsigned long int);
break;
#if HAVE_LONG_LONG_INT
case TYPE_LONGLONGINT:
ap->a.a_longlongint = va_arg (args, long long int);
break;
case TYPE_ULONGLONGINT:
ap->a.a_ulonglongint = va_arg (args, unsigned long long int);
break;
#endif
case TYPE_DOUBLE:
ap->a.a_double = va_arg (args, double);
break;
case TYPE_LONGDOUBLE:
ap->a.a_longdouble = va_arg (args, long double);
break;
case TYPE_CHAR:
ap->a.a_char = va_arg (args, int);
break;
#if HAVE_WINT_T
case TYPE_WIDE_CHAR:
/* Although ISO C 99 7.24.1.(2) says that wint_t is "unchanged by
default argument promotions", this is not the case in mingw32,
where wint_t is 'unsigned short'. */
ap->a.a_wide_char =
(sizeof (wint_t) < sizeof (int)
? va_arg (args, int) : va_arg (args, wint_t));
break;
#endif
case TYPE_STRING:
ap->a.a_string = va_arg (args, const char *);
/* A null pointer is an invalid argument for "%s", but in practice
it occurs quite frequently in printf statements that produce
debug output. Use a fallback in this case. */
if (ap->a.a_string == NULL)
ap->a.a_string = "(NULL)";
break;
#if HAVE_WCHAR_T
case TYPE_WIDE_STRING:
ap->a.a_wide_string = va_arg (args, const wchar_t *);
/* A null pointer is an invalid argument for "%ls", but in practice
it occurs quite frequently in printf statements that produce
debug output. Use a fallback in this case. */
if (ap->a.a_wide_string == NULL)
{
static const wchar_t wide_null_string[] = {
(wchar_t) '(',
(wchar_t) 'N', (wchar_t) 'U', (wchar_t) 'L', (wchar_t) 'L',
(wchar_t) ')',
(wchar_t) 0
};
ap->a.a_wide_string = wide_null_string;
}
break;
#endif
case TYPE_POINTER:
ap->a.a_pointer = va_arg (args, void *);
break;
case TYPE_COUNT_SCHAR_POINTER:
ap->a.a_count_schar_pointer = va_arg (args, signed char *);
break;
case TYPE_COUNT_SHORT_POINTER:
ap->a.a_count_short_pointer = va_arg (args, short *);
break;
case TYPE_COUNT_INT_POINTER:
ap->a.a_count_int_pointer = va_arg (args, int *);
break;
case TYPE_COUNT_LONGINT_POINTER:
ap->a.a_count_longint_pointer = va_arg (args, long int *);
break;
#if HAVE_LONG_LONG_INT
case TYPE_COUNT_LONGLONGINT_POINTER:
ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
break;
#endif
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
case TYPE_U8_STRING:
ap->a.a_u8_string = va_arg (args, const uint8_t *);
/* A null pointer is an invalid argument for "%U", but in practice
it occurs quite frequently in printf statements that produce
debug output. Use a fallback in this case. */
if (ap->a.a_u8_string == NULL)
{
static const uint8_t u8_null_string[] =
{ '(', 'N', 'U', 'L', 'L', ')', 0 };
ap->a.a_u8_string = u8_null_string;
}
break;
case TYPE_U16_STRING:
ap->a.a_u16_string = va_arg (args, const uint16_t *);
/* A null pointer is an invalid argument for "%lU", but in practice
it occurs quite frequently in printf statements that produce
debug output. Use a fallback in this case. */
if (ap->a.a_u16_string == NULL)
{
static const uint16_t u16_null_string[] =
{ '(', 'N', 'U', 'L', 'L', ')', 0 };
ap->a.a_u16_string = u16_null_string;
}
break;
case TYPE_U32_STRING:
ap->a.a_u32_string = va_arg (args, const uint32_t *);
/* A null pointer is an invalid argument for "%llU", but in practice
it occurs quite frequently in printf statements that produce
debug output. Use a fallback in this case. */
if (ap->a.a_u32_string == NULL)
{
static const uint32_t u32_null_string[] =
{ '(', 'N', 'U', 'L', 'L', ')', 0 };
ap->a.a_u32_string = u32_null_string;
}
break;
#endif
default:
/* Unknown type. */
return -1;
}
return 0;
}
+154
View File
@@ -0,0 +1,154 @@
/* Decomposed printf argument list.
Copyright (C) 1999, 2002-2003, 2006-2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _PRINTF_ARGS_H
#define _PRINTF_ARGS_H
/* This file can be parametrized with the following macros:
ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions.
PRINTF_FETCHARGS Name of the function to be declared.
STATIC Set to 'static' to declare the function static. */
/* Default parameters. */
#ifndef PRINTF_FETCHARGS
# define PRINTF_FETCHARGS printf_fetchargs
#endif
/* Get size_t. */
#include <stddef.h>
/* Get wchar_t. */
#if HAVE_WCHAR_T
# include <stddef.h>
#endif
/* Get wint_t. */
#if HAVE_WINT_T
# include <wchar.h>
#endif
/* Get va_list. */
#include <stdarg.h>
/* Argument types */
typedef enum
{
TYPE_NONE,
TYPE_SCHAR,
TYPE_UCHAR,
TYPE_SHORT,
TYPE_USHORT,
TYPE_INT,
TYPE_UINT,
TYPE_LONGINT,
TYPE_ULONGINT,
#if HAVE_LONG_LONG_INT
TYPE_LONGLONGINT,
TYPE_ULONGLONGINT,
#endif
TYPE_DOUBLE,
TYPE_LONGDOUBLE,
TYPE_CHAR,
#if HAVE_WINT_T
TYPE_WIDE_CHAR,
#endif
TYPE_STRING,
#if HAVE_WCHAR_T
TYPE_WIDE_STRING,
#endif
TYPE_POINTER,
TYPE_COUNT_SCHAR_POINTER,
TYPE_COUNT_SHORT_POINTER,
TYPE_COUNT_INT_POINTER,
TYPE_COUNT_LONGINT_POINTER
#if HAVE_LONG_LONG_INT
, TYPE_COUNT_LONGLONGINT_POINTER
#endif
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
, TYPE_U8_STRING
, TYPE_U16_STRING
, TYPE_U32_STRING
#endif
} arg_type;
/* Polymorphic argument */
typedef struct
{
arg_type type;
union
{
signed char a_schar;
unsigned char a_uchar;
short a_short;
unsigned short a_ushort;
int a_int;
unsigned int a_uint;
long int a_longint;
unsigned long int a_ulongint;
#if HAVE_LONG_LONG_INT
long long int a_longlongint;
unsigned long long int a_ulonglongint;
#endif
float a_float;
double a_double;
long double a_longdouble;
int a_char;
#if HAVE_WINT_T
wint_t a_wide_char;
#endif
const char* a_string;
#if HAVE_WCHAR_T
const wchar_t* a_wide_string;
#endif
void* a_pointer;
signed char * a_count_schar_pointer;
short * a_count_short_pointer;
int * a_count_int_pointer;
long int * a_count_longint_pointer;
#if HAVE_LONG_LONG_INT
long long int * a_count_longlongint_pointer;
#endif
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
const uint8_t * a_u8_string;
const uint16_t * a_u16_string;
const uint32_t * a_u32_string;
#endif
}
a;
}
argument;
typedef struct
{
size_t count;
argument *arg;
}
arguments;
/* Fetch the arguments, putting them into a. */
#ifdef STATIC
STATIC
#else
extern
#endif
int PRINTF_FETCHARGS (va_list args, arguments *a);
#endif /* _PRINTF_ARGS_H */
+599
View File
@@ -0,0 +1,599 @@
/* Formatted output to strings.
Copyright (C) 1999-2000, 2002-2003, 2006-2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* This file can be parametrized with the following macros:
CHAR_T The element type of the format string.
CHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters
in the format string are ASCII.
DIRECTIVE Structure denoting a format directive.
Depends on CHAR_T.
DIRECTIVES Structure denoting the set of format directives of a
format string. Depends on CHAR_T.
PRINTF_PARSE Function that parses a format string.
Depends on CHAR_T.
STATIC Set to 'static' to declare the function static.
ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions. */
#ifndef PRINTF_PARSE
# include <config.h>
#endif
/* Specification. */
#ifndef PRINTF_PARSE
# include "printf-parse.h"
#endif
/* Default parameters. */
#ifndef PRINTF_PARSE
# define PRINTF_PARSE printf_parse
# define CHAR_T char
# define DIRECTIVE char_directive
# define DIRECTIVES char_directives
#endif
/* Get size_t, NULL. */
#include <stddef.h>
/* Get intmax_t. */
#if defined IN_LIBINTL || defined IN_LIBASPRINTF
# if HAVE_STDINT_H_WITH_UINTMAX
# include <stdint.h>
# endif
# if HAVE_INTTYPES_H_WITH_UINTMAX
# include <inttypes.h>
# endif
#else
# include <stdint.h>
#endif
/* malloc(), realloc(), free(). */
#include <stdlib.h>
/* errno. */
#include <errno.h>
/* Checked size_t computations. */
#include "xsize.h"
#if CHAR_T_ONLY_ASCII
/* c_isascii(). */
# include "c-ctype.h"
#endif
#ifdef STATIC
STATIC
#endif
int
PRINTF_PARSE (const CHAR_T * format, DIRECTIVES * d, arguments * a)
{
const CHAR_T *cp = format; /* pointer into format */
size_t arg_posn = 0; /* number of regular arguments consumed */
size_t d_allocated; /* allocated elements of d->dir */
size_t a_allocated; /* allocated elements of a->arg */
size_t max_width_length = 0;
size_t max_precision_length = 0;
d->count = 0;
d_allocated = 1;
d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE));
if (d->dir == NULL)
/* Out of memory. */
goto out_of_memory_1;
a->count = 0;
a_allocated = 0;
a->arg = NULL;
#define REGISTER_ARG(_index_,_type_) \
{ \
size_t n = (_index_); \
if (n >= a_allocated) \
{ \
size_t memory_size; \
argument *memory; \
\
a_allocated = xtimes (a_allocated, 2); \
if (a_allocated <= n) \
a_allocated = xsum (n, 1); \
memory_size = xtimes (a_allocated, sizeof (argument)); \
if (size_overflow_p (memory_size)) \
/* Overflow, would lead to out of memory. */ \
goto out_of_memory; \
memory = (argument *) (a->arg \
? realloc (a->arg, memory_size) \
: malloc (memory_size)); \
if (memory == NULL) \
/* Out of memory. */ \
goto out_of_memory; \
a->arg = memory; \
} \
while (a->count <= n) \
a->arg[a->count++].type = TYPE_NONE; \
if (a->arg[n].type == TYPE_NONE) \
a->arg[n].type = (_type_); \
else if (a->arg[n].type != (_type_)) \
/* Ambiguous type for positional argument. */ \
goto error; \
}
while (*cp != '\0')
{
CHAR_T c = *cp++;
if (c == '%')
{
size_t arg_index = ARG_NONE;
DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
/* Initialize the next directive. */
dp->dir_start = cp - 1;
dp->flags = 0;
dp->width_start = NULL;
dp->width_end = NULL;
dp->width_arg_index = ARG_NONE;
dp->precision_start = NULL;
dp->precision_end = NULL;
dp->precision_arg_index = ARG_NONE;
dp->arg_index = ARG_NONE;
/* Test for positional argument. */
if (*cp >= '0' && *cp <= '9')
{
const CHAR_T *np;
for (np = cp; *np >= '0' && *np <= '9'; np++)
;
if (*np == '$')
{
size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory later. */
goto error;
arg_index = n - 1;
cp = np + 1;
}
}
/* Read the flags. */
for (;;)
{
if (*cp == '\'')
{
dp->flags |= FLAG_GROUP;
cp++;
}
else if (*cp == '-')
{
dp->flags |= FLAG_LEFT;
cp++;
}
else if (*cp == '+')
{
dp->flags |= FLAG_SHOWSIGN;
cp++;
}
else if (*cp == ' ')
{
dp->flags |= FLAG_SPACE;
cp++;
}
else if (*cp == '#')
{
dp->flags |= FLAG_ALT;
cp++;
}
else if (*cp == '0')
{
dp->flags |= FLAG_ZERO;
cp++;
}
else
break;
}
/* Parse the field width. */
if (*cp == '*')
{
dp->width_start = cp;
cp++;
dp->width_end = cp;
if (max_width_length < 1)
max_width_length = 1;
/* Test for positional argument. */
if (*cp >= '0' && *cp <= '9')
{
const CHAR_T *np;
for (np = cp; *np >= '0' && *np <= '9'; np++)
;
if (*np == '$')
{
size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory later. */
goto error;
dp->width_arg_index = n - 1;
cp = np + 1;
}
}
if (dp->width_arg_index == ARG_NONE)
{
dp->width_arg_index = arg_posn++;
if (dp->width_arg_index == ARG_NONE)
/* arg_posn wrapped around. */
goto error;
}
REGISTER_ARG (dp->width_arg_index, TYPE_INT);
}
else if (*cp >= '0' && *cp <= '9')
{
size_t width_length;
dp->width_start = cp;
for (; *cp >= '0' && *cp <= '9'; cp++)
;
dp->width_end = cp;
width_length = dp->width_end - dp->width_start;
if (max_width_length < width_length)
max_width_length = width_length;
}
/* Parse the precision. */
if (*cp == '.')
{
cp++;
if (*cp == '*')
{
dp->precision_start = cp - 1;
cp++;
dp->precision_end = cp;
if (max_precision_length < 2)
max_precision_length = 2;
/* Test for positional argument. */
if (*cp >= '0' && *cp <= '9')
{
const CHAR_T *np;
for (np = cp; *np >= '0' && *np <= '9'; np++)
;
if (*np == '$')
{
size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory
later. */
goto error;
dp->precision_arg_index = n - 1;
cp = np + 1;
}
}
if (dp->precision_arg_index == ARG_NONE)
{
dp->precision_arg_index = arg_posn++;
if (dp->precision_arg_index == ARG_NONE)
/* arg_posn wrapped around. */
goto error;
}
REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
}
else
{
size_t precision_length;
dp->precision_start = cp - 1;
for (; *cp >= '0' && *cp <= '9'; cp++)
;
dp->precision_end = cp;
precision_length = dp->precision_end - dp->precision_start;
if (max_precision_length < precision_length)
max_precision_length = precision_length;
}
}
{
arg_type type;
/* Parse argument type/size specifiers. */
{
int flags = 0;
for (;;)
{
if (*cp == 'h')
{
flags |= (1 << (flags & 1));
cp++;
}
else if (*cp == 'L')
{
flags |= 4;
cp++;
}
else if (*cp == 'l')
{
flags += 8;
cp++;
}
else if (*cp == 'j')
{
if (sizeof (intmax_t) > sizeof (long))
{
/* intmax_t = long long */
flags += 16;
}
else if (sizeof (intmax_t) > sizeof (int))
{
/* intmax_t = long */
flags += 8;
}
cp++;
}
else if (*cp == 'z' || *cp == 'Z')
{
/* 'z' is standardized in ISO C 99, but glibc uses 'Z'
because the warning facility in gcc-2.95.2 understands
only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
if (sizeof (size_t) > sizeof (long))
{
/* size_t = long long */
flags += 16;
}
else if (sizeof (size_t) > sizeof (int))
{
/* size_t = long */
flags += 8;
}
cp++;
}
else if (*cp == 't')
{
if (sizeof (ptrdiff_t) > sizeof (long))
{
/* ptrdiff_t = long long */
flags += 16;
}
else if (sizeof (ptrdiff_t) > sizeof (int))
{
/* ptrdiff_t = long */
flags += 8;
}
cp++;
}
else
break;
}
/* Read the conversion character. */
c = *cp++;
switch (c)
{
case 'd':
case 'i':
#if HAVE_LONG_LONG_INT
/* If 'long long' exists and is larger than 'long': */
if (flags >= 16 || (flags & 4))
type = TYPE_LONGLONGINT;
else
#endif
/* If 'long long' exists and is the same as 'long', we parse
"lld" into TYPE_LONGINT. */
if (flags >= 8)
type = TYPE_LONGINT;
else if (flags & 2)
type = TYPE_SCHAR;
else if (flags & 1)
type = TYPE_SHORT;
else
type = TYPE_INT;
break;
case 'o':
case 'u':
case 'x':
case 'X':
#if HAVE_LONG_LONG_INT
/* If 'long long' exists and is larger than 'long': */
if (flags >= 16 || (flags & 4))
type = TYPE_ULONGLONGINT;
else
#endif
/* If 'unsigned long long' exists and is the same as
'unsigned long', we parse "llu" into TYPE_ULONGINT. */
if (flags >= 8)
type = TYPE_ULONGINT;
else if (flags & 2)
type = TYPE_UCHAR;
else if (flags & 1)
type = TYPE_USHORT;
else
type = TYPE_UINT;
break;
case 'f':
case 'F':
case 'e':
case 'E':
case 'g':
case 'G':
case 'a':
case 'A':
if (flags >= 16 || (flags & 4))
type = TYPE_LONGDOUBLE;
else
type = TYPE_DOUBLE;
break;
case 'c':
if (flags >= 8)
#if HAVE_WINT_T
type = TYPE_WIDE_CHAR;
#else
goto error;
#endif
else
type = TYPE_CHAR;
break;
#if HAVE_WINT_T
case 'C':
type = TYPE_WIDE_CHAR;
c = 'c';
break;
#endif
case 's':
if (flags >= 8)
#if HAVE_WCHAR_T
type = TYPE_WIDE_STRING;
#else
goto error;
#endif
else
type = TYPE_STRING;
break;
#if HAVE_WCHAR_T
case 'S':
type = TYPE_WIDE_STRING;
c = 's';
break;
#endif
case 'p':
type = TYPE_POINTER;
break;
case 'n':
#if HAVE_LONG_LONG_INT
/* If 'long long' exists and is larger than 'long': */
if (flags >= 16 || (flags & 4))
type = TYPE_COUNT_LONGLONGINT_POINTER;
else
#endif
/* If 'long long' exists and is the same as 'long', we parse
"lln" into TYPE_COUNT_LONGINT_POINTER. */
if (flags >= 8)
type = TYPE_COUNT_LONGINT_POINTER;
else if (flags & 2)
type = TYPE_COUNT_SCHAR_POINTER;
else if (flags & 1)
type = TYPE_COUNT_SHORT_POINTER;
else
type = TYPE_COUNT_INT_POINTER;
break;
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
case 'U':
if (flags >= 16)
type = TYPE_U32_STRING;
else if (flags >= 8)
type = TYPE_U16_STRING;
else
type = TYPE_U8_STRING;
break;
#endif
case '%':
type = TYPE_NONE;
break;
default:
/* Unknown conversion character. */
goto error;
}
}
if (type != TYPE_NONE)
{
dp->arg_index = arg_index;
if (dp->arg_index == ARG_NONE)
{
dp->arg_index = arg_posn++;
if (dp->arg_index == ARG_NONE)
/* arg_posn wrapped around. */
goto error;
}
REGISTER_ARG (dp->arg_index, type);
}
dp->conversion = c;
dp->dir_end = cp;
}
d->count++;
if (d->count >= d_allocated)
{
size_t memory_size;
DIRECTIVE *memory;
d_allocated = xtimes (d_allocated, 2);
memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
if (size_overflow_p (memory_size))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
memory = (DIRECTIVE *) realloc (d->dir, memory_size);
if (memory == NULL)
/* Out of memory. */
goto out_of_memory;
d->dir = memory;
}
}
#if CHAR_T_ONLY_ASCII
else if (!c_isascii (c))
{
/* Non-ASCII character. Not supported. */
goto error;
}
#endif
}
d->dir[d->count].dir_start = cp;
d->max_width_length = max_width_length;
d->max_precision_length = max_precision_length;
return 0;
error:
if (a->arg)
free (a->arg);
if (d->dir)
free (d->dir);
errno = EINVAL;
return -1;
out_of_memory:
if (a->arg)
free (a->arg);
if (d->dir)
free (d->dir);
out_of_memory_1:
errno = ENOMEM;
return -1;
}
#undef PRINTF_PARSE
#undef DIRECTIVES
#undef DIRECTIVE
#undef CHAR_T_ONLY_ASCII
#undef CHAR_T
+178
View File
@@ -0,0 +1,178 @@
/* Parse printf format string.
Copyright (C) 1999, 2002-2003, 2005, 2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _PRINTF_PARSE_H
#define _PRINTF_PARSE_H
/* This file can be parametrized with the following macros:
ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions.
STATIC Set to 'static' to declare the function static. */
#include "printf-args.h"
/* Flags */
#define FLAG_GROUP 1 /* ' flag */
#define FLAG_LEFT 2 /* - flag */
#define FLAG_SHOWSIGN 4 /* + flag */
#define FLAG_SPACE 8 /* space flag */
#define FLAG_ALT 16 /* # flag */
#define FLAG_ZERO 32
/* arg_index value indicating that no argument is consumed. */
#define ARG_NONE (~(size_t)0)
/* xxx_directive: A parsed directive.
xxx_directives: A parsed format string. */
/* A parsed directive. */
typedef struct
{
const char* dir_start;
const char* dir_end;
int flags;
const char* width_start;
const char* width_end;
size_t width_arg_index;
const char* precision_start;
const char* precision_end;
size_t precision_arg_index;
char conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */
size_t arg_index;
}
char_directive;
/* A parsed format string. */
typedef struct
{
size_t count;
char_directive *dir;
size_t max_width_length;
size_t max_precision_length;
}
char_directives;
#if ENABLE_UNISTDIO
/* A parsed directive. */
typedef struct
{
const uint8_t* dir_start;
const uint8_t* dir_end;
int flags;
const uint8_t* width_start;
const uint8_t* width_end;
size_t width_arg_index;
const uint8_t* precision_start;
const uint8_t* precision_end;
size_t precision_arg_index;
uint8_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */
size_t arg_index;
}
u8_directive;
/* A parsed format string. */
typedef struct
{
size_t count;
u8_directive *dir;
size_t max_width_length;
size_t max_precision_length;
}
u8_directives;
/* A parsed directive. */
typedef struct
{
const uint16_t* dir_start;
const uint16_t* dir_end;
int flags;
const uint16_t* width_start;
const uint16_t* width_end;
size_t width_arg_index;
const uint16_t* precision_start;
const uint16_t* precision_end;
size_t precision_arg_index;
uint16_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */
size_t arg_index;
}
u16_directive;
/* A parsed format string. */
typedef struct
{
size_t count;
u16_directive *dir;
size_t max_width_length;
size_t max_precision_length;
}
u16_directives;
/* A parsed directive. */
typedef struct
{
const uint32_t* dir_start;
const uint32_t* dir_end;
int flags;
const uint32_t* width_start;
const uint32_t* width_end;
size_t width_arg_index;
const uint32_t* precision_start;
const uint32_t* precision_end;
size_t precision_arg_index;
uint32_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */
size_t arg_index;
}
u32_directive;
/* A parsed format string. */
typedef struct
{
size_t count;
u32_directive *dir;
size_t max_width_length;
size_t max_precision_length;
}
u32_directives;
#endif
/* Parses the format string. Fills in the number N of directives, and fills
in directives[0], ..., directives[N-1], and sets directives[N].dir_start
to the end of the format string. Also fills in the arg_type fields of the
arguments and the needed count of arguments. */
#if ENABLE_UNISTDIO
extern int
ulc_printf_parse (const char *format, char_directives *d, arguments *a);
extern int
u8_printf_parse (const uint8_t *format, u8_directives *d, arguments *a);
extern int
u16_printf_parse (const uint16_t *format, u16_directives *d,
arguments *a);
extern int
u32_printf_parse (const uint32_t *format, u32_directives *d,
arguments *a);
#else
# ifdef STATIC
STATIC
# else
extern
# endif
int printf_parse (const char *format, char_directives *d, arguments *a);
#endif
#endif /* _PRINTF_PARSE_H */
+136
View File
@@ -0,0 +1,136 @@
/* read-file.c -- read file contents into a string
Copyright (C) 2006 Free Software Foundation, Inc.
Written by Simon Josefsson and Bruno Haible.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <config.h>
#include "read-file.h"
/* Get realloc, free. */
#include <stdlib.h>
/* Get errno. */
#include <errno.h>
/* Read a STREAM and return a newly allocated string with the content,
and set *LENGTH to the length of the string. The string is
zero-terminated, but the terminating zero byte is not counted in
*LENGTH. On errors, *LENGTH is undefined, errno preserves the
values set by system functions (if any), and NULL is returned. */
char *
fread_file (FILE * stream, size_t * length)
{
char *buf = NULL;
size_t alloc = 0;
size_t size = 0;
int save_errno;
for (;;)
{
size_t count;
size_t requested;
if (size + BUFSIZ + 1 > alloc)
{
char *new_buf;
alloc += alloc / 2;
if (alloc < size + BUFSIZ + 1)
alloc = size + BUFSIZ + 1;
new_buf = realloc (buf, alloc);
if (!new_buf)
{
save_errno = errno;
break;
}
buf = new_buf;
}
requested = alloc - size - 1;
count = fread (buf + size, 1, requested, stream);
size += count;
if (count != requested)
{
save_errno = errno;
if (ferror (stream))
break;
buf[size] = '\0';
*length = size;
return buf;
}
}
free (buf);
errno = save_errno;
return NULL;
}
static char *
internal_read_file (const char *filename, size_t * length, const char *mode)
{
FILE *stream = fopen (filename, mode);
char *out;
int save_errno;
if (!stream)
return NULL;
out = fread_file (stream, length);
save_errno = errno;
if (fclose (stream) != 0)
{
if (out)
{
save_errno = errno;
free (out);
}
errno = save_errno;
return NULL;
}
return out;
}
/* Open and read the contents of FILENAME, and return a newly
allocated string with the content, and set *LENGTH to the length of
the string. The string is zero-terminated, but the terminating
zero byte is not counted in *LENGTH. On errors, *LENGTH is
undefined, errno preserves the values set by system functions (if
any), and NULL is returned. */
char *
read_file (const char *filename, size_t * length)
{
return internal_read_file (filename, length, "r");
}
/* Open (on non-POSIX systems, in binary mode) and read the contents
of FILENAME, and return a newly allocated string with the content,
and set LENGTH to the length of the string. The string is
zero-terminated, but the terminating zero byte is not counted in
the LENGTH variable. On errors, *LENGTH is undefined, errno
preserves the values set by system functions (if any), and NULL is
returned. */
char *
read_binary_file (const char *filename, size_t * length)
{
return internal_read_file (filename, length, "rb");
}
+34
View File
@@ -0,0 +1,34 @@
/* read-file.h -- read file contents into a string
Copyright (C) 2006 Free Software Foundation, Inc.
Written by Simon Josefsson.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef READ_FILE_H
#define READ_FILE_H
/* Get size_t. */
#include <stddef.h>
/* Get FILE. */
#include <stdio.h>
extern char *fread_file (FILE * stream, size_t * length);
extern char *read_file (const char *filename, size_t * length);
extern char *read_binary_file (const char *filename, size_t * length);
#endif /* READ_FILE_H */
+87
View File
@@ -0,0 +1,87 @@
/* realloc() function that is glibc compatible.
Copyright (C) 1997, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* written by Jim Meyering and Bruno Haible */
#include <config.h>
/* Only the AC_FUNC_REALLOC macro defines 'realloc' already in config.h. */
#ifdef realloc
# define NEED_REALLOC_GNU 1
#endif
/* Infer the properties of the system's malloc function.
Only the AC_FUNC_MALLOC macro defines 'malloc' already in config.h. */
#if GNULIB_MALLOC_GNU && !defined malloc
# define SYSTEM_MALLOC_GLIBC_COMPATIBLE 1
#endif
/* Below we want to call the system's malloc and realloc.
Undefine the symbols here so that including <stdlib.h> provides a
declaration of malloc(), not of rpl_malloc(), and likewise for realloc. */
#undef malloc
#undef realloc
/* Specification. */
#include <stdlib.h>
#include <errno.h>
/* Below we want to call the system's malloc and realloc.
Undefine the symbols, if they were defined by gnulib's <stdlib.h>
replacement. */
#undef malloc
#undef realloc
/* Change the size of an allocated block of memory P to N bytes,
with error checking. If N is zero, change it to 1. If P is NULL,
use malloc. */
void *
rpl_realloc (void *p, size_t n)
{
void *result;
#if NEED_REALLOC_GNU
if (n == 0)
{
n = 1;
/* In theory realloc might fail, so don't rely on it to free. */
free (p);
p = NULL;
}
#endif
if (p == NULL)
{
#if GNULIB_REALLOC_GNU && !NEED_REALLOC_GNU && !SYSTEM_MALLOC_GLIBC_COMPATIBLE
if (n == 0)
n = 1;
#endif
result = malloc (n);
}
else
result = realloc (p, n);
#if !HAVE_REALLOC_POSIX
if (result == NULL)
errno = ENOMEM;
#endif
return result;
}
+1083
View File
@@ -0,0 +1,1083 @@
/* rijndael-alg-fst.c --- Rijndael cipher implementation.
* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Adapted for gnulib by Simon Josefsson.
*
* Based on public domain "Optimised C code" retrieved from (SHA1
* 7c8e4b00d06685d1dbc6724a9e0d502353de339e):
* http://www.iaik.tu-graz.ac.at/research/krypto/AES/old/~rijmen/rijndael/rijndael-fst-3.0.zip
*/
#include <config.h>
/**
* rijndael-alg-fst.c
*
* @version 3.0 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "rijndael-alg-fst.h"
/*
Te0[x] = S [x].[02, 01, 01, 03];
Te1[x] = S [x].[03, 02, 01, 01];
Te2[x] = S [x].[01, 03, 02, 01];
Te3[x] = S [x].[01, 01, 03, 02];
Te4[x] = S [x].[01, 01, 01, 01];
Td0[x] = Si[x].[0e, 09, 0d, 0b];
Td1[x] = Si[x].[0b, 0e, 09, 0d];
Td2[x] = Si[x].[0d, 0b, 0e, 09];
Td3[x] = Si[x].[09, 0d, 0b, 0e];
Td4[x] = Si[x].[01, 01, 01, 01];
*/
static const uint32_t Te0[256] = {
0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d,
0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d,
0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87,
0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea,
0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108,
0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e,
0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d,
0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e,
0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce,
0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c,
0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b,
0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16,
0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a,
0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163,
0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f,
0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47,
0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f,
0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c,
0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e,
0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6,
0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25,
0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72,
0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21,
0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa,
0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0,
0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133,
0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920,
0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17,
0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
};
static const uint32_t Te1[256] = {
0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b,
0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b,
0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d,
0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf,
0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626,
0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1,
0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3,
0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2,
0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a,
0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3,
0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded,
0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939,
0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb,
0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f,
0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f,
0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121,
0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec,
0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d,
0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc,
0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414,
0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a,
0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262,
0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d,
0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea,
0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e,
0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f,
0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666,
0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9,
0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111,
0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9,
0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d,
0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f,
0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
};
static const uint32_t Te2[256] = {
0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b,
0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b,
0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d,
0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af,
0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26,
0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1,
0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3,
0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2,
0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a,
0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3,
0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed,
0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239,
0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb,
0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f,
0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f,
0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221,
0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec,
0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d,
0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc,
0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814,
0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a,
0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462,
0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d,
0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea,
0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e,
0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f,
0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66,
0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9,
0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211,
0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9,
0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d,
0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f,
0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
};
static const uint32_t Te3[256] = {
0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6,
0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56,
0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa,
0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45,
0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c,
0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9,
0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d,
0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf,
0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34,
0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d,
0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1,
0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72,
0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed,
0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe,
0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05,
0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342,
0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3,
0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a,
0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3,
0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28,
0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14,
0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4,
0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da,
0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf,
0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c,
0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e,
0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc,
0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069,
0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322,
0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9,
0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a,
0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e,
0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
};
static const uint32_t Te4[256] = {
0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b,
0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5,
0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b,
0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676,
0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d,
0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0,
0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf,
0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0,
0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626,
0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc,
0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1,
0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515,
0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3,
0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a,
0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2,
0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575,
0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a,
0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0,
0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3,
0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484,
0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed,
0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b,
0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939,
0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf,
0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb,
0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585,
0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f,
0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8,
0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f,
0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5,
0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121,
0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2,
0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec,
0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717,
0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d,
0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373,
0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc,
0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888,
0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414,
0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb,
0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a,
0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c,
0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262,
0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979,
0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d,
0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9,
0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea,
0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808,
0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e,
0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6,
0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f,
0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a,
0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666,
0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e,
0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9,
0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e,
0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111,
0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494,
0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9,
0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf,
0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d,
0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868,
0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f,
0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616,
};
static const uint32_t Td0[256] = {
0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96,
0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25,
0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1,
0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da,
0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd,
0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45,
0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7,
0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5,
0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1,
0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75,
0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46,
0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77,
0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000,
0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927,
0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e,
0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d,
0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd,
0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163,
0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d,
0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422,
0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36,
0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662,
0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3,
0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8,
0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6,
0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815,
0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df,
0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e,
0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89,
0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf,
0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f,
0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190,
0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
};
static const uint32_t Td1[256] = {
0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e,
0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c,
0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0,
0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259,
0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971,
0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f,
0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8,
0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708,
0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2,
0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb,
0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd,
0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e,
0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000,
0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39,
0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91,
0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17,
0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60,
0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1,
0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1,
0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964,
0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b,
0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46,
0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512,
0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a,
0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c,
0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8,
0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604,
0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41,
0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c,
0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737,
0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340,
0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1,
0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
};
static const uint32_t Td2[256] = {
0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27,
0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502,
0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe,
0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552,
0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9,
0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253,
0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b,
0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337,
0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69,
0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6,
0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6,
0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9,
0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000,
0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d,
0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b,
0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b,
0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f,
0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4,
0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729,
0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9,
0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4,
0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e,
0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25,
0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f,
0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0,
0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7,
0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496,
0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b,
0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13,
0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7,
0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3,
0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456,
0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
};
static const uint32_t Td3[256] = {
0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a,
0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5,
0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d,
0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95,
0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27,
0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562,
0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752,
0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3,
0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e,
0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4,
0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d,
0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767,
0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000,
0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736,
0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b,
0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12,
0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3,
0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8,
0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7,
0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247,
0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698,
0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254,
0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf,
0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883,
0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629,
0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533,
0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4,
0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb,
0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb,
0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73,
0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2,
0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064,
0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
};
static const uint32_t Td4[256] = {
0x52525252, 0x09090909, 0x6a6a6a6a, 0xd5d5d5d5,
0x30303030, 0x36363636, 0xa5a5a5a5, 0x38383838,
0xbfbfbfbf, 0x40404040, 0xa3a3a3a3, 0x9e9e9e9e,
0x81818181, 0xf3f3f3f3, 0xd7d7d7d7, 0xfbfbfbfb,
0x7c7c7c7c, 0xe3e3e3e3, 0x39393939, 0x82828282,
0x9b9b9b9b, 0x2f2f2f2f, 0xffffffff, 0x87878787,
0x34343434, 0x8e8e8e8e, 0x43434343, 0x44444444,
0xc4c4c4c4, 0xdededede, 0xe9e9e9e9, 0xcbcbcbcb,
0x54545454, 0x7b7b7b7b, 0x94949494, 0x32323232,
0xa6a6a6a6, 0xc2c2c2c2, 0x23232323, 0x3d3d3d3d,
0xeeeeeeee, 0x4c4c4c4c, 0x95959595, 0x0b0b0b0b,
0x42424242, 0xfafafafa, 0xc3c3c3c3, 0x4e4e4e4e,
0x08080808, 0x2e2e2e2e, 0xa1a1a1a1, 0x66666666,
0x28282828, 0xd9d9d9d9, 0x24242424, 0xb2b2b2b2,
0x76767676, 0x5b5b5b5b, 0xa2a2a2a2, 0x49494949,
0x6d6d6d6d, 0x8b8b8b8b, 0xd1d1d1d1, 0x25252525,
0x72727272, 0xf8f8f8f8, 0xf6f6f6f6, 0x64646464,
0x86868686, 0x68686868, 0x98989898, 0x16161616,
0xd4d4d4d4, 0xa4a4a4a4, 0x5c5c5c5c, 0xcccccccc,
0x5d5d5d5d, 0x65656565, 0xb6b6b6b6, 0x92929292,
0x6c6c6c6c, 0x70707070, 0x48484848, 0x50505050,
0xfdfdfdfd, 0xedededed, 0xb9b9b9b9, 0xdadadada,
0x5e5e5e5e, 0x15151515, 0x46464646, 0x57575757,
0xa7a7a7a7, 0x8d8d8d8d, 0x9d9d9d9d, 0x84848484,
0x90909090, 0xd8d8d8d8, 0xabababab, 0x00000000,
0x8c8c8c8c, 0xbcbcbcbc, 0xd3d3d3d3, 0x0a0a0a0a,
0xf7f7f7f7, 0xe4e4e4e4, 0x58585858, 0x05050505,
0xb8b8b8b8, 0xb3b3b3b3, 0x45454545, 0x06060606,
0xd0d0d0d0, 0x2c2c2c2c, 0x1e1e1e1e, 0x8f8f8f8f,
0xcacacaca, 0x3f3f3f3f, 0x0f0f0f0f, 0x02020202,
0xc1c1c1c1, 0xafafafaf, 0xbdbdbdbd, 0x03030303,
0x01010101, 0x13131313, 0x8a8a8a8a, 0x6b6b6b6b,
0x3a3a3a3a, 0x91919191, 0x11111111, 0x41414141,
0x4f4f4f4f, 0x67676767, 0xdcdcdcdc, 0xeaeaeaea,
0x97979797, 0xf2f2f2f2, 0xcfcfcfcf, 0xcececece,
0xf0f0f0f0, 0xb4b4b4b4, 0xe6e6e6e6, 0x73737373,
0x96969696, 0xacacacac, 0x74747474, 0x22222222,
0xe7e7e7e7, 0xadadadad, 0x35353535, 0x85858585,
0xe2e2e2e2, 0xf9f9f9f9, 0x37373737, 0xe8e8e8e8,
0x1c1c1c1c, 0x75757575, 0xdfdfdfdf, 0x6e6e6e6e,
0x47474747, 0xf1f1f1f1, 0x1a1a1a1a, 0x71717171,
0x1d1d1d1d, 0x29292929, 0xc5c5c5c5, 0x89898989,
0x6f6f6f6f, 0xb7b7b7b7, 0x62626262, 0x0e0e0e0e,
0xaaaaaaaa, 0x18181818, 0xbebebebe, 0x1b1b1b1b,
0xfcfcfcfc, 0x56565656, 0x3e3e3e3e, 0x4b4b4b4b,
0xc6c6c6c6, 0xd2d2d2d2, 0x79797979, 0x20202020,
0x9a9a9a9a, 0xdbdbdbdb, 0xc0c0c0c0, 0xfefefefe,
0x78787878, 0xcdcdcdcd, 0x5a5a5a5a, 0xf4f4f4f4,
0x1f1f1f1f, 0xdddddddd, 0xa8a8a8a8, 0x33333333,
0x88888888, 0x07070707, 0xc7c7c7c7, 0x31313131,
0xb1b1b1b1, 0x12121212, 0x10101010, 0x59595959,
0x27272727, 0x80808080, 0xecececec, 0x5f5f5f5f,
0x60606060, 0x51515151, 0x7f7f7f7f, 0xa9a9a9a9,
0x19191919, 0xb5b5b5b5, 0x4a4a4a4a, 0x0d0d0d0d,
0x2d2d2d2d, 0xe5e5e5e5, 0x7a7a7a7a, 0x9f9f9f9f,
0x93939393, 0xc9c9c9c9, 0x9c9c9c9c, 0xefefefef,
0xa0a0a0a0, 0xe0e0e0e0, 0x3b3b3b3b, 0x4d4d4d4d,
0xaeaeaeae, 0x2a2a2a2a, 0xf5f5f5f5, 0xb0b0b0b0,
0xc8c8c8c8, 0xebebebeb, 0xbbbbbbbb, 0x3c3c3c3c,
0x83838383, 0x53535353, 0x99999999, 0x61616161,
0x17171717, 0x2b2b2b2b, 0x04040404, 0x7e7e7e7e,
0xbabababa, 0x77777777, 0xd6d6d6d6, 0x26262626,
0xe1e1e1e1, 0x69696969, 0x14141414, 0x63636363,
0x55555555, 0x21212121, 0x0c0c0c0c, 0x7d7d7d7d,
};
static const uint32_t rcon[] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000
/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
#define GETU32(pt) (((uint32_t)((pt)[0] & 0xFF) << 24) ^ \
((uint32_t)((pt)[1] & 0xFF) << 16) ^ \
((uint32_t)((pt)[2] & 0xFF) << 8) ^ \
((uint32_t)((pt)[3] & 0xFF)))
#define PUTU32(ct, st) { \
(ct)[0] = (char)((st) >> 24); \
(ct)[1] = (char)((st) >> 16); \
(ct)[2] = (char)((st) >> 8); \
(ct)[3] = (char)(st); }
/**
* Expand the cipher key into the encryption key schedule.
*
* @return the number of rounds for the given cipher key size.
*/
int
rijndaelKeySetupEnc (uint32_t rk[ /*4*(Nr + 1) */ ],
const char cipherKey[], size_t keyBits)
{
size_t i = 0;
uint32_t temp;
rk[0] = GETU32 (cipherKey);
rk[1] = GETU32 (cipherKey + 4);
rk[2] = GETU32 (cipherKey + 8);
rk[3] = GETU32 (cipherKey + 12);
if (keyBits == 128)
{
for (;;)
{
temp = rk[3];
rk[4] = rk[0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i];
rk[5] = rk[1] ^ rk[4];
rk[6] = rk[2] ^ rk[5];
rk[7] = rk[3] ^ rk[6];
if (++i == 10)
{
return 10;
}
rk += 4;
}
}
rk[4] = GETU32 (cipherKey + 16);
rk[5] = GETU32 (cipherKey + 20);
if (keyBits == 192)
{
for (;;)
{
temp = rk[5];
rk[6] = rk[0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i];
rk[7] = rk[1] ^ rk[6];
rk[8] = rk[2] ^ rk[7];
rk[9] = rk[3] ^ rk[8];
if (++i == 8)
{
return 12;
}
rk[10] = rk[4] ^ rk[9];
rk[11] = rk[5] ^ rk[10];
rk += 6;
}
}
rk[6] = GETU32 (cipherKey + 24);
rk[7] = GETU32 (cipherKey + 28);
if (keyBits == 256)
{
for (;;)
{
temp = rk[7];
rk[8] = rk[0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i];
rk[9] = rk[1] ^ rk[8];
rk[10] = rk[2] ^ rk[9];
rk[11] = rk[3] ^ rk[10];
if (++i == 7)
{
return 14;
}
temp = rk[11];
rk[12] = rk[4] ^
(Te4[(temp >> 24)] & 0xff000000) ^
(Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(temp) & 0xff] & 0x000000ff);
rk[13] = rk[5] ^ rk[12];
rk[14] = rk[6] ^ rk[13];
rk[15] = rk[7] ^ rk[14];
rk += 8;
}
}
return 0;
}
/**
* Expand the cipher key into the decryption key schedule.
*
* @return the number of rounds for the given cipher key size.
*/
int
rijndaelKeySetupDec (uint32_t rk[ /*4*(Nr + 1) */ ],
const char cipherKey[], size_t keyBits)
{
size_t Nr, i, j;
uint32_t temp;
/* expand the cipher key: */
Nr = rijndaelKeySetupEnc (rk, cipherKey, keyBits);
/* invert the order of the round keys: */
for (i = 0, j = 4 * Nr; i < j; i += 4, j -= 4)
{
temp = rk[i];
rk[i] = rk[j];
rk[j] = temp;
temp = rk[i + 1];
rk[i + 1] = rk[j + 1];
rk[j + 1] = temp;
temp = rk[i + 2];
rk[i + 2] = rk[j + 2];
rk[j + 2] = temp;
temp = rk[i + 3];
rk[i + 3] = rk[j + 3];
rk[j + 3] = temp;
}
/* apply the inverse MixColumn transform to all round keys but the
first and the last: */
for (i = 1; i < Nr; i++)
{
rk += 4;
rk[0] =
Td0[Te4[(rk[0] >> 24)] & 0xff] ^
Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[0]) & 0xff] & 0xff];
rk[1] =
Td0[Te4[(rk[1] >> 24)] & 0xff] ^
Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[1]) & 0xff] & 0xff];
rk[2] =
Td0[Te4[(rk[2] >> 24)] & 0xff] ^
Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[2]) & 0xff] & 0xff];
rk[3] =
Td0[Te4[(rk[3] >> 24)] & 0xff] ^
Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[3]) & 0xff] & 0xff];
}
return Nr;
}
void
rijndaelEncrypt (const uint32_t rk[ /*4*(Nr + 1) */ ], size_t Nr,
const char pt[16], char ct[16])
{
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
size_t r;
/*
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32 (pt) ^ rk[0];
s1 = GETU32 (pt + 4) ^ rk[1];
s2 = GETU32 (pt + 8) ^ rk[2];
s3 = GETU32 (pt + 12) ^ rk[3];
/*
* Nr - 1 full rounds:
*/
r = Nr >> 1;
for (;;)
{
t0 =
Te0[(s0 >> 24)] ^
Te1[(s1 >> 16) & 0xff] ^
Te2[(s2 >> 8) & 0xff] ^ Te3[(s3) & 0xff] ^ rk[4];
t1 =
Te0[(s1 >> 24)] ^
Te1[(s2 >> 16) & 0xff] ^
Te2[(s3 >> 8) & 0xff] ^ Te3[(s0) & 0xff] ^ rk[5];
t2 =
Te0[(s2 >> 24)] ^
Te1[(s3 >> 16) & 0xff] ^
Te2[(s0 >> 8) & 0xff] ^ Te3[(s1) & 0xff] ^ rk[6];
t3 =
Te0[(s3 >> 24)] ^
Te1[(s0 >> 16) & 0xff] ^
Te2[(s1 >> 8) & 0xff] ^ Te3[(s2) & 0xff] ^ rk[7];
rk += 8;
if (--r == 0)
{
break;
}
s0 =
Te0[(t0 >> 24)] ^
Te1[(t1 >> 16) & 0xff] ^
Te2[(t2 >> 8) & 0xff] ^ Te3[(t3) & 0xff] ^ rk[0];
s1 =
Te0[(t1 >> 24)] ^
Te1[(t2 >> 16) & 0xff] ^
Te2[(t3 >> 8) & 0xff] ^ Te3[(t0) & 0xff] ^ rk[1];
s2 =
Te0[(t2 >> 24)] ^
Te1[(t3 >> 16) & 0xff] ^
Te2[(t0 >> 8) & 0xff] ^ Te3[(t1) & 0xff] ^ rk[2];
s3 =
Te0[(t3 >> 24)] ^
Te1[(t0 >> 16) & 0xff] ^
Te2[(t1 >> 8) & 0xff] ^ Te3[(t2) & 0xff] ^ rk[3];
}
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 =
(Te4[(t0 >> 24)] & 0xff000000) ^
(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t3) & 0xff] & 0x000000ff) ^ rk[0];
PUTU32 (ct, s0);
s1 =
(Te4[(t1 >> 24)] & 0xff000000) ^
(Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t0) & 0xff] & 0x000000ff) ^ rk[1];
PUTU32 (ct + 4, s1);
s2 =
(Te4[(t2 >> 24)] & 0xff000000) ^
(Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t1) & 0xff] & 0x000000ff) ^ rk[2];
PUTU32 (ct + 8, s2);
s3 =
(Te4[(t3 >> 24)] & 0xff000000) ^
(Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t2) & 0xff] & 0x000000ff) ^ rk[3];
PUTU32 (ct + 12, s3);
}
void
rijndaelDecrypt (const uint32_t rk[ /*4*(Nr + 1) */ ], size_t Nr,
const char ct[16], char pt[16])
{
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
size_t r;
/*
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32 (ct) ^ rk[0];
s1 = GETU32 (ct + 4) ^ rk[1];
s2 = GETU32 (ct + 8) ^ rk[2];
s3 = GETU32 (ct + 12) ^ rk[3];
/*
* Nr - 1 full rounds:
*/
r = Nr >> 1;
for (;;)
{
t0 =
Td0[(s0 >> 24)] ^
Td1[(s3 >> 16) & 0xff] ^
Td2[(s2 >> 8) & 0xff] ^ Td3[(s1) & 0xff] ^ rk[4];
t1 =
Td0[(s1 >> 24)] ^
Td1[(s0 >> 16) & 0xff] ^
Td2[(s3 >> 8) & 0xff] ^ Td3[(s2) & 0xff] ^ rk[5];
t2 =
Td0[(s2 >> 24)] ^
Td1[(s1 >> 16) & 0xff] ^
Td2[(s0 >> 8) & 0xff] ^ Td3[(s3) & 0xff] ^ rk[6];
t3 =
Td0[(s3 >> 24)] ^
Td1[(s2 >> 16) & 0xff] ^
Td2[(s1 >> 8) & 0xff] ^ Td3[(s0) & 0xff] ^ rk[7];
rk += 8;
if (--r == 0)
{
break;
}
s0 =
Td0[(t0 >> 24)] ^
Td1[(t3 >> 16) & 0xff] ^
Td2[(t2 >> 8) & 0xff] ^ Td3[(t1) & 0xff] ^ rk[0];
s1 =
Td0[(t1 >> 24)] ^
Td1[(t0 >> 16) & 0xff] ^
Td2[(t3 >> 8) & 0xff] ^ Td3[(t2) & 0xff] ^ rk[1];
s2 =
Td0[(t2 >> 24)] ^
Td1[(t1 >> 16) & 0xff] ^
Td2[(t0 >> 8) & 0xff] ^ Td3[(t3) & 0xff] ^ rk[2];
s3 =
Td0[(t3 >> 24)] ^
Td1[(t2 >> 16) & 0xff] ^
Td2[(t1 >> 8) & 0xff] ^ Td3[(t0) & 0xff] ^ rk[3];
}
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 =
(Td4[(t0 >> 24)] & 0xff000000) ^
(Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t1) & 0xff] & 0x000000ff) ^ rk[0];
PUTU32 (pt, s0);
s1 =
(Td4[(t1 >> 24)] & 0xff000000) ^
(Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t2) & 0xff] & 0x000000ff) ^ rk[1];
PUTU32 (pt + 4, s1);
s2 =
(Td4[(t2 >> 24)] & 0xff000000) ^
(Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t3) & 0xff] & 0x000000ff) ^ rk[2];
PUTU32 (pt + 8, s2);
s3 =
(Td4[(t3 >> 24)] & 0xff000000) ^
(Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t0) & 0xff] & 0x000000ff) ^ rk[3];
PUTU32 (pt + 12, s3);
}
+67
View File
@@ -0,0 +1,67 @@
/* rijndael-alg-fst.h --- Rijndael cipher implementation.
* Copyright (C) 2005 Free Software Foundation, Inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Adapted for gnulib by Simon Josefsson. */
/**
* rijndael-alg-fst.h
*
* @version 3.0 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __RIJNDAEL_ALG_FST_H
#define __RIJNDAEL_ALG_FST_H
#include <stdint.h>
#include <stddef.h>
#define RIJNDAEL_MAXKC (256/32)
#define RIJNDAEL_MAXKB (256/8)
#define RIJNDAEL_MAXNR 14
int rijndaelKeySetupEnc (uint32_t rk[ /*4*(Nr + 1) */ ],
const char cipherKey[], size_t keyBits);
int rijndaelKeySetupDec (uint32_t rk[ /*4*(Nr + 1) */ ],
const char cipherKey[], size_t keyBits);
void rijndaelEncrypt (const uint32_t rk[ /*4*(Nr + 1) */ ], size_t Nr,
const char pt[16], char ct[16]);
void rijndaelDecrypt (const uint32_t rk[ /*4*(Nr + 1) */ ], size_t Nr,
const char ct[16], char pt[16]);
#endif /* __RIJNDAEL_ALG_FST_H */
+517
View File
@@ -0,0 +1,517 @@
/* rijndael-api-fst.c --- Rijndael cipher implementation.
* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Adapted for gnulib by Simon Josefsson.
*
* Based on public domain "Optimised C code" retrieved from (SHA1
* 7c8e4b00d06685d1dbc6724a9e0d502353de339e):
* http://www.iaik.tu-graz.ac.at/research/krypto/AES/old/~rijmen/rijndael/rijndael-fst-3.0.zip
*/
#include <config.h>
/**
* rijndael-api-fst.c
*
* @version 2.9 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Acknowledgements:
*
* We are deeply indebted to the following people for their bug reports,
* fixes, and improvement suggestions to this implementation. Though we
* tried to list all contributions, we apologise in advance for any
* missing reference.
*
* Andrew Bales <Andrew.Bales@Honeywell.com>
* Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
* John Skodon <skodonj@webquill.com>
*/
#include "rijndael-alg-fst.h"
#include "rijndael-api-fst.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
rijndael_rc
rijndaelMakeKey (rijndaelKeyInstance * key, rijndael_direction direction,
size_t keyLen, const char *keyMaterial)
{
size_t i;
char *keyMat;
char cipherKey[RIJNDAEL_MAXKB];
if (key == NULL)
{
return RIJNDAEL_BAD_KEY_INSTANCE;
}
if ((direction == RIJNDAEL_DIR_ENCRYPT)
|| (direction == RIJNDAEL_DIR_DECRYPT))
{
key->direction = direction;
}
else
{
return RIJNDAEL_BAD_KEY_DIR;
}
if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256))
{
key->keyLen = keyLen;
}
else
{
return RIJNDAEL_BAD_KEY_MAT;
}
if (keyMaterial != NULL)
{
strncpy (key->keyMaterial, keyMaterial, keyLen / 4);
}
/* initialize key schedule: */
keyMat = key->keyMaterial;
for (i = 0; i < key->keyLen / 8; i++)
{
char t, v;
t = *keyMat++;
if ((t >= '0') && (t <= '9'))
v = (t - '0') << 4;
else if ((t >= 'a') && (t <= 'f'))
v = (t - 'a' + 10) << 4;
else if ((t >= 'A') && (t <= 'F'))
v = (t - 'A' + 10) << 4;
else
return RIJNDAEL_BAD_KEY_MAT;
t = *keyMat++;
if ((t >= '0') && (t <= '9'))
v ^= (t - '0');
else if ((t >= 'a') && (t <= 'f'))
v ^= (t - 'a' + 10);
else if ((t >= 'A') && (t <= 'F'))
v ^= (t - 'A' + 10);
else
return RIJNDAEL_BAD_KEY_MAT;
cipherKey[i] = v;
}
if (direction == RIJNDAEL_DIR_ENCRYPT)
{
key->Nr = rijndaelKeySetupEnc (key->rk, cipherKey, keyLen);
}
else
{
key->Nr = rijndaelKeySetupDec (key->rk, cipherKey, keyLen);
}
rijndaelKeySetupEnc (key->ek, cipherKey, keyLen);
return 0;
}
rijndael_rc
rijndaelCipherInit (rijndaelCipherInstance * cipher, rijndael_mode mode,
const char *IV)
{
if ((mode == RIJNDAEL_MODE_ECB) || (mode == RIJNDAEL_MODE_CBC)
|| (mode == RIJNDAEL_MODE_CFB1))
{
cipher->mode = mode;
}
else
{
return RIJNDAEL_BAD_CIPHER_MODE;
}
if (IV != NULL)
{
int i;
for (i = 0; i < RIJNDAEL_MAX_IV_SIZE; i++)
{
int t, j;
t = IV[2 * i];
if ((t >= '0') && (t <= '9'))
j = (t - '0') << 4;
else if ((t >= 'a') && (t <= 'f'))
j = (t - 'a' + 10) << 4;
else if ((t >= 'A') && (t <= 'F'))
j = (t - 'A' + 10) << 4;
else
return RIJNDAEL_BAD_CIPHER_INSTANCE;
t = IV[2 * i + 1];
if ((t >= '0') && (t <= '9'))
j ^= (t - '0');
else if ((t >= 'a') && (t <= 'f'))
j ^= (t - 'a' + 10);
else if ((t >= 'A') && (t <= 'F'))
j ^= (t - 'A' + 10);
else
return RIJNDAEL_BAD_CIPHER_INSTANCE;
cipher->IV[i] = (uint8_t) j;
}
}
else
{
memset (cipher->IV, 0, RIJNDAEL_MAX_IV_SIZE);
}
return 0;
}
int
rijndaelBlockEncrypt (rijndaelCipherInstance * cipher,
const rijndaelKeyInstance * key,
const char *input, size_t inputLen, char *outBuffer)
{
size_t i, k, t, numBlocks;
char block[16], *iv;
if (cipher == NULL || key == NULL || key->direction == RIJNDAEL_DIR_DECRYPT)
{
return RIJNDAEL_BAD_CIPHER_STATE;
}
if (input == NULL || inputLen <= 0)
{
return 0; /* nothing to do */
}
numBlocks = inputLen / 128;
switch (cipher->mode)
{
case RIJNDAEL_MODE_ECB:
for (i = numBlocks; i > 0; i--)
{
rijndaelEncrypt (key->rk, key->Nr, input, outBuffer);
input += 16;
outBuffer += 16;
}
break;
case RIJNDAEL_MODE_CBC:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--)
{
((uint32_t *) block)[0] = ((uint32_t *) input)[0] ^
((uint32_t *) iv)[0];
((uint32_t *) block)[1] = ((uint32_t *) input)[1] ^
((uint32_t *) iv)[1];
((uint32_t *) block)[2] = ((uint32_t *) input)[2] ^
((uint32_t *) iv)[2];
((uint32_t *) block)[3] = ((uint32_t *) input)[3] ^
((uint32_t *) iv)[3];
rijndaelEncrypt (key->rk, key->Nr, block, outBuffer);
memcpy (cipher->IV, outBuffer, 16);
input += 16;
outBuffer += 16;
}
break;
case RIJNDAEL_MODE_CFB1:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--)
{
memcpy (outBuffer, input, 16);
for (k = 0; k < 128; k++)
{
rijndaelEncrypt (key->ek, key->Nr, iv, block);
outBuffer[k >> 3] ^= (block[0] & 0x80U) >> (k & 7);
for (t = 0; t < 15; t++)
{
iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
}
iv[15] = (iv[15] << 1) |
((outBuffer[k >> 3] >> (7 - (k & 7))) & 1);
}
outBuffer += 16;
input += 16;
}
break;
default:
return RIJNDAEL_BAD_CIPHER_STATE;
}
return 128 * numBlocks;
}
int
rijndaelPadEncrypt (rijndaelCipherInstance * cipher,
const rijndaelKeyInstance * key,
const char *input, size_t inputOctets, char *outBuffer)
{
size_t i, numBlocks, padLen;
char block[16], *iv;
if (cipher == NULL || key == NULL || key->direction == RIJNDAEL_DIR_DECRYPT)
{
return RIJNDAEL_BAD_CIPHER_STATE;
}
if (input == NULL || inputOctets <= 0)
{
return 0; /* nothing to do */
}
numBlocks = inputOctets / 16;
switch (cipher->mode)
{
case RIJNDAEL_MODE_ECB:
for (i = numBlocks; i > 0; i--)
{
rijndaelEncrypt (key->rk, key->Nr, input, outBuffer);
input += 16;
outBuffer += 16;
}
padLen = 16 - (inputOctets - 16 * numBlocks);
assert (padLen > 0 && padLen <= 16);
memcpy (block, input, 16 - padLen);
memset (block + 16 - padLen, padLen, padLen);
rijndaelEncrypt (key->rk, key->Nr, block, outBuffer);
break;
case RIJNDAEL_MODE_CBC:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--)
{
((uint32_t *) block)[0] = ((uint32_t *) input)[0] ^
((uint32_t *) iv)[0];
((uint32_t *) block)[1] = ((uint32_t *) input)[1] ^
((uint32_t *) iv)[1];
((uint32_t *) block)[2] = ((uint32_t *) input)[2] ^
((uint32_t *) iv)[2];
((uint32_t *) block)[3] = ((uint32_t *) input)[3] ^
((uint32_t *) iv)[3];
rijndaelEncrypt (key->rk, key->Nr, block, outBuffer);
memcpy (cipher->IV, outBuffer, 16);
input += 16;
outBuffer += 16;
}
padLen = 16 - (inputOctets - 16 * numBlocks);
assert (padLen > 0 && padLen <= 16);
for (i = 0; i < 16 - padLen; i++)
{
block[i] = input[i] ^ iv[i];
}
for (i = 16 - padLen; i < 16; i++)
{
block[i] = (char) padLen ^ iv[i];
}
rijndaelEncrypt (key->rk, key->Nr, block, outBuffer);
memcpy (cipher->IV, outBuffer, 16);
break;
default:
return RIJNDAEL_BAD_CIPHER_STATE;
}
return 16 * (numBlocks + 1);
}
int
rijndaelBlockDecrypt (rijndaelCipherInstance * cipher,
const rijndaelKeyInstance * key,
const char *input, size_t inputLen, char *outBuffer)
{
size_t i, k, t, numBlocks;
char block[16], *iv;
if (cipher == NULL
|| key == NULL
|| (cipher->mode != RIJNDAEL_MODE_CFB1
&& key->direction == RIJNDAEL_DIR_ENCRYPT))
{
return RIJNDAEL_BAD_CIPHER_STATE;
}
if (input == NULL || inputLen <= 0)
{
return 0; /* nothing to do */
}
numBlocks = inputLen / 128;
switch (cipher->mode)
{
case RIJNDAEL_MODE_ECB:
for (i = numBlocks; i > 0; i--)
{
rijndaelDecrypt (key->rk, key->Nr, input, outBuffer);
input += 16;
outBuffer += 16;
}
break;
case RIJNDAEL_MODE_CBC:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--)
{
rijndaelDecrypt (key->rk, key->Nr, input, block);
((uint32_t *) block)[0] ^= ((uint32_t *) iv)[0];
((uint32_t *) block)[1] ^= ((uint32_t *) iv)[1];
((uint32_t *) block)[2] ^= ((uint32_t *) iv)[2];
((uint32_t *) block)[3] ^= ((uint32_t *) iv)[3];
memcpy (cipher->IV, input, 16);
memcpy (outBuffer, block, 16);
input += 16;
outBuffer += 16;
}
break;
case RIJNDAEL_MODE_CFB1:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--)
{
memcpy (outBuffer, input, 16);
for (k = 0; k < 128; k++)
{
rijndaelEncrypt (key->ek, key->Nr, iv, block);
for (t = 0; t < 15; t++)
{
iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
}
iv[15] = (iv[15] << 1) | ((input[k >> 3] >> (7 - (k & 7))) & 1);
outBuffer[k >> 3] ^= (block[0] & 0x80U) >> (k & 7);
}
outBuffer += 16;
input += 16;
}
break;
default:
return RIJNDAEL_BAD_CIPHER_STATE;
}
return 128 * numBlocks;
}
int
rijndaelPadDecrypt (rijndaelCipherInstance * cipher,
const rijndaelKeyInstance * key,
const char *input, size_t inputOctets, char *outBuffer)
{
size_t i, numBlocks, padLen;
char block[16];
if (cipher == NULL || key == NULL || key->direction == RIJNDAEL_DIR_ENCRYPT)
{
return RIJNDAEL_BAD_CIPHER_STATE;
}
if (input == NULL || inputOctets <= 0)
{
return 0; /* nothing to do */
}
if (inputOctets % 16 != 0)
{
return RIJNDAEL_BAD_DATA;
}
numBlocks = inputOctets / 16;
switch (cipher->mode)
{
case RIJNDAEL_MODE_ECB:
/* all blocks but last */
for (i = numBlocks - 1; i > 0; i--)
{
rijndaelDecrypt (key->rk, key->Nr, input, outBuffer);
input += 16;
outBuffer += 16;
}
/* last block */
rijndaelDecrypt (key->rk, key->Nr, input, block);
padLen = block[15];
if (padLen >= 16)
{
return RIJNDAEL_BAD_DATA;
}
for (i = 16 - padLen; i < 16; i++)
{
if (block[i] != padLen)
{
return RIJNDAEL_BAD_DATA;
}
}
memcpy (outBuffer, block, 16 - padLen);
break;
case RIJNDAEL_MODE_CBC:
/* all blocks but last */
for (i = numBlocks - 1; i > 0; i--)
{
rijndaelDecrypt (key->rk, key->Nr, input, block);
((uint32_t *) block)[0] ^= ((uint32_t *) cipher->IV)[0];
((uint32_t *) block)[1] ^= ((uint32_t *) cipher->IV)[1];
((uint32_t *) block)[2] ^= ((uint32_t *) cipher->IV)[2];
((uint32_t *) block)[3] ^= ((uint32_t *) cipher->IV)[3];
memcpy (cipher->IV, input, 16);
memcpy (outBuffer, block, 16);
input += 16;
outBuffer += 16;
}
/* last block */
rijndaelDecrypt (key->rk, key->Nr, input, block);
((uint32_t *) block)[0] ^= ((uint32_t *) cipher->IV)[0];
((uint32_t *) block)[1] ^= ((uint32_t *) cipher->IV)[1];
((uint32_t *) block)[2] ^= ((uint32_t *) cipher->IV)[2];
((uint32_t *) block)[3] ^= ((uint32_t *) cipher->IV)[3];
padLen = block[15];
if (padLen <= 0 || padLen > 16)
{
return RIJNDAEL_BAD_DATA;
}
for (i = 16 - padLen; i < 16; i++)
{
if (block[i] != padLen)
{
return RIJNDAEL_BAD_DATA;
}
}
memcpy (outBuffer, block, 16 - padLen);
break;
default:
return RIJNDAEL_BAD_CIPHER_STATE;
}
return 16 * numBlocks - padLen;
}
+207
View File
@@ -0,0 +1,207 @@
/* rijndael-api-fst.h --- Rijndael cipher implementation.
* Copyright (C) 2005 Free Software Foundation, Inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/* Adapted for gnulib by Simon Josefsson. */
/**
* rijndael-api-fst.h
*
* @version 2.9 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Acknowledgements:
*
* We are deeply indebted to the following people for their bug reports,
* fixes, and improvement suggestions to this implementation. Though we
* tried to list all contributions, we apologise in advance for any
* missing reference.
*
* Andrew Bales <Andrew.Bales@Honeywell.com>
* Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
* John Skodon <skodonj@webquill.com>
*/
#ifndef __RIJNDAEL_API_FST_H
#define __RIJNDAEL_API_FST_H
#include "rijndael-alg-fst.h"
#include <stdio.h>
/* Default number of bits in a cipher block */
#define RIJNDAEL_BITSPERBLOCK 128
/* Number of ASCII char's needed to represent a key */
#define RIJNDAEL_MAX_KEY_SIZE 64
/* Number bytes needed to represent an IV */
#define RIJNDAEL_MAX_IV_SIZE 16
typedef enum
{
/* Key direction is invalid, e.g., unknown value */
RIJNDAEL_BAD_KEY_DIR = -1,
/* Key material not of correct length */
RIJNDAEL_BAD_KEY_MAT = -2,
/* Key passed is not valid */
RIJNDAEL_BAD_KEY_INSTANCE = -3,
/* Params struct passed to cipherInit invalid */
RIJNDAEL_BAD_CIPHER_MODE = -4,
/* Cipher in wrong state (e.g., not initialized) */
RIJNDAEL_BAD_CIPHER_STATE = -5,
RIJNDAEL_BAD_BLOCK_LENGTH = -6,
RIJNDAEL_BAD_CIPHER_INSTANCE = -7,
/* Data contents are invalid, e.g., invalid padding */
RIJNDAEL_BAD_DATA = -8,
/* Unknown error */
RIJNDAEL_BAD_OTHER = -9
} rijndael_rc;
typedef enum
{
RIJNDAEL_DIR_ENCRYPT = 0, /* Are we encrypting? */
RIJNDAEL_DIR_DECRYPT = 1 /* Are we decrypting? */
} rijndael_direction;
typedef enum
{
RIJNDAEL_MODE_ECB = 1, /* Are we ciphering in ECB mode? */
RIJNDAEL_MODE_CBC = 2, /* Are we ciphering in CBC mode? */
RIJNDAEL_MODE_CFB1 = 3 /* Are we ciphering in 1-bit CFB mode? */
} rijndael_mode;
/* The structure for key information */
typedef struct
{
/* Key used for encrypting or decrypting? */
rijndael_direction direction;
/* Length of the key */
size_t keyLen;
/* Raw key data in ASCII, e.g., user input or KAT values */
char keyMaterial[RIJNDAEL_MAX_KEY_SIZE + 1];
/* key-length-dependent number of rounds */
int Nr;
/* key schedule */
uint32_t rk[4 * (RIJNDAEL_MAXNR + 1)];
/* CFB1 key schedule (encryption only) */
uint32_t ek[4 * (RIJNDAEL_MAXNR + 1)];
} rijndaelKeyInstance;
/* The structure for cipher information */
typedef struct
{ /* changed order of the components */
rijndael_mode mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */
/* A possible Initialization Vector for ciphering */
char IV[RIJNDAEL_MAX_IV_SIZE];
} rijndaelCipherInstance;
/* Function prototypes */
/* Create KEY, for encryption or decryption depending on DIRECTION,
from KEYMATERIAL, a hex string, of KEYLEN size. KEYLEN should be
128, 192 or 256. Returns 0 on success, or an error code. */
extern rijndael_rc
rijndaelMakeKey (rijndaelKeyInstance *key, rijndael_direction direction,
size_t keyLen, const char *keyMaterial);
/* Initialize cipher state CIPHER for encryption MODE (e.g.,
RIJNDAEL_MODE_CBC) with initialization vector IV, a hex string of
2*RIJNDAEL_MAX_IV_SIZE length. IV may be NULL for modes that do
not need an IV (i.e., RIJNDAEL_MODE_ECB). */
extern rijndael_rc
rijndaelCipherInit (rijndaelCipherInstance *cipher,
rijndael_mode mode, const char *IV);
/* Encrypt data in INPUT, of INPUTLEN/8 bytes length, placing the
output in the pre-allocated OUTBUFFER which must hold at least
INPUTLEN/8 bytes of data. The CIPHER is used as state, and must be
initialized with rijndaelCipherInit before calling this function.
The encryption KEY must be initialized with rijndaelMakeKey before
calling this function. Return the number of bits written, or a
negative rijndael_rc error code. */
extern int
rijndaelBlockEncrypt (rijndaelCipherInstance *cipher,
const rijndaelKeyInstance *key,
const char *input, size_t inputLen,
char *outBuffer);
/* Encrypt data in INPUT, of INPUTOCTETS bytes length, placing the
output in the pre-allocated OUTBUFFER which must hold at least
INPUTOCTETS aligned to the next block size boundary.
Ciphertext-Stealing as described in RFC 2040 is used to encrypt
partial blocks. The CIPHER is used as state, and must be
initialized with rijndaelCipherInit before calling this function.
The encryption KEY must be initialized with rijndaelMakeKey before
calling this function. Return the number of bits written, or a
negative rijndael_rc error code. */
extern int
rijndaelPadEncrypt (rijndaelCipherInstance *cipher,
const rijndaelKeyInstance *key,
const char *input, size_t inputOctets,
char *outBuffer);
/* Decrypt data in INPUT, of INPUTLEN/8 bytes length, placing the
output in the pre-allocated OUTBUFFER which must hold at least
INPUTLEN/8 bytes of data. The CIPHER is used as state, and must be
initialized with rijndaelCipherInit before calling this function.
The encryption KEY must be initialized with rijndaelMakeKey before
calling this function. Return the number of bits written, or a
negative rijndael_rc error code. */
extern int
rijndaelBlockDecrypt (rijndaelCipherInstance *cipher,
const rijndaelKeyInstance *key,
const char *input, size_t inputLen,
char *outBuffer);
/* Decrypt data in INPUT, of INPUTOCTETS bytes length, placing the
output in the pre-allocated OUTBUFFER which must hold at least
INPUTOCTETS aligned to the next block size boundary.
Ciphertext-Stealing as described in RFC 2040 is used to encrypt
partial blocks. The CIPHER is used as state, and must be
initialized with rijndaelCipherInit before calling this function.
The encryption KEY must be initialized with rijndaelMakeKey before
calling this function. Return the number of bits written, or a
negative rijndael_rc error code. */
extern int
rijndaelPadDecrypt (rijndaelCipherInstance *cipher,
const rijndaelKeyInstance *key,
const char *input, size_t inputOctets,
char *outBuffer);
#endif /* __RIJNDAEL_API_FST_H */
+416
View File
@@ -0,0 +1,416 @@
/* sha1.c - Functions to compute SHA1 message digest of files or
memory blocks according to the NIST specification FIPS-180-1.
Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Scott G. Miller
Credits:
Robert Klep <robert@ilse.nl> -- Expansion function fix
*/
#include <config.h>
#include "sha1.h"
#include <stddef.h>
#include <string.h>
#if USE_UNLOCKED_IO
# include "unlocked-io.h"
#endif
#ifdef WORDS_BIGENDIAN
# define SWAP(n) (n)
#else
# define SWAP(n) \
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
#endif
#define BLOCKSIZE 4096
#if BLOCKSIZE % 64 != 0
# error "invalid BLOCKSIZE"
#endif
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (RFC 1321, 3.1: Step 1) */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
initialize it to the start constants of the SHA1 algorithm. This
must be called before using hash in the call to sha1_hash. */
void
sha1_init_ctx (struct sha1_ctx *ctx)
{
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->E = 0xc3d2e1f0;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Put result from CTX in first 20 bytes following RESBUF. The result
must be in little endian byte order.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32-bit value. */
void *
sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf)
{
((uint32_t *) resbuf)[0] = SWAP (ctx->A);
((uint32_t *) resbuf)[1] = SWAP (ctx->B);
((uint32_t *) resbuf)[2] = SWAP (ctx->C);
((uint32_t *) resbuf)[3] = SWAP (ctx->D);
((uint32_t *) resbuf)[4] = SWAP (ctx->E);
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32-bit value. */
void *
sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf)
{
/* Take yet unprocessed bytes into account. */
uint32_t bytes = ctx->buflen;
size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
/* Put the 64-bit file length in *bits* at the end of the buffer. */
ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3);
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
/* Process last bytes. */
sha1_process_block (ctx->buffer, size * 4, ctx);
return sha1_read_ctx (ctx, resbuf);
}
/* Compute SHA1 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 16 bytes
beginning at RESBLOCK. */
int
sha1_stream (FILE * stream, void *resblock)
{
struct sha1_ctx ctx;
char buffer[BLOCKSIZE + 72];
size_t sum;
/* Initialize the computation context. */
sha1_init_ctx (&ctx);
/* Iterate over full file contents. */
while (1)
{
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
computation function processes the whole buffer so that with the
next round of the loop another block can be read. */
size_t n;
sum = 0;
/* Read block. Take care for partial reads. */
while (1)
{
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
sum += n;
if (sum == BLOCKSIZE)
break;
if (n == 0)
{
/* Check for the error flag IFF N == 0, so that we don't
exit the loop after a partial read due to e.g., EAGAIN
or EWOULDBLOCK. */
if (ferror (stream))
return 1;
goto process_partial_block;
}
/* We've read at least one byte, so ignore errors. But always
check for EOF, since feof may be true even though N > 0.
Otherwise, we could end up calling fread after EOF. */
if (feof (stream))
goto process_partial_block;
}
/* Process buffer with BLOCKSIZE bytes. Note that
BLOCKSIZE % 64 == 0
*/
sha1_process_block (buffer, BLOCKSIZE, &ctx);
}
process_partial_block:;
/* Process any remaining bytes. */
if (sum > 0)
sha1_process_bytes (buffer, sum, &ctx);
/* Construct result in desired memory. */
sha1_finish_ctx (&ctx, resblock);
return 0;
}
/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
void *
sha1_buffer (const char *buffer, size_t len, void *resblock)
{
struct sha1_ctx ctx;
/* Initialize the computation context. */
sha1_init_ctx (&ctx);
/* Process whole buffer but last len % 64 bytes. */
sha1_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return sha1_finish_ctx (&ctx, resblock);
}
void
sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx)
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64)
{
sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer,
&((char *) ctx->buffer)[(left_over + add) & ~63],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64)
{
#if !_STRING_ARCH_unaligned
# define alignof(type) offsetof (struct { char c; type x; }, x)
# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0)
if (UNALIGNED_P (buffer))
while (len > 64)
{
sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
else
#endif
{
sha1_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
}
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
size_t left_over = ctx->buflen;
memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
left_over += len;
if (left_over >= 64)
{
sha1_process_block (ctx->buffer, 64, ctx);
left_over -= 64;
memcpy (ctx->buffer, &ctx->buffer[16], left_over);
}
ctx->buflen = left_over;
}
}
/* --- Code below is the primary difference between md5.c and sha1.c --- */
/* SHA1 round constants */
#define K1 0x5a827999
#define K2 0x6ed9eba1
#define K3 0x8f1bbcdc
#define K4 0xca62c1d6
/* Round functions. Note that F2 is the same as F4. */
#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) )
#define F2(B,C,D) (B ^ C ^ D)
#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) )
#define F4(B,C,D) (B ^ C ^ D)
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0.
Most of this code comes from GnuPG's cipher/sha1.c. */
void
sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx)
{
const uint32_t *words = buffer;
size_t nwords = len / sizeof (uint32_t);
const uint32_t *endp = words + nwords;
uint32_t x[16];
uint32_t a = ctx->A;
uint32_t b = ctx->B;
uint32_t c = ctx->C;
uint32_t d = ctx->D;
uint32_t e = ctx->E;
/* First increment the byte count. RFC 1321 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
#define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n))))
#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \
^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \
, (x[I&0x0f] = rol(tm, 1)) )
#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \
+ F( B, C, D ) \
+ K \
+ M; \
B = rol( B, 30 ); \
} while(0)
while (words < endp)
{
uint32_t tm;
int t;
for (t = 0; t < 16; t++)
{
x[t] = SWAP (*words);
words++;
}
R (a, b, c, d, e, F1, K1, x[0]);
R (e, a, b, c, d, F1, K1, x[1]);
R (d, e, a, b, c, F1, K1, x[2]);
R (c, d, e, a, b, F1, K1, x[3]);
R (b, c, d, e, a, F1, K1, x[4]);
R (a, b, c, d, e, F1, K1, x[5]);
R (e, a, b, c, d, F1, K1, x[6]);
R (d, e, a, b, c, F1, K1, x[7]);
R (c, d, e, a, b, F1, K1, x[8]);
R (b, c, d, e, a, F1, K1, x[9]);
R (a, b, c, d, e, F1, K1, x[10]);
R (e, a, b, c, d, F1, K1, x[11]);
R (d, e, a, b, c, F1, K1, x[12]);
R (c, d, e, a, b, F1, K1, x[13]);
R (b, c, d, e, a, F1, K1, x[14]);
R (a, b, c, d, e, F1, K1, x[15]);
R (e, a, b, c, d, F1, K1, M (16));
R (d, e, a, b, c, F1, K1, M (17));
R (c, d, e, a, b, F1, K1, M (18));
R (b, c, d, e, a, F1, K1, M (19));
R (a, b, c, d, e, F2, K2, M (20));
R (e, a, b, c, d, F2, K2, M (21));
R (d, e, a, b, c, F2, K2, M (22));
R (c, d, e, a, b, F2, K2, M (23));
R (b, c, d, e, a, F2, K2, M (24));
R (a, b, c, d, e, F2, K2, M (25));
R (e, a, b, c, d, F2, K2, M (26));
R (d, e, a, b, c, F2, K2, M (27));
R (c, d, e, a, b, F2, K2, M (28));
R (b, c, d, e, a, F2, K2, M (29));
R (a, b, c, d, e, F2, K2, M (30));
R (e, a, b, c, d, F2, K2, M (31));
R (d, e, a, b, c, F2, K2, M (32));
R (c, d, e, a, b, F2, K2, M (33));
R (b, c, d, e, a, F2, K2, M (34));
R (a, b, c, d, e, F2, K2, M (35));
R (e, a, b, c, d, F2, K2, M (36));
R (d, e, a, b, c, F2, K2, M (37));
R (c, d, e, a, b, F2, K2, M (38));
R (b, c, d, e, a, F2, K2, M (39));
R (a, b, c, d, e, F3, K3, M (40));
R (e, a, b, c, d, F3, K3, M (41));
R (d, e, a, b, c, F3, K3, M (42));
R (c, d, e, a, b, F3, K3, M (43));
R (b, c, d, e, a, F3, K3, M (44));
R (a, b, c, d, e, F3, K3, M (45));
R (e, a, b, c, d, F3, K3, M (46));
R (d, e, a, b, c, F3, K3, M (47));
R (c, d, e, a, b, F3, K3, M (48));
R (b, c, d, e, a, F3, K3, M (49));
R (a, b, c, d, e, F3, K3, M (50));
R (e, a, b, c, d, F3, K3, M (51));
R (d, e, a, b, c, F3, K3, M (52));
R (c, d, e, a, b, F3, K3, M (53));
R (b, c, d, e, a, F3, K3, M (54));
R (a, b, c, d, e, F3, K3, M (55));
R (e, a, b, c, d, F3, K3, M (56));
R (d, e, a, b, c, F3, K3, M (57));
R (c, d, e, a, b, F3, K3, M (58));
R (b, c, d, e, a, F3, K3, M (59));
R (a, b, c, d, e, F4, K4, M (60));
R (e, a, b, c, d, F4, K4, M (61));
R (d, e, a, b, c, F4, K4, M (62));
R (c, d, e, a, b, F4, K4, M (63));
R (b, c, d, e, a, F4, K4, M (64));
R (a, b, c, d, e, F4, K4, M (65));
R (e, a, b, c, d, F4, K4, M (66));
R (d, e, a, b, c, F4, K4, M (67));
R (c, d, e, a, b, F4, K4, M (68));
R (b, c, d, e, a, F4, K4, M (69));
R (a, b, c, d, e, F4, K4, M (70));
R (e, a, b, c, d, F4, K4, M (71));
R (d, e, a, b, c, F4, K4, M (72));
R (c, d, e, a, b, F4, K4, M (73));
R (b, c, d, e, a, F4, K4, M (74));
R (a, b, c, d, e, F4, K4, M (75));
R (e, a, b, c, d, F4, K4, M (76));
R (d, e, a, b, c, F4, K4, M (77));
R (c, d, e, a, b, F4, K4, M (78));
R (b, c, d, e, a, F4, K4, M (79));
a = ctx->A += a;
b = ctx->B += b;
c = ctx->C += c;
d = ctx->D += d;
e = ctx->E += e;
}
}
+87
View File
@@ -0,0 +1,87 @@
/* Declarations of functions and data types used for SHA1 sum
library functions.
Copyright (C) 2000, 2001, 2003, 2005, 2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef SHA1_H
# define SHA1_H 1
# include <stdio.h>
# include <stdint.h>
/* Structure to save state of computation between the single steps. */
struct sha1_ctx
{
uint32_t A;
uint32_t B;
uint32_t C;
uint32_t D;
uint32_t E;
uint32_t total[2];
uint32_t buflen;
uint32_t buffer[32];
};
/* Initialize structure containing state of computation. */
extern void sha1_init_ctx (struct sha1_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */
extern void sha1_process_block (const void *buffer, size_t len,
struct sha1_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */
extern void sha1_process_bytes (const void *buffer, size_t len,
struct sha1_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX
in first 20 bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest.
IMPORTANT: On some systems it is required that RESBUF be correctly
aligned for a 32 bits value. */
extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf);
/* Put result from CTX in first 20 bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf);
/* Compute SHA1 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 20 bytes
beginning at RESBLOCK. */
extern int sha1_stream (FILE *stream, void *resblock);
/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
extern void *sha1_buffer (const char *buffer, size_t len, void *resblock);
#endif
+77
View File
@@ -0,0 +1,77 @@
/* Formatted output to strings.
Copyright (C) 2004, 2006-2007 Free Software Foundation, Inc.
Written by Simon Josefsson and Paul Eggert.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <config.h>
/* Specification. */
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "vasnprintf.h"
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
#ifndef EOVERFLOW
# define EOVERFLOW E2BIG
#endif
/* Print formatted output to string STR. Similar to sprintf, but
additional length SIZE limit how much is written into STR. Returns
string length of formatted string (which may be larger than SIZE).
STR may be NULL, in which case nothing will be written. On error,
return a negative value. */
int
snprintf (char *str, size_t size, const char *format, ...)
{
char *output;
size_t len;
size_t lenbuf = size;
va_list args;
va_start (args, format);
output = vasnprintf (str, &lenbuf, format, args);
len = lenbuf;
va_end (args);
if (!output)
return -1;
if (output != str)
{
if (size)
{
size_t pruned_len = (len < size ? len : size - 1);
memcpy (str, output, pruned_len);
str[pruned_len] = '\0';
}
free (output);
}
if (INT_MAX < len)
{
errno = EOVERFLOW;
return -1;
}
return len;
}
+130
View File
@@ -0,0 +1,130 @@
/* Compare strings while treating digits characters numerically.
Copyright (C) 1997, 2000, 2002, 2004, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#if !_LIBC
# include <config.h>
#endif
#include <string.h>
#include <ctype.h>
/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
fractional parts, S_Z: idem but with leading Zeroes only */
#define S_N 0x0
#define S_I 0x4
#define S_F 0x8
#define S_Z 0xC
/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
#define CMP 2
#define LEN 3
/* ISDIGIT differs from isdigit, as follows:
- Its arg may be any int or unsigned int; it need not be an unsigned char
or EOF.
- It's typically faster.
POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
isdigit unless it's important to use the locale's definition
of `digit' even when the host does not conform to POSIX. */
#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
#undef __strverscmp
#undef strverscmp
#ifndef weak_alias
# define __strverscmp strverscmp
#endif
/* Compare S1 and S2 as strings holding indices/version numbers,
returning less than, equal to or greater than zero if S1 is less than,
equal to or greater than S2 (for more info, see the texinfo doc).
*/
int
__strverscmp (const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *) s1;
const unsigned char *p2 = (const unsigned char *) s2;
unsigned char c1, c2;
int state;
int diff;
/* Symbol(s) 0 [1-9] others (padding)
Transition (10) 0 (01) d (00) x (11) - */
static const unsigned int next_state[] = {
/* state x d 0 - */
/* S_N */ S_N, S_I, S_Z, S_N,
/* S_I */ S_N, S_I, S_I, S_I,
/* S_F */ S_N, S_F, S_F, S_F,
/* S_Z */ S_N, S_F, S_Z, S_Z
};
static const int result_type[] = {
/* state x/x x/d x/0 x/- d/x d/d d/0 d/-
0/x 0/d 0/0 0/- -/x -/d -/0 -/- */
/* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
/* S_I */ CMP, -1, -1, CMP, 1, LEN, LEN, CMP,
1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
/* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
/* S_Z */ CMP, 1, 1, CMP, -1, CMP, CMP, CMP,
-1, CMP, CMP, CMP
};
if (p1 == p2)
return 0;
c1 = *p1++;
c2 = *p2++;
/* Hint: '0' is a digit too. */
state = S_N | ((c1 == '0') + (ISDIGIT (c1) != 0));
while ((diff = c1 - c2) == 0 && c1 != '\0')
{
state = next_state[state];
c1 = *p1++;
c2 = *p2++;
state |= (c1 == '0') + (ISDIGIT (c1) != 0);
}
state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT (c2) != 0))];
switch (state)
{
case CMP:
return diff;
case LEN:
while (ISDIGIT (*p1++))
if (!ISDIGIT (*p2++))
return 1;
return ISDIGIT (*p2) ? -1 : diff;
default:
return state;
}
}
#ifdef weak_alias
weak_alias (__strverscmp, strverscmp)
#endif
+24
View File
@@ -0,0 +1,24 @@
/* Compare strings while treating digits characters numerically.
Copyright (C) 1997, 2003 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef STRVERSCMP_H_
# define STRVERSCMP_H_
int strverscmp (const char *, const char *);
#endif /* not STRVERSCMP_H_ */
+46
View File
@@ -0,0 +1,46 @@
/* Reentrant time functions like localtime_r.
Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Paul Eggert. */
#include <config.h>
#include <time.h>
#include <string.h>
static struct tm *
copy_tm_result (struct tm *dest, struct tm const *src)
{
if (!src)
return 0;
*dest = *src;
return dest;
}
struct tm *
gmtime_r (time_t const *restrict t, struct tm *restrict tp)
{
return copy_tm_result (tp, gmtime (t));
}
struct tm *
localtime_r (time_t const *restrict t, struct tm *restrict tp)
{
return copy_tm_result (tp, localtime (t));
}
+4825
View File
@@ -0,0 +1,4825 @@
/* vsprintf with automatic memory allocation.
Copyright (C) 1999, 2002-2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* This file can be parametrized with the following macros:
VASNPRINTF The name of the function being defined.
FCHAR_T The element type of the format string.
DCHAR_T The element type of the destination (result) string.
FCHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters
in the format string are ASCII. MUST be set if
FCHAR_T and DCHAR_T are not the same type.
DIRECTIVE Structure denoting a format directive.
Depends on FCHAR_T.
DIRECTIVES Structure denoting the set of format directives of a
format string. Depends on FCHAR_T.
PRINTF_PARSE Function that parses a format string.
Depends on FCHAR_T.
DCHAR_CPY memcpy like function for DCHAR_T[] arrays.
DCHAR_SET memset like function for DCHAR_T[] arrays.
DCHAR_MBSNLEN mbsnlen like function for DCHAR_T[] arrays.
SNPRINTF The system's snprintf (or similar) function.
This may be either snprintf or swprintf.
TCHAR_T The element type of the argument and result string
of the said SNPRINTF function. This may be either
char or wchar_t. The code exploits that
sizeof (TCHAR_T) | sizeof (DCHAR_T) and
alignof (TCHAR_T) <= alignof (DCHAR_T).
DCHAR_IS_TCHAR Set to 1 if DCHAR_T and TCHAR_T are the same type.
DCHAR_CONV_FROM_ENCODING A function to convert from char[] to DCHAR[].
DCHAR_IS_UINT8_T Set to 1 if DCHAR_T is uint8_t.
DCHAR_IS_UINT16_T Set to 1 if DCHAR_T is uint16_t.
DCHAR_IS_UINT32_T Set to 1 if DCHAR_T is uint32_t. */
/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
This must come before <config.h> because <config.h> may include
<features.h>, and once <features.h> has been included, it's too late. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#ifndef VASNPRINTF
# include <config.h>
#endif
#ifndef IN_LIBINTL
# include <alloca.h>
#endif
/* Specification. */
#ifndef VASNPRINTF
# if WIDE_CHAR_VERSION
# include "vasnwprintf.h"
# else
# include "vasnprintf.h"
# endif
#endif
#include <locale.h> /* localeconv() */
#include <stdio.h> /* snprintf(), sprintf() */
#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
#include <string.h> /* memcpy(), strlen() */
#include <errno.h> /* errno */
#include <limits.h> /* CHAR_BIT */
#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
#if HAVE_NL_LANGINFO
# include <langinfo.h>
#endif
#ifndef VASNPRINTF
# if WIDE_CHAR_VERSION
# include "wprintf-parse.h"
# else
# include "printf-parse.h"
# endif
#endif
/* Checked size_t computations. */
#include "xsize.h"
#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
# include <math.h>
# include "float+.h"
#endif
#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL
# include <math.h>
# include "isnan.h"
#endif
#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) && !defined IN_LIBINTL
# include <math.h>
# include "isnanl-nolibm.h"
# include "fpucw.h"
#endif
#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
# include <math.h>
# include "isnan.h"
# include "printf-frexp.h"
#endif
#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
# include <math.h>
# include "isnanl-nolibm.h"
# include "printf-frexpl.h"
# include "fpucw.h"
#endif
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
#ifndef EOVERFLOW
# define EOVERFLOW E2BIG
#endif
#if HAVE_WCHAR_T
# if HAVE_WCSLEN
# define local_wcslen wcslen
# else
/* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
a dependency towards this library, here is a local substitute.
Define this substitute only once, even if this file is included
twice in the same compilation unit. */
# ifndef local_wcslen_defined
# define local_wcslen_defined 1
static size_t
local_wcslen (const wchar_t * s)
{
const wchar_t *ptr;
for (ptr = s; *ptr != (wchar_t) 0; ptr++)
;
return ptr - s;
}
# endif
# endif
#endif
/* Default parameters. */
#ifndef VASNPRINTF
# if WIDE_CHAR_VERSION
# define VASNPRINTF vasnwprintf
# define FCHAR_T wchar_t
# define DCHAR_T wchar_t
# define TCHAR_T wchar_t
# define DCHAR_IS_TCHAR 1
# define DIRECTIVE wchar_t_directive
# define DIRECTIVES wchar_t_directives
# define PRINTF_PARSE wprintf_parse
# define DCHAR_CPY wmemcpy
# else
# define VASNPRINTF vasnprintf
# define FCHAR_T char
# define DCHAR_T char
# define TCHAR_T char
# define DCHAR_IS_TCHAR 1
# define DIRECTIVE char_directive
# define DIRECTIVES char_directives
# define PRINTF_PARSE printf_parse
# define DCHAR_CPY memcpy
# endif
#endif
#if WIDE_CHAR_VERSION
/* TCHAR_T is wchar_t. */
# define USE_SNPRINTF 1
# if HAVE_DECL__SNWPRINTF
/* On Windows, the function swprintf() has a different signature than
on Unix; we use the _snwprintf() function instead. */
# define SNPRINTF _snwprintf
# else
/* Unix. */
# define SNPRINTF swprintf
# endif
#else
/* TCHAR_T is char. */
# /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
But don't use it on BeOS, since BeOS snprintf produces no output if the
size argument is >= 0x3000000. */
# if (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) && !defined __BEOS__
# define USE_SNPRINTF 1
# else
# define USE_SNPRINTF 0
# endif
# if HAVE_DECL__SNPRINTF
/* Windows. */
# define SNPRINTF _snprintf
# else
/* Unix. */
# define SNPRINTF snprintf
/* Here we need to call the native snprintf, not rpl_snprintf. */
# undef snprintf
# endif
#endif
/* Here we need to call the native sprintf, not rpl_sprintf. */
#undef sprintf
#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL
/* Determine the decimal-point character according to the current locale. */
# ifndef decimal_point_char_defined
# define decimal_point_char_defined 1
static char
decimal_point_char ()
{
const char *point;
/* Determine it in a multithread-safe way. We know nl_langinfo is
multithread-safe on glibc systems, but is not required to be multithread-
safe by POSIX. sprintf(), however, is multithread-safe. localeconv()
is rarely multithread-safe. */
# if HAVE_NL_LANGINFO && __GLIBC__
point = nl_langinfo (RADIXCHAR);
# elif 1
char pointbuf[5];
sprintf (pointbuf, "%#.0f", 1.0);
point = &pointbuf[1];
# else
point = localeconv ()->decimal_point;
# endif
/* The decimal point is always a single byte: either '.' or ','. */
return (point[0] != '\0' ? point[0] : '.');
}
# endif
#endif
#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE && !defined IN_LIBINTL
/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
static int
is_infinite_or_zero (double x)
{
return isnan (x) || x + x == x;
}
#endif
#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
/* Equivalent to !isfinite(x), but does not require libm. */
static int
is_infinitel (long double x)
{
return isnanl (x) || (x + x == x && x != 0.0L);
}
#endif
#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
/* Converting 'long double' to decimal without rare rounding bugs requires
real bignums. We use the naming conventions of GNU gmp, but vastly simpler
(and slower) algorithms. */
typedef unsigned int mp_limb_t;
# define GMP_LIMB_BITS 32
typedef int mp_limb_verify[2 *
(sizeof (mp_limb_t) * CHAR_BIT ==
GMP_LIMB_BITS) - 1];
typedef unsigned long long mp_twolimb_t;
# define GMP_TWOLIMB_BITS 64
typedef int mp_twolimb_verify[2 *
(sizeof (mp_twolimb_t) * CHAR_BIT ==
GMP_TWOLIMB_BITS) - 1];
/* Representation of a bignum >= 0. */
typedef struct
{
size_t nlimbs;
mp_limb_t *limbs; /* Bits in little-endian order, allocated with malloc(). */
} mpn_t;
/* Compute the product of two bignums >= 0.
Return the allocated memory in case of success, NULL in case of memory
allocation failure. */
static void *
multiply (mpn_t src1, mpn_t src2, mpn_t * dest)
{
const mp_limb_t *p1;
const mp_limb_t *p2;
size_t len1;
size_t len2;
if (src1.nlimbs <= src2.nlimbs)
{
len1 = src1.nlimbs;
p1 = src1.limbs;
len2 = src2.nlimbs;
p2 = src2.limbs;
}
else
{
len1 = src2.nlimbs;
p1 = src2.limbs;
len2 = src1.nlimbs;
p2 = src1.limbs;
}
/* Now 0 <= len1 <= len2. */
if (len1 == 0)
{
/* src1 or src2 is zero. */
dest->nlimbs = 0;
dest->limbs = (mp_limb_t *) malloc (1);
}
else
{
/* Here 1 <= len1 <= len2. */
size_t dlen;
mp_limb_t *dp;
size_t k, i, j;
dlen = len1 + len2;
dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t));
if (dp == NULL)
return NULL;
for (k = len2; k > 0;)
dp[--k] = 0;
for (i = 0; i < len1; i++)
{
mp_limb_t digit1 = p1[i];
mp_twolimb_t carry = 0;
for (j = 0; j < len2; j++)
{
mp_limb_t digit2 = p2[j];
carry += (mp_twolimb_t) digit1 *(mp_twolimb_t) digit2;
carry += dp[i + j];
dp[i + j] = (mp_limb_t) carry;
carry = carry >> GMP_LIMB_BITS;
}
dp[i + len2] = (mp_limb_t) carry;
}
/* Normalise. */
while (dlen > 0 && dp[dlen - 1] == 0)
dlen--;
dest->nlimbs = dlen;
dest->limbs = dp;
}
return dest->limbs;
}
/* Compute the quotient of a bignum a >= 0 and a bignum b > 0.
a is written as a = q * b + r with 0 <= r < b. q is the quotient, r
the remainder.
Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd,
q is incremented.
Return the allocated memory in case of success, NULL in case of memory
allocation failure. */
static void *
divide (mpn_t a, mpn_t b, mpn_t * q)
{
/* Algorithm:
First normalise a and b: a=[a[m-1],...,a[0]], b=[b[n-1],...,b[0]]
with m>=0 and n>0 (in base beta = 2^GMP_LIMB_BITS).
If m<n, then q:=0 and r:=a.
If m>=n=1, perform a single-precision division:
r:=0, j:=m,
while j>0 do
{Here (q[m-1]*beta^(m-1)+...+q[j]*beta^j) * b[0] + r*beta^j =
= a[m-1]*beta^(m-1)+...+a[j]*beta^j und 0<=r<b[0]<beta}
j:=j-1, r:=r*beta+a[j], q[j]:=floor(r/b[0]), r:=r-b[0]*q[j].
Normalise [q[m-1],...,q[0]], yields q.
If m>=n>1, perform a multiple-precision division:
We have a/b < beta^(m-n+1).
s:=intDsize-1-(hightest bit in b[n-1]), 0<=s<intDsize.
Shift a and b left by s bits, copying them. r:=a.
r=[r[m],...,r[0]], b=[b[n-1],...,b[0]] with b[n-1]>=beta/2.
For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).}
Compute q* :
q* := floor((r[j+n]*beta+r[j+n-1])/b[n-1]).
In case of overflow (q* >= beta) set q* := beta-1.
Compute c2 := ((r[j+n]*beta+r[j+n-1]) - q* * b[n-1])*beta + r[j+n-2]
and c3 := b[n-2] * q*.
{We have 0 <= c2 < 2*beta^2, even 0 <= c2 < beta^2 if no overflow
occurred. Furthermore 0 <= c3 < beta^2.
If there was overflow and
r[j+n]*beta+r[j+n-1] - q* * b[n-1] >= beta, i.e. c2 >= beta^2,
the next test can be skipped.}
While c3 > c2, {Here 0 <= c2 < c3 < beta^2}
Put q* := q* - 1, c2 := c2 + b[n-1]*beta, c3 := c3 - b[n-2].
If q* > 0:
Put r := r - b * q* * beta^j. In detail:
[r[n+j],...,r[j]] := [r[n+j],...,r[j]] - q* * [b[n-1],...,b[0]].
hence: u:=0, for i:=0 to n-1 do
u := u + q* * b[i],
r[j+i]:=r[j+i]-(u mod beta) (+ beta, if carry),
u:=u div beta (+ 1, if carry in subtraction)
r[n+j]:=r[n+j]-u.
{Since always u = (q* * [b[i-1],...,b[0]] div beta^i) + 1
< q* + 1 <= beta,
the carry u does not overflow.}
If a negative carry occurs, put q* := q* - 1
and [r[n+j],...,r[j]] := [r[n+j],...,r[j]] + [0,b[n-1],...,b[0]].
Set q[j] := q*.
Normalise [q[m-n],..,q[0]]; this yields the quotient q.
Shift [r[n-1],...,r[0]] right by s bits and normalise; this yields the
rest r.
The room for q[j] can be allocated at the memory location of r[n+j].
Finally, round-to-even:
Shift r left by 1 bit.
If r > b or if r = b and q[0] is odd, q := q+1.
*/
const mp_limb_t *a_ptr = a.limbs;
size_t a_len = a.nlimbs;
const mp_limb_t *b_ptr = b.limbs;
size_t b_len = b.nlimbs;
mp_limb_t *roomptr;
mp_limb_t *tmp_roomptr = NULL;
mp_limb_t *q_ptr;
size_t q_len;
mp_limb_t *r_ptr;
size_t r_len;
/* Allocate room for a_len+2 digits.
(Need a_len+1 digits for the real division and 1 more digit for the
final rounding of q.) */
roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t));
if (roomptr == NULL)
return NULL;
/* Normalise a. */
while (a_len > 0 && a_ptr[a_len - 1] == 0)
a_len--;
/* Normalise b. */
for (;;)
{
if (b_len == 0)
/* Division by zero. */
abort ();
if (b_ptr[b_len - 1] == 0)
b_len--;
else
break;
}
/* Here m = a_len >= 0 and n = b_len > 0. */
if (a_len < b_len)
{
/* m<n: trivial case. q=0, r := copy of a. */
r_ptr = roomptr;
r_len = a_len;
memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t));
q_ptr = roomptr + a_len;
q_len = 0;
}
else if (b_len == 1)
{
/* n=1: single precision division.
beta^(m-1) <= a < beta^m ==> beta^(m-2) <= a/b < beta^m */
r_ptr = roomptr;
q_ptr = roomptr + 1;
{
mp_limb_t den = b_ptr[0];
mp_limb_t remainder = 0;
const mp_limb_t *sourceptr = a_ptr + a_len;
mp_limb_t *destptr = q_ptr + a_len;
size_t count;
for (count = a_len; count > 0; count--)
{
mp_twolimb_t num =
((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--sourceptr;
*--destptr = num / den;
remainder = num % den;
}
/* Normalise and store r. */
if (remainder > 0)
{
r_ptr[0] = remainder;
r_len = 1;
}
else
r_len = 0;
/* Normalise q. */
q_len = a_len;
if (q_ptr[q_len - 1] == 0)
q_len--;
}
}
else
{
/* n>1: multiple precision division.
beta^(m-1) <= a < beta^m, beta^(n-1) <= b < beta^n ==>
beta^(m-n-1) <= a/b < beta^(m-n+1). */
/* Determine s. */
size_t s;
{
mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */
s = 31;
if (msd >= 0x10000)
{
msd = msd >> 16;
s -= 16;
}
if (msd >= 0x100)
{
msd = msd >> 8;
s -= 8;
}
if (msd >= 0x10)
{
msd = msd >> 4;
s -= 4;
}
if (msd >= 0x4)
{
msd = msd >> 2;
s -= 2;
}
if (msd >= 0x2)
{
msd = msd >> 1;
s -= 1;
}
}
/* 0 <= s < GMP_LIMB_BITS.
Copy b, shifting it left by s bits. */
if (s > 0)
{
tmp_roomptr = (mp_limb_t *) malloc (b_len * sizeof (mp_limb_t));
if (tmp_roomptr == NULL)
{
free (roomptr);
return NULL;
}
{
const mp_limb_t *sourceptr = b_ptr;
mp_limb_t *destptr = tmp_roomptr;
mp_twolimb_t accu = 0;
size_t count;
for (count = b_len; count > 0; count--)
{
accu += (mp_twolimb_t) * sourceptr++ << s;
*destptr++ = (mp_limb_t) accu;
accu = accu >> GMP_LIMB_BITS;
}
/* accu must be zero, since that was how s was determined. */
if (accu != 0)
abort ();
}
b_ptr = tmp_roomptr;
}
/* Copy a, shifting it left by s bits, yields r.
Memory layout:
At the beginning: r = roomptr[0..a_len],
at the end: r = roomptr[0..b_len-1], q = roomptr[b_len..a_len] */
r_ptr = roomptr;
if (s == 0)
{
memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t));
r_ptr[a_len] = 0;
}
else
{
const mp_limb_t *sourceptr = a_ptr;
mp_limb_t *destptr = r_ptr;
mp_twolimb_t accu = 0;
size_t count;
for (count = a_len; count > 0; count--)
{
accu += (mp_twolimb_t) * sourceptr++ << s;
*destptr++ = (mp_limb_t) accu;
accu = accu >> GMP_LIMB_BITS;
}
*destptr++ = (mp_limb_t) accu;
}
q_ptr = roomptr + b_len;
q_len = a_len - b_len + 1; /* q will have m-n+1 limbs */
{
size_t j = a_len - b_len; /* m-n */
mp_limb_t b_msd = b_ptr[b_len - 1]; /* b[n-1] */
mp_limb_t b_2msd = b_ptr[b_len - 2]; /* b[n-2] */
mp_twolimb_t b_msdd = /* b[n-1]*beta+b[n-2] */
((mp_twolimb_t) b_msd << GMP_LIMB_BITS) | b_2msd;
/* Division loop, traversed m-n+1 times.
j counts down, b is unchanged, beta/2 <= b[n-1] < beta. */
for (;;)
{
mp_limb_t q_star;
mp_limb_t c1;
if (r_ptr[j + b_len] < b_msd) /* r[j+n] < b[n-1] ? */
{
/* Divide r[j+n]*beta+r[j+n-1] by b[n-1], no overflow. */
mp_twolimb_t num =
((mp_twolimb_t) r_ptr[j + b_len] << GMP_LIMB_BITS)
| r_ptr[j + b_len - 1];
q_star = num / b_msd;
c1 = num % b_msd;
}
else
{
/* Overflow, hence r[j+n]*beta+r[j+n-1] >= beta*b[n-1]. */
q_star = (mp_limb_t) ~ (mp_limb_t) 0; /* q* = beta-1 */
/* Test whether r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] >= beta
<==> r[j+n]*beta+r[j+n-1] + b[n-1] >= beta*b[n-1]+beta
<==> b[n-1] < floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta)
{<= beta !}.
If yes, jump directly to the subtraction loop.
(Otherwise, r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] < beta
<==> floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) = b[n-1] ) */
if (r_ptr[j + b_len] > b_msd
|| (c1 = r_ptr[j + b_len - 1] + b_msd) < b_msd)
/* r[j+n] >= b[n-1]+1 or
r[j+n] = b[n-1] and the addition r[j+n-1]+b[n-1] gives a
carry. */
goto subtract;
}
/* q_star = q*,
c1 = (r[j+n]*beta+r[j+n-1]) - q* * b[n-1] (>=0, <beta). */
{
mp_twolimb_t c2 = /* c1*beta+r[j+n-2] */
((mp_twolimb_t) c1 << GMP_LIMB_BITS) | r_ptr[j + b_len - 2];
mp_twolimb_t c3 = /* b[n-2] * q* */
(mp_twolimb_t) b_2msd * (mp_twolimb_t) q_star;
/* While c2 < c3, increase c2 and decrease c3.
Consider c3-c2. While it is > 0, decrease it by
b[n-1]*beta+b[n-2]. Because of b[n-1]*beta+b[n-2] >= beta^2/2
this can happen only twice. */
if (c3 > c2)
{
q_star = q_star - 1; /* q* := q* - 1 */
if (c3 - c2 > b_msdd)
q_star = q_star - 1; /* q* := q* - 1 */
}
}
if (q_star > 0)
subtract:
{
/* Subtract r := r - b * q* * beta^j. */
mp_limb_t cr;
{
const mp_limb_t *sourceptr = b_ptr;
mp_limb_t *destptr = r_ptr + j;
mp_twolimb_t carry = 0;
size_t count;
for (count = b_len; count > 0; count--)
{
/* Here 0 <= carry <= q*. */
carry =
carry
+ (mp_twolimb_t) q_star *(mp_twolimb_t) * sourceptr++
+ (mp_limb_t) ~ (*destptr);
/* Here 0 <= carry <= beta*q* + beta-1. */
*destptr++ = ~(mp_limb_t) carry;
carry = carry >> GMP_LIMB_BITS; /* <= q* */
}
cr = (mp_limb_t) carry;
}
/* Subtract cr from r_ptr[j + b_len], then forget about
r_ptr[j + b_len]. */
if (cr > r_ptr[j + b_len])
{
/* Subtraction gave a carry. */
q_star = q_star - 1; /* q* := q* - 1 */
/* Add b back. */
{
const mp_limb_t *sourceptr = b_ptr;
mp_limb_t *destptr = r_ptr + j;
mp_limb_t carry = 0;
size_t count;
for (count = b_len; count > 0; count--)
{
mp_limb_t source1 = *sourceptr++;
mp_limb_t source2 = *destptr;
*destptr++ = source1 + source2 + carry;
carry =
(carry
? source1 >= (mp_limb_t) ~ source2
: source1 > (mp_limb_t) ~ source2);
}
}
/* Forget about the carry and about r[j+n]. */
}
}
/* q* is determined. Store it as q[j]. */
q_ptr[j] = q_star;
if (j == 0)
break;
j--;
}
}
r_len = b_len;
/* Normalise q. */
if (q_ptr[q_len - 1] == 0)
q_len--;
# if 0 /* Not needed here, since we need r only to compare it with b/2, and
b is shifted left by s bits. */
/* Shift r right by s bits. */
if (s > 0)
{
mp_limb_t ptr = r_ptr + r_len;
mp_twolimb_t accu = 0;
size_t count;
for (count = r_len; count > 0; count--)
{
accu = (mp_twolimb_t) (mp_limb_t) accu << GMP_LIMB_BITS;
accu += (mp_twolimb_t) * --ptr << (GMP_LIMB_BITS - s);
*ptr = (mp_limb_t) (accu >> GMP_LIMB_BITS);
}
}
# endif
/* Normalise r. */
while (r_len > 0 && r_ptr[r_len - 1] == 0)
r_len--;
}
/* Compare r << 1 with b. */
if (r_len > b_len)
goto increment_q;
{
size_t i;
for (i = b_len;;)
{
mp_limb_t r_i =
(i <= r_len && i > 0 ? r_ptr[i - 1] >> (GMP_LIMB_BITS - 1) : 0)
| (i < r_len ? r_ptr[i] << 1 : 0);
mp_limb_t b_i = (i < b_len ? b_ptr[i] : 0);
if (r_i > b_i)
goto increment_q;
if (r_i < b_i)
goto keep_q;
if (i == 0)
break;
i--;
}
}
if (q_len > 0 && ((q_ptr[0] & 1) != 0))
/* q is odd. */
increment_q:
{
size_t i;
for (i = 0; i < q_len; i++)
if (++(q_ptr[i]) != 0)
goto keep_q;
q_ptr[q_len++] = 1;
}
keep_q:
if (tmp_roomptr != NULL)
free (tmp_roomptr);
q->limbs = q_ptr;
q->nlimbs = q_len;
return roomptr;
}
/* Convert a bignum a >= 0, multiplied with 10^extra_zeroes, to decimal
representation.
Destroys the contents of a.
Return the allocated memory - containing the decimal digits in low-to-high
order, terminated with a NUL character - in case of success, NULL in case
of memory allocation failure. */
static char *
convert_to_decimal (mpn_t a, size_t extra_zeroes)
{
mp_limb_t *a_ptr = a.limbs;
size_t a_len = a.nlimbs;
/* 0.03345 is slightly larger than log(2)/(9*log(10)). */
size_t c_len = 9 * ((size_t) (a_len * (GMP_LIMB_BITS * 0.03345f)) + 1);
char *c_ptr = (char *) malloc (xsum (c_len, extra_zeroes));
if (c_ptr != NULL)
{
char *d_ptr = c_ptr;
for (; extra_zeroes > 0; extra_zeroes--)
*d_ptr++ = '0';
while (a_len > 0)
{
/* Divide a by 10^9, in-place. */
mp_limb_t remainder = 0;
mp_limb_t *ptr = a_ptr + a_len;
size_t count;
for (count = a_len; count > 0; count--)
{
mp_twolimb_t num =
((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--ptr;
*ptr = num / 1000000000;
remainder = num % 1000000000;
}
/* Store the remainder as 9 decimal digits. */
for (count = 9; count > 0; count--)
{
*d_ptr++ = '0' + (remainder % 10);
remainder = remainder / 10;
}
/* Normalize a. */
if (a_ptr[a_len - 1] == 0)
a_len--;
}
/* Remove leading zeroes. */
while (d_ptr > c_ptr && d_ptr[-1] == '0')
d_ptr--;
/* But keep at least one zero. */
if (d_ptr == c_ptr)
*d_ptr++ = '0';
/* Terminate the string. */
*d_ptr = '\0';
}
return c_ptr;
}
# if NEED_PRINTF_LONG_DOUBLE
/* Assuming x is finite and >= 0:
write x as x = 2^e * m, where m is a bignum.
Return the allocated memory in case of success, NULL in case of memory
allocation failure. */
static void *
decode_long_double (long double x, int *ep, mpn_t * mp)
{
mpn_t m;
int exp;
long double y;
size_t i;
/* Allocate memory for result. */
m.nlimbs = (LDBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t));
if (m.limbs == NULL)
return NULL;
/* Split into exponential part and mantissa. */
y = frexpl (x, &exp);
if (!(y >= 0.0L && y < 1.0L))
abort ();
/* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * LDBL_MANT_BIT), and the
latter is an integer. */
/* Convert the mantissa (y * LDBL_MANT_BIT) to a sequence of limbs.
I'm not sure whether it's safe to cast a 'long double' value between
2^31 and 2^32 to 'unsigned int', therefore play safe and cast only
'long double' values between 0 and 2^16 (to 'unsigned int' or 'int',
doesn't matter). */
# if (LDBL_MANT_BIT % GMP_LIMB_BITS) != 0
# if (LDBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2
{
mp_limb_t hi, lo;
y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % (GMP_LIMB_BITS / 2));
hi = (int) y;
y -= hi;
if (!(y >= 0.0L && y < 1.0L))
abort ();
y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
lo = (int) y;
y -= lo;
if (!(y >= 0.0L && y < 1.0L))
abort ();
m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo;
}
# else
{
mp_limb_t d;
y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % GMP_LIMB_BITS);
d = (int) y;
y -= d;
if (!(y >= 0.0L && y < 1.0L))
abort ();
m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = d;
}
# endif
# endif
for (i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0;)
{
mp_limb_t hi, lo;
y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
hi = (int) y;
y -= hi;
if (!(y >= 0.0L && y < 1.0L))
abort ();
y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
lo = (int) y;
y -= lo;
if (!(y >= 0.0L && y < 1.0L))
abort ();
m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo;
}
#if 0 /* On FreeBSD 6.1/x86, 'long double' numbers sometimes have excess
precision. */
if (!(y == 0.0L))
abort ();
#endif
/* Normalise. */
while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0)
m.nlimbs--;
*mp = m;
*ep = exp - LDBL_MANT_BIT;
return m.limbs;
}
# endif
# if NEED_PRINTF_DOUBLE
/* Assuming x is finite and >= 0:
write x as x = 2^e * m, where m is a bignum.
Return the allocated memory in case of success, NULL in case of memory
allocation failure. */
static void *
decode_double (double x, int *ep, mpn_t * mp)
{
mpn_t m;
int exp;
double y;
size_t i;
/* Allocate memory for result. */
m.nlimbs = (DBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t));
if (m.limbs == NULL)
return NULL;
/* Split into exponential part and mantissa. */
y = frexp (x, &exp);
if (!(y >= 0.0 && y < 1.0))
abort ();
/* x = 2^exp * y = 2^(exp - DBL_MANT_BIT) * (y * DBL_MANT_BIT), and the
latter is an integer. */
/* Convert the mantissa (y * DBL_MANT_BIT) to a sequence of limbs.
I'm not sure whether it's safe to cast a 'double' value between
2^31 and 2^32 to 'unsigned int', therefore play safe and cast only
'double' values between 0 and 2^16 (to 'unsigned int' or 'int',
doesn't matter). */
# if (DBL_MANT_BIT % GMP_LIMB_BITS) != 0
# if (DBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2
{
mp_limb_t hi, lo;
y *= (mp_limb_t) 1 << (DBL_MANT_BIT % (GMP_LIMB_BITS / 2));
hi = (int) y;
y -= hi;
if (!(y >= 0.0 && y < 1.0))
abort ();
y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
lo = (int) y;
y -= lo;
if (!(y >= 0.0 && y < 1.0))
abort ();
m.limbs[DBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo;
}
# else
{
mp_limb_t d;
y *= (mp_limb_t) 1 << (DBL_MANT_BIT % GMP_LIMB_BITS);
d = (int) y;
y -= d;
if (!(y >= 0.0 && y < 1.0))
abort ();
m.limbs[DBL_MANT_BIT / GMP_LIMB_BITS] = d;
}
# endif
# endif
for (i = DBL_MANT_BIT / GMP_LIMB_BITS; i > 0;)
{
mp_limb_t hi, lo;
y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
hi = (int) y;
y -= hi;
if (!(y >= 0.0 && y < 1.0))
abort ();
y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
lo = (int) y;
y -= lo;
if (!(y >= 0.0 && y < 1.0))
abort ();
m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo;
}
if (!(y == 0.0))
abort ();
/* Normalise. */
while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0)
m.nlimbs--;
*mp = m;
*ep = exp - DBL_MANT_BIT;
return m.limbs;
}
# endif
/* Assuming x = 2^e * m is finite and >= 0, and n is an integer:
Returns the decimal representation of round (x * 10^n).
Return the allocated memory - containing the decimal digits in low-to-high
order, terminated with a NUL character - in case of success, NULL in case
of memory allocation failure. */
static char *
scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
{
int s;
size_t extra_zeroes;
unsigned int abs_n;
unsigned int abs_s;
mp_limb_t *pow5_ptr;
size_t pow5_len;
unsigned int s_limbs;
unsigned int s_bits;
mpn_t pow5;
mpn_t z;
void *z_memory;
char *digits;
if (memory == NULL)
return NULL;
/* x = 2^e * m, hence
y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m)
= round (2^s * 5^n * m). */
s = e + n;
extra_zeroes = 0;
/* Factor out a common power of 10 if possible. */
if (s > 0 && n > 0)
{
extra_zeroes = (s < n ? s : n);
s -= extra_zeroes;
n -= extra_zeroes;
}
/* Here y = round (2^s * 5^n * m) * 10^extra_zeroes.
Before converting to decimal, we need to compute
z = round (2^s * 5^n * m). */
/* Compute 5^|n|, possibly shifted by |s| bits if n and s have the same
sign. 2.322 is slightly larger than log(5)/log(2). */
abs_n = (n >= 0 ? n : -n);
abs_s = (s >= 0 ? s : -s);
pow5_ptr =
(mp_limb_t *)
malloc (((int) (abs_n * (2.322f / GMP_LIMB_BITS)) + 1 +
abs_s / GMP_LIMB_BITS + 1) * sizeof (mp_limb_t));
if (pow5_ptr == NULL)
{
free (memory);
return NULL;
}
/* Initialize with 1. */
pow5_ptr[0] = 1;
pow5_len = 1;
/* Multiply with 5^|n|. */
if (abs_n > 0)
{
static mp_limb_t const small_pow5[13 + 1] = {
1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625,
48828125, 244140625, 1220703125
};
unsigned int n13;
for (n13 = 0; n13 <= abs_n; n13 += 13)
{
mp_limb_t digit1 = small_pow5[n13 + 13 <= abs_n ? 13 : abs_n - n13];
size_t j;
mp_twolimb_t carry = 0;
for (j = 0; j < pow5_len; j++)
{
mp_limb_t digit2 = pow5_ptr[j];
carry += (mp_twolimb_t) digit1 *(mp_twolimb_t) digit2;
pow5_ptr[j] = (mp_limb_t) carry;
carry = carry >> GMP_LIMB_BITS;
}
if (carry > 0)
pow5_ptr[pow5_len++] = (mp_limb_t) carry;
}
}
s_limbs = abs_s / GMP_LIMB_BITS;
s_bits = abs_s % GMP_LIMB_BITS;
if (n >= 0 ? s >= 0 : s <= 0)
{
/* Multiply with 2^|s|. */
if (s_bits > 0)
{
mp_limb_t *ptr = pow5_ptr;
mp_twolimb_t accu = 0;
size_t count;
for (count = pow5_len; count > 0; count--)
{
accu += (mp_twolimb_t) * ptr << s_bits;
*ptr++ = (mp_limb_t) accu;
accu = accu >> GMP_LIMB_BITS;
}
if (accu > 0)
{
*ptr = (mp_limb_t) accu;
pow5_len++;
}
}
if (s_limbs > 0)
{
size_t count;
for (count = pow5_len; count > 0;)
{
count--;
pow5_ptr[s_limbs + count] = pow5_ptr[count];
}
for (count = s_limbs; count > 0;)
{
count--;
pow5_ptr[count] = 0;
}
pow5_len += s_limbs;
}
pow5.limbs = pow5_ptr;
pow5.nlimbs = pow5_len;
if (n >= 0)
{
/* Multiply m with pow5. No division needed. */
z_memory = multiply (m, pow5, &z);
}
else
{
/* Divide m by pow5 and round. */
z_memory = divide (m, pow5, &z);
}
}
else
{
pow5.limbs = pow5_ptr;
pow5.nlimbs = pow5_len;
if (n >= 0)
{
/* n >= 0, s < 0.
Multiply m with pow5, then divide by 2^|s|. */
mpn_t numerator;
mpn_t denominator;
void *tmp_memory;
tmp_memory = multiply (m, pow5, &numerator);
if (tmp_memory == NULL)
{
free (pow5_ptr);
free (memory);
return NULL;
}
/* Construct 2^|s|. */
{
mp_limb_t *ptr = pow5_ptr + pow5_len;
size_t i;
for (i = 0; i < s_limbs; i++)
ptr[i] = 0;
ptr[s_limbs] = (mp_limb_t) 1 << s_bits;
denominator.limbs = ptr;
denominator.nlimbs = s_limbs + 1;
}
z_memory = divide (numerator, denominator, &z);
free (tmp_memory);
}
else
{
/* n < 0, s > 0.
Multiply m with 2^s, then divide by pow5. */
mpn_t numerator;
mp_limb_t *num_ptr;
num_ptr = (mp_limb_t *) malloc ((m.nlimbs + s_limbs + 1)
* sizeof (mp_limb_t));
if (num_ptr == NULL)
{
free (pow5_ptr);
free (memory);
return NULL;
}
{
mp_limb_t *destptr = num_ptr;
{
size_t i;
for (i = 0; i < s_limbs; i++)
*destptr++ = 0;
}
if (s_bits > 0)
{
const mp_limb_t *sourceptr = m.limbs;
mp_twolimb_t accu = 0;
size_t count;
for (count = m.nlimbs; count > 0; count--)
{
accu += (mp_twolimb_t) * sourceptr++ << s_bits;
*destptr++ = (mp_limb_t) accu;
accu = accu >> GMP_LIMB_BITS;
}
if (accu > 0)
*destptr++ = (mp_limb_t) accu;
}
else
{
const mp_limb_t *sourceptr = m.limbs;
size_t count;
for (count = m.nlimbs; count > 0; count--)
*destptr++ = *sourceptr++;
}
numerator.limbs = num_ptr;
numerator.nlimbs = destptr - num_ptr;
}
z_memory = divide (numerator, pow5, &z);
free (num_ptr);
}
}
free (pow5_ptr);
free (memory);
/* Here y = round (x * 10^n) = z * 10^extra_zeroes. */
if (z_memory == NULL)
return NULL;
digits = convert_to_decimal (z, extra_zeroes);
free (z_memory);
return digits;
}
# if NEED_PRINTF_LONG_DOUBLE
/* Assuming x is finite and >= 0, and n is an integer:
Returns the decimal representation of round (x * 10^n).
Return the allocated memory - containing the decimal digits in low-to-high
order, terminated with a NUL character - in case of success, NULL in case
of memory allocation failure. */
static char *
scale10_round_decimal_long_double (long double x, int n)
{
int e;
mpn_t m;
void *memory = decode_long_double (x, &e, &m);
return scale10_round_decimal_decoded (e, m, memory, n);
}
# endif
# if NEED_PRINTF_DOUBLE
/* Assuming x is finite and >= 0, and n is an integer:
Returns the decimal representation of round (x * 10^n).
Return the allocated memory - containing the decimal digits in low-to-high
order, terminated with a NUL character - in case of success, NULL in case
of memory allocation failure. */
static char *
scale10_round_decimal_double (double x, int n)
{
int e;
mpn_t m;
void *memory = decode_double (x, &e, &m);
return scale10_round_decimal_decoded (e, m, memory, n);
}
# endif
# if NEED_PRINTF_LONG_DOUBLE
/* Assuming x is finite and > 0:
Return an approximation for n with 10^n <= x < 10^(n+1).
The approximation is usually the right n, but may be off by 1 sometimes. */
static int
floorlog10l (long double x)
{
int exp;
long double y;
double z;
double l;
/* Split into exponential part and mantissa. */
y = frexpl (x, &exp);
if (!(y >= 0.0L && y < 1.0L))
abort ();
if (y == 0.0L)
return INT_MIN;
if (y < 0.5L)
{
while (y <
(1.0L / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2))))
{
y *= 1.0L * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2));
exp -= GMP_LIMB_BITS;
}
if (y < (1.0L / (1 << 16)))
{
y *= 1.0L * (1 << 16);
exp -= 16;
}
if (y < (1.0L / (1 << 8)))
{
y *= 1.0L * (1 << 8);
exp -= 8;
}
if (y < (1.0L / (1 << 4)))
{
y *= 1.0L * (1 << 4);
exp -= 4;
}
if (y < (1.0L / (1 << 2)))
{
y *= 1.0L * (1 << 2);
exp -= 2;
}
if (y < (1.0L / (1 << 1)))
{
y *= 1.0L * (1 << 1);
exp -= 1;
}
}
if (!(y >= 0.5L && y < 1.0L))
abort ();
/* Compute an approximation for l = log2(x) = exp + log2(y). */
l = exp;
z = y;
if (z < 0.70710678118654752444)
{
z *= 1.4142135623730950488;
l -= 0.5;
}
if (z < 0.8408964152537145431)
{
z *= 1.1892071150027210667;
l -= 0.25;
}
if (z < 0.91700404320467123175)
{
z *= 1.0905077326652576592;
l -= 0.125;
}
if (z < 0.9576032806985736469)
{
z *= 1.0442737824274138403;
l -= 0.0625;
}
/* Now 0.95 <= z <= 1.01. */
z = 1 - z;
/* log(1-z) = - z - z^2/2 - z^3/3 - z^4/4 - ...
Four terms are enough to get an approximation with error < 10^-7. */
l -= z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25)));
/* Finally multiply with log(2)/log(10), yields an approximation for
log10(x). */
l *= 0.30102999566398119523;
/* Round down to the next integer. */
return (int) l + (l < 0 ? -1 : 0);
}
# endif
# if NEED_PRINTF_DOUBLE
/* Assuming x is finite and > 0:
Return an approximation for n with 10^n <= x < 10^(n+1).
The approximation is usually the right n, but may be off by 1 sometimes. */
static int
floorlog10 (double x)
{
int exp;
double y;
double z;
double l;
/* Split into exponential part and mantissa. */
y = frexp (x, &exp);
if (!(y >= 0.0 && y < 1.0))
abort ();
if (y == 0.0)
return INT_MIN;
if (y < 0.5)
{
while (y <
(1.0 / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2))))
{
y *= 1.0 * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2));
exp -= GMP_LIMB_BITS;
}
if (y < (1.0 / (1 << 16)))
{
y *= 1.0 * (1 << 16);
exp -= 16;
}
if (y < (1.0 / (1 << 8)))
{
y *= 1.0 * (1 << 8);
exp -= 8;
}
if (y < (1.0 / (1 << 4)))
{
y *= 1.0 * (1 << 4);
exp -= 4;
}
if (y < (1.0 / (1 << 2)))
{
y *= 1.0 * (1 << 2);
exp -= 2;
}
if (y < (1.0 / (1 << 1)))
{
y *= 1.0 * (1 << 1);
exp -= 1;
}
}
if (!(y >= 0.5 && y < 1.0))
abort ();
/* Compute an approximation for l = log2(x) = exp + log2(y). */
l = exp;
z = y;
if (z < 0.70710678118654752444)
{
z *= 1.4142135623730950488;
l -= 0.5;
}
if (z < 0.8408964152537145431)
{
z *= 1.1892071150027210667;
l -= 0.25;
}
if (z < 0.91700404320467123175)
{
z *= 1.0905077326652576592;
l -= 0.125;
}
if (z < 0.9576032806985736469)
{
z *= 1.0442737824274138403;
l -= 0.0625;
}
/* Now 0.95 <= z <= 1.01. */
z = 1 - z;
/* log(1-z) = - z - z^2/2 - z^3/3 - z^4/4 - ...
Four terms are enough to get an approximation with error < 10^-7. */
l -= z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25)));
/* Finally multiply with log(2)/log(10), yields an approximation for
log10(x). */
l *= 0.30102999566398119523;
/* Round down to the next integer. */
return (int) l + (l < 0 ? -1 : 0);
}
# endif
#endif
DCHAR_T *
VASNPRINTF (DCHAR_T * resultbuf, size_t * lengthp,
const FCHAR_T * format, va_list args)
{
DIRECTIVES d;
arguments a;
if (PRINTF_PARSE (format, &d, &a) < 0)
/* errno is already set. */
return NULL;
#define CLEANUP() \
free (d.dir); \
if (a.arg) \
free (a.arg);
if (PRINTF_FETCHARGS (args, &a) < 0)
{
CLEANUP ();
errno = EINVAL;
return NULL;
}
{
size_t buf_neededlength;
TCHAR_T *buf;
TCHAR_T *buf_malloced;
const FCHAR_T *cp;
size_t i;
DIRECTIVE *dp;
/* Output string accumulator. */
DCHAR_T *result;
size_t allocated;
size_t length;
/* Allocate a small buffer that will hold a directive passed to
sprintf or snprintf. */
buf_neededlength =
xsum4 (7, d.max_width_length, d.max_precision_length, 6);
#if HAVE_ALLOCA
if (buf_neededlength < 4000 / sizeof (TCHAR_T))
{
buf = (TCHAR_T *) alloca (buf_neededlength * sizeof (TCHAR_T));
buf_malloced = NULL;
}
else
#endif
{
size_t buf_memsize = xtimes (buf_neededlength, sizeof (TCHAR_T));
if (size_overflow_p (buf_memsize))
goto out_of_memory_1;
buf = (TCHAR_T *) malloc (buf_memsize);
if (buf == NULL)
goto out_of_memory_1;
buf_malloced = buf;
}
if (resultbuf != NULL)
{
result = resultbuf;
allocated = *lengthp;
}
else
{
result = NULL;
allocated = 0;
}
length = 0;
/* Invariants:
result is either == resultbuf or == NULL or malloc-allocated.
If length > 0, then result != NULL. */
/* Ensures that allocated >= needed. Aborts through a jump to
out_of_memory if needed is SIZE_MAX or otherwise too big. */
#define ENSURE_ALLOCATION(needed) \
if ((needed) > allocated) \
{ \
size_t memory_size; \
DCHAR_T *memory; \
\
allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \
if ((needed) > allocated) \
allocated = (needed); \
memory_size = xtimes (allocated, sizeof (DCHAR_T)); \
if (size_overflow_p (memory_size)) \
goto out_of_memory; \
if (result == resultbuf || result == NULL) \
memory = (DCHAR_T *) malloc (memory_size); \
else \
memory = (DCHAR_T *) realloc (result, memory_size); \
if (memory == NULL) \
goto out_of_memory; \
if (result == resultbuf && length > 0) \
DCHAR_CPY (memory, result, length); \
result = memory; \
}
for (cp = format, i = 0, dp = &d.dir[0];; cp = dp->dir_end, i++, dp++)
{
if (cp != dp->dir_start)
{
size_t n = dp->dir_start - cp;
size_t augmented_length = xsum (length, n);
ENSURE_ALLOCATION (augmented_length);
/* This copies a piece of FCHAR_T[] into a DCHAR_T[]. Here we
need that the format string contains only ASCII characters
if FCHAR_T and DCHAR_T are not the same type. */
if (sizeof (FCHAR_T) == sizeof (DCHAR_T))
{
DCHAR_CPY (result + length, (const DCHAR_T *) cp, n);
length = augmented_length;
}
else
{
do
result[length++] = (unsigned char) *cp++;
while (--n > 0);
}
}
if (i == d.count)
break;
/* Execute a single directive. */
if (dp->conversion == '%')
{
size_t augmented_length;
if (!(dp->arg_index == ARG_NONE))
abort ();
augmented_length = xsum (length, 1);
ENSURE_ALLOCATION (augmented_length);
result[length] = '%';
length = augmented_length;
}
else
{
if (!(dp->arg_index != ARG_NONE))
abort ();
if (dp->conversion == 'n')
{
switch (a.arg[dp->arg_index].type)
{
case TYPE_COUNT_SCHAR_POINTER:
*a.arg[dp->arg_index].a.a_count_schar_pointer = length;
break;
case TYPE_COUNT_SHORT_POINTER:
*a.arg[dp->arg_index].a.a_count_short_pointer = length;
break;
case TYPE_COUNT_INT_POINTER:
*a.arg[dp->arg_index].a.a_count_int_pointer = length;
break;
case TYPE_COUNT_LONGINT_POINTER:
*a.arg[dp->arg_index].a.a_count_longint_pointer = length;
break;
#if HAVE_LONG_LONG_INT
case TYPE_COUNT_LONGLONGINT_POINTER:
*a.arg[dp->arg_index].a.a_count_longlongint_pointer =
length;
break;
#endif
default:
abort ();
}
}
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
else if (dp->conversion == 'U')
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
int has_width;
size_t width;
int has_precision;
size_t precision;
has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
width = (unsigned int) (-arg);
}
else
width = arg;
}
else
{
const FCHAR_T *digitp = dp->width_start;
do
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
has_width = 1;
}
has_precision = 0;
precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
int arg;
if (!
(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
precision = arg;
has_precision = 1;
}
}
else
{
const FCHAR_T *digitp = dp->precision_start + 1;
precision = 0;
while (digitp != dp->precision_end)
precision =
xsum (xtimes (precision, 10), *digitp++ - '0');
has_precision = 1;
}
}
switch (type)
{
case TYPE_U8_STRING:
{
const uint8_t *arg = a.arg[dp->arg_index].a.a_u8_string;
const uint8_t *arg_end;
size_t characters;
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
arg_end = arg;
characters = 0;
for (; precision > 0; precision--)
{
int count = u8_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!
(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
arg_end = arg;
characters = 0;
for (;;)
{
int count = u8_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!
(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else
{
/* Use the entire string. */
arg_end = arg + u8_strlen (arg);
/* The number of characters doesn't matter. */
characters = 0;
}
if (has_width && width > characters
&& !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
# if DCHAR_IS_UINT8_T
{
size_t n = arg_end - arg;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_CPY (result + length, arg, n);
length += n;
}
# else
{ /* Convert. */
DCHAR_T *converted = result + length;
size_t converted_len = allocated - length;
# if DCHAR_IS_TCHAR
/* Convert from UTF-8 to locale encoding. */
if (u8_conv_to_encoding (locale_charset (),
iconveh_question_mark,
arg, arg_end - arg, NULL,
&converted, &converted_len)
< 0)
# else
/* Convert from UTF-8 to UTF-16/UTF-32. */
converted =
U8_TO_DCHAR (arg, arg_end - arg,
converted, &converted_len);
if (converted == NULL)
# endif
{
int saved_errno = errno;
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
if (converted != result + length)
{
ENSURE_ALLOCATION (xsum (length, converted_len));
DCHAR_CPY (result + length, converted,
converted_len);
free (converted);
}
length += converted_len;
}
# endif
if (has_width && width > characters
&& (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
}
break;
case TYPE_U16_STRING:
{
const uint16_t *arg =
a.arg[dp->arg_index].a.a_u16_string;
const uint16_t *arg_end;
size_t characters;
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
arg_end = arg;
characters = 0;
for (; precision > 0; precision--)
{
int count = u16_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!
(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
arg_end = arg;
characters = 0;
for (;;)
{
int count = u16_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!
(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else
{
/* Use the entire string. */
arg_end = arg + u16_strlen (arg);
/* The number of characters doesn't matter. */
characters = 0;
}
if (has_width && width > characters
&& !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
# if DCHAR_IS_UINT16_T
{
size_t n = arg_end - arg;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_CPY (result + length, arg, n);
length += n;
}
# else
{ /* Convert. */
DCHAR_T *converted = result + length;
size_t converted_len = allocated - length;
# if DCHAR_IS_TCHAR
/* Convert from UTF-16 to locale encoding. */
if (u16_conv_to_encoding (locale_charset (),
iconveh_question_mark,
arg, arg_end - arg, NULL,
&converted, &converted_len)
< 0)
# else
/* Convert from UTF-16 to UTF-8/UTF-32. */
converted =
U16_TO_DCHAR (arg, arg_end - arg,
converted, &converted_len);
if (converted == NULL)
# endif
{
int saved_errno = errno;
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
if (converted != result + length)
{
ENSURE_ALLOCATION (xsum (length, converted_len));
DCHAR_CPY (result + length, converted,
converted_len);
free (converted);
}
length += converted_len;
}
# endif
if (has_width && width > characters
&& (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
}
break;
case TYPE_U32_STRING:
{
const uint32_t *arg =
a.arg[dp->arg_index].a.a_u32_string;
const uint32_t *arg_end;
size_t characters;
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
arg_end = arg;
characters = 0;
for (; precision > 0; precision--)
{
int count = u32_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!
(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
arg_end = arg;
characters = 0;
for (;;)
{
int count = u32_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!
(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else
{
/* Use the entire string. */
arg_end = arg + u32_strlen (arg);
/* The number of characters doesn't matter. */
characters = 0;
}
if (has_width && width > characters
&& !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
# if DCHAR_IS_UINT32_T
{
size_t n = arg_end - arg;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_CPY (result + length, arg, n);
length += n;
}
# else
{ /* Convert. */
DCHAR_T *converted = result + length;
size_t converted_len = allocated - length;
# if DCHAR_IS_TCHAR
/* Convert from UTF-32 to locale encoding. */
if (u32_conv_to_encoding (locale_charset (),
iconveh_question_mark,
arg, arg_end - arg, NULL,
&converted, &converted_len)
< 0)
# else
/* Convert from UTF-32 to UTF-8/UTF-16. */
converted =
U32_TO_DCHAR (arg, arg_end - arg,
converted, &converted_len);
if (converted == NULL)
# endif
{
int saved_errno = errno;
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
if (converted != result + length)
{
ENSURE_ALLOCATION (xsum (length, converted_len));
DCHAR_CPY (result + length, converted,
converted_len);
free (converted);
}
length += converted_len;
}
# endif
if (has_width && width > characters
&& (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
}
break;
default:
abort ();
}
}
#endif
#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
else if ((dp->conversion == 'a' || dp->conversion == 'A')
# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE))
&& (0
# if NEED_PRINTF_DOUBLE
|| a.arg[dp->arg_index].type == TYPE_DOUBLE
# endif
# if NEED_PRINTF_LONG_DOUBLE
|| a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
# endif
)
# endif
)
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
int has_width;
size_t width;
int has_precision;
size_t precision;
size_t tmp_length;
DCHAR_T tmpbuf[700];
DCHAR_T *tmp;
DCHAR_T *pad_ptr;
DCHAR_T *p;
has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
width = (unsigned int) (-arg);
}
else
width = arg;
}
else
{
const FCHAR_T *digitp = dp->width_start;
do
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
has_width = 1;
}
has_precision = 0;
precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
int arg;
if (!
(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
precision = arg;
has_precision = 1;
}
}
else
{
const FCHAR_T *digitp = dp->precision_start + 1;
precision = 0;
while (digitp != dp->precision_end)
precision =
xsum (xtimes (precision, 10), *digitp++ - '0');
has_precision = 1;
}
}
/* Allocate a temporary buffer of sufficient size. */
if (type == TYPE_LONGDOUBLE)
tmp_length = (unsigned int) ((LDBL_DIG + 1) * 0.831 /* decimal -> hexadecimal */
) + 1; /* turn floor into ceil */
else
tmp_length = (unsigned int) ((DBL_DIG + 1) * 0.831 /* decimal -> hexadecimal */
) + 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Account for sign, decimal point etc. */
tmp_length = xsum (tmp_length, 12);
if (tmp_length < width)
tmp_length = width;
tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
tmp = tmpbuf;
else
{
size_t tmp_memsize =
xtimes (tmp_length, sizeof (DCHAR_T));
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
tmp = (DCHAR_T *) malloc (tmp_memsize);
if (tmp == NULL)
/* Out of memory. */
goto out_of_memory;
}
pad_ptr = NULL;
p = tmp;
if (type == TYPE_LONGDOUBLE)
{
# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE
long double arg = a.arg[dp->arg_index].a.a_longdouble;
if (isnanl (arg))
{
if (dp->conversion == 'A')
{
*p++ = 'N';
*p++ = 'A';
*p++ = 'N';
}
else
{
*p++ = 'n';
*p++ = 'a';
*p++ = 'n';
}
}
else
{
int sign = 0;
DECL_LONG_DOUBLE_ROUNDING
BEGIN_LONG_DOUBLE_ROUNDING ();
if (signbit (arg)) /* arg < 0.0L or negative zero */
{
sign = -1;
arg = -arg;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
if (arg > 0.0L && arg + arg == arg)
{
if (dp->conversion == 'A')
{
*p++ = 'I';
*p++ = 'N';
*p++ = 'F';
}
else
{
*p++ = 'i';
*p++ = 'n';
*p++ = 'f';
}
}
else
{
int exponent;
long double mantissa;
if (arg > 0.0L)
mantissa = printf_frexpl (arg, &exponent);
else
{
exponent = 0;
mantissa = 0.0L;
}
if (has_precision
&& precision <
(unsigned int) ((LDBL_DIG + 1) * 0.831) + 1)
{
/* Round the mantissa. */
long double tail = mantissa;
size_t q;
for (q = precision;; q--)
{
int digit = (int) tail;
tail -= digit;
if (q == 0)
{
if (digit & 1 ? tail >= 0.5L : tail >
0.5L)
tail = 1 - tail;
else
tail = -tail;
break;
}
tail *= 16.0L;
}
if (tail != 0.0L)
for (q = precision; q > 0; q--)
tail *= 0.0625L;
mantissa += tail;
}
*p++ = '0';
*p++ = dp->conversion - 'A' + 'X';
pad_ptr = p;
{
int digit;
digit = (int) mantissa;
mantissa -= digit;
*p++ = '0' + digit;
if ((flags & FLAG_ALT)
|| mantissa > 0.0L || precision > 0)
{
*p++ = decimal_point_char ();
/* This loop terminates because we assume
that FLT_RADIX is a power of 2. */
while (mantissa > 0.0L)
{
mantissa *= 16.0L;
digit = (int) mantissa;
mantissa -= digit;
*p++ = digit
+ (digit < 10
? '0' : dp->conversion - 10);
if (precision > 0)
precision--;
}
while (precision > 0)
{
*p++ = '0';
precision--;
}
}
}
*p++ = dp->conversion - 'A' + 'P';
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
{ '%', '+', 'd', '\0' };
SNPRINTF (p, 6 + 1, decimal_format, exponent);
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, "%+d", exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, "%+d", exponent);
for (ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
}
END_LONG_DOUBLE_ROUNDING ();
}
# else
abort ();
# endif
}
else
{
# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE
double arg = a.arg[dp->arg_index].a.a_double;
if (isnan (arg))
{
if (dp->conversion == 'A')
{
*p++ = 'N';
*p++ = 'A';
*p++ = 'N';
}
else
{
*p++ = 'n';
*p++ = 'a';
*p++ = 'n';
}
}
else
{
int sign = 0;
if (signbit (arg)) /* arg < 0.0 or negative zero */
{
sign = -1;
arg = -arg;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
if (arg > 0.0 && arg + arg == arg)
{
if (dp->conversion == 'A')
{
*p++ = 'I';
*p++ = 'N';
*p++ = 'F';
}
else
{
*p++ = 'i';
*p++ = 'n';
*p++ = 'f';
}
}
else
{
int exponent;
double mantissa;
if (arg > 0.0)
mantissa = printf_frexp (arg, &exponent);
else
{
exponent = 0;
mantissa = 0.0;
}
if (has_precision
&& precision <
(unsigned int) ((DBL_DIG + 1) * 0.831) + 1)
{
/* Round the mantissa. */
double tail = mantissa;
size_t q;
for (q = precision;; q--)
{
int digit = (int) tail;
tail -= digit;
if (q == 0)
{
if (digit & 1 ? tail >= 0.5 : tail >
0.5)
tail = 1 - tail;
else
tail = -tail;
break;
}
tail *= 16.0;
}
if (tail != 0.0)
for (q = precision; q > 0; q--)
tail *= 0.0625;
mantissa += tail;
}
*p++ = '0';
*p++ = dp->conversion - 'A' + 'X';
pad_ptr = p;
{
int digit;
digit = (int) mantissa;
mantissa -= digit;
*p++ = '0' + digit;
if ((flags & FLAG_ALT)
|| mantissa > 0.0 || precision > 0)
{
*p++ = decimal_point_char ();
/* This loop terminates because we assume
that FLT_RADIX is a power of 2. */
while (mantissa > 0.0)
{
mantissa *= 16.0;
digit = (int) mantissa;
mantissa -= digit;
*p++ = digit
+ (digit < 10
? '0' : dp->conversion - 10);
if (precision > 0)
precision--;
}
while (precision > 0)
{
*p++ = '0';
precision--;
}
}
}
*p++ = dp->conversion - 'A' + 'P';
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
{ '%', '+', 'd', '\0' };
SNPRINTF (p, 6 + 1, decimal_format, exponent);
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, "%+d", exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, "%+d", exponent);
for (ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
}
}
# else
abort ();
# endif
}
/* The generated string now extends from tmp to p, with the
zero padding insertion point being at pad_ptr. */
if (has_width && p - tmp < width)
{
size_t pad = width - (p - tmp);
DCHAR_T *end = p + pad;
if (flags & FLAG_LEFT)
{
/* Pad with spaces on the right. */
for (; pad > 0; pad--)
*p++ = ' ';
}
else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
{
/* Pad with zeroes. */
DCHAR_T *q = end;
while (p > pad_ptr)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = '0';
}
else
{
/* Pad with spaces on the left. */
DCHAR_T *q = end;
while (p > tmp)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = ' ';
}
p = end;
}
{
size_t count = p - tmp;
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
code above! */
abort ();
/* Make room for the result. */
if (count >= allocated - length)
{
size_t n = xsum (length, count);
ENSURE_ALLOCATION (n);
}
/* Append the result. */
memcpy (result + length, tmp, count * sizeof (DCHAR_T));
if (tmp != tmpbuf)
free (tmp);
length += count;
}
}
#endif
#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
else if ((dp->conversion == 'f' || dp->conversion == 'F'
|| dp->conversion == 'e' || dp->conversion == 'E'
|| dp->conversion == 'g' || dp->conversion == 'G'
|| dp->conversion == 'a' || dp->conversion == 'A') && (0
# if NEED_PRINTF_DOUBLE
||
a.
arg
[dp->
arg_index].
type
==
TYPE_DOUBLE
# elif NEED_PRINTF_INFINITE_DOUBLE
||
(a.
arg
[dp->
arg_index].
type
==
TYPE_DOUBLE
/* The systems (mingw) which produce wrong output
for Inf, -Inf, and NaN also do so for -0.0.
Therefore we treat this case here as well. */
&&
is_infinite_or_zero
(a.
arg
[dp->
arg_index].
a.
a_double))
# endif
# if NEED_PRINTF_LONG_DOUBLE
||
a.
arg
[dp->
arg_index].
type
==
TYPE_LONGDOUBLE
# elif NEED_PRINTF_INFINITE_LONG_DOUBLE
||
(a.
arg
[dp->
arg_index].
type
==
TYPE_LONGDOUBLE
/* Some systems produce wrong output for Inf,
-Inf, and NaN. */
&&
is_infinitel
(a.
arg
[dp->
arg_index].
a.
a_longdouble))
# endif
))
{
# if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE)
arg_type type = a.arg[dp->arg_index].type;
# endif
int flags = dp->flags;
int has_width;
size_t width;
int has_precision;
size_t precision;
size_t tmp_length;
DCHAR_T tmpbuf[700];
DCHAR_T *tmp;
DCHAR_T *pad_ptr;
DCHAR_T *p;
has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
width = (unsigned int) (-arg);
}
else
width = arg;
}
else
{
const FCHAR_T *digitp = dp->width_start;
do
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
has_width = 1;
}
has_precision = 0;
precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
int arg;
if (!
(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
precision = arg;
has_precision = 1;
}
}
else
{
const FCHAR_T *digitp = dp->precision_start + 1;
precision = 0;
while (digitp != dp->precision_end)
precision =
xsum (xtimes (precision, 10), *digitp++ - '0');
has_precision = 1;
}
}
/* POSIX specifies the default precision to be 6 for %f, %F,
%e, %E, but not for %g, %G. Implementations appear to use
the same default precision also for %g, %G. */
if (!has_precision)
precision = 6;
/* Allocate a temporary buffer of sufficient size. */
# if NEED_PRINTF_DOUBLE && NEED_PRINTF_LONG_DOUBLE
tmp_length =
(type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : DBL_DIG + 1);
# elif NEED_PRINTF_INFINITE_DOUBLE && NEED_PRINTF_LONG_DOUBLE
tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : 0);
# elif NEED_PRINTF_LONG_DOUBLE
tmp_length = LDBL_DIG + 1;
# elif NEED_PRINTF_DOUBLE
tmp_length = DBL_DIG + 1;
# else
tmp_length = 0;
# endif
if (tmp_length < precision)
tmp_length = precision;
# if NEED_PRINTF_LONG_DOUBLE
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
if (type == TYPE_LONGDOUBLE)
# endif
if (dp->conversion == 'f' || dp->conversion == 'F')
{
long double arg = a.arg[dp->arg_index].a.a_longdouble;
if (!(isnanl (arg) || arg + arg == arg))
{
/* arg is finite and nonzero. */
int exponent = floorlog10l (arg < 0 ? -arg : arg);
if (exponent >= 0
&& tmp_length < exponent + precision)
tmp_length = exponent + precision;
}
}
# endif
# if NEED_PRINTF_DOUBLE
# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
if (type == TYPE_DOUBLE)
# endif
if (dp->conversion == 'f' || dp->conversion == 'F')
{
double arg = a.arg[dp->arg_index].a.a_double;
if (!(isnan (arg) || arg + arg == arg))
{
/* arg is finite and nonzero. */
int exponent = floorlog10 (arg < 0 ? -arg : arg);
if (exponent >= 0
&& tmp_length < exponent + precision)
tmp_length = exponent + precision;
}
}
# endif
/* Account for sign, decimal point etc. */
tmp_length = xsum (tmp_length, 12);
if (tmp_length < width)
tmp_length = width;
tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
tmp = tmpbuf;
else
{
size_t tmp_memsize =
xtimes (tmp_length, sizeof (DCHAR_T));
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
tmp = (DCHAR_T *) malloc (tmp_memsize);
if (tmp == NULL)
/* Out of memory. */
goto out_of_memory;
}
pad_ptr = NULL;
p = tmp;
# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
if (type == TYPE_LONGDOUBLE)
# endif
{
long double arg = a.arg[dp->arg_index].a.a_longdouble;
if (isnanl (arg))
{
if (dp->conversion >= 'A' && dp->conversion <= 'Z')
{
*p++ = 'N';
*p++ = 'A';
*p++ = 'N';
}
else
{
*p++ = 'n';
*p++ = 'a';
*p++ = 'n';
}
}
else
{
int sign = 0;
DECL_LONG_DOUBLE_ROUNDING
BEGIN_LONG_DOUBLE_ROUNDING ();
if (signbit (arg)) /* arg < 0.0L or negative zero */
{
sign = -1;
arg = -arg;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
if (arg > 0.0L && arg + arg == arg)
{
if (dp->conversion >= 'A'
&& dp->conversion <= 'Z')
{
*p++ = 'I';
*p++ = 'N';
*p++ = 'F';
}
else
{
*p++ = 'i';
*p++ = 'n';
*p++ = 'f';
}
}
else
{
# if NEED_PRINTF_LONG_DOUBLE
pad_ptr = p;
if (dp->conversion == 'f'
|| dp->conversion == 'F')
{
char *digits;
size_t ndigits;
digits =
scale10_round_decimal_long_double (arg,
precision);
if (digits == NULL)
{
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
ndigits = strlen (digits);
if (ndigits > precision)
do
{
--ndigits;
*p++ = digits[ndigits];
}
while (ndigits > precision);
else
*p++ = '0';
/* Here ndigits <= precision. */
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > ndigits; precision--)
*p++ = '0';
while (ndigits > 0)
{
--ndigits;
*p++ = digits[ndigits];
}
}
free (digits);
}
else if (dp->conversion == 'e'
|| dp->conversion == 'E')
{
int exponent;
if (arg == 0.0L)
{
exponent = 0;
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
}
else
{
/* arg > 0.0L. */
int adjusted;
char *digits;
size_t ndigits;
exponent = floorlog10l (arg);
adjusted = 0;
for (;;)
{
digits =
scale10_round_decimal_long_double
(arg, (int) precision - exponent);
if (digits == NULL)
{
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
ndigits = strlen (digits);
if (ndigits == precision + 1)
break;
if (ndigits < precision
|| ndigits > precision + 2)
/* The exponent was not guessed
precisely enough. */
abort ();
if (adjusted)
/* None of two values of exponent is
the right one. Prevent an endless
loop. */
abort ();
free (digits);
if (ndigits == precision)
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = precision+1. */
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
while (ndigits > 0)
{
--ndigits;
*p++ = digits[ndigits];
}
}
free (digits);
}
*p++ = dp->conversion; /* 'e' or 'E' */
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
{ '%', '+', '.', '2', 'd', '\0' };
SNPRINTF (p, 6 + 1, decimal_format,
exponent);
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, "%+.2d", exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, "%+.2d", exponent);
for (ep = expbuf; (*p = *ep) != '\0';
ep++)
p++;
}
# endif
}
else if (dp->conversion == 'g'
|| dp->conversion == 'G')
{
if (precision == 0)
precision = 1;
/* precision >= 1. */
if (arg == 0.0L)
/* The exponent is 0, >= -4, < precision.
Use fixed-point notation. */
{
size_t ndigits = precision;
/* Number of trailing zeroes that have to be
dropped. */
size_t nzeroes =
(flags & FLAG_ALT ? 0 : precision - 1);
--ndigits;
*p++ = '0';
if ((flags & FLAG_ALT)
|| ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = '0';
}
}
}
else
{
/* arg > 0.0L. */
int exponent;
int adjusted;
char *digits;
size_t ndigits;
size_t nzeroes;
exponent = floorlog10l (arg);
adjusted = 0;
for (;;)
{
digits =
scale10_round_decimal_long_double
(arg,
(int) (precision - 1) - exponent);
if (digits == NULL)
{
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
ndigits = strlen (digits);
if (ndigits == precision)
break;
if (ndigits < precision - 1
|| ndigits > precision + 1)
/* The exponent was not guessed
precisely enough. */
abort ();
if (adjusted)
/* None of two values of exponent is
the right one. Prevent an endless
loop. */
abort ();
free (digits);
if (ndigits < precision)
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = precision. */
/* Determine the number of trailing zeroes
that have to be dropped. */
nzeroes = 0;
if ((flags & FLAG_ALT) == 0)
while (nzeroes < ndigits
&& digits[nzeroes] == '0')
nzeroes++;
/* The exponent is now determined. */
if (exponent >= -4
&& exponent < (long) precision)
{
/* Fixed-point notation:
max(exponent,0)+1 digits, then the
decimal point, then the remaining
digits without trailing zeroes. */
if (exponent >= 0)
{
size_t count = exponent + 1;
/* Note: count <= precision = ndigits. */
for (; count > 0; count--)
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT)
|| ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
}
else
{
size_t count = -exponent - 1;
*p++ = '0';
*p++ = decimal_point_char ();
for (; count > 0; count--)
*p++ = '0';
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
}
else
{
/* Exponential notation. */
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT)
|| ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
*p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
# if WIDE_CHAR_VERSION
{
static const wchar_t
decimal_format[] =
{ '%', '+', '.', '2', 'd', '\0' };
SNPRINTF (p, 6 + 1, decimal_format,
exponent);
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, "%+.2d",
exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, "%+.2d",
exponent);
for (ep = expbuf;
(*p = *ep) != '\0'; ep++)
p++;
}
# endif
}
free (digits);
}
}
else
abort ();
# else
/* arg is finite. */
abort ();
# endif
}
END_LONG_DOUBLE_ROUNDING ();
}
}
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
else
# endif
# endif
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
{
double arg = a.arg[dp->arg_index].a.a_double;
if (isnan (arg))
{
if (dp->conversion >= 'A' && dp->conversion <= 'Z')
{
*p++ = 'N';
*p++ = 'A';
*p++ = 'N';
}
else
{
*p++ = 'n';
*p++ = 'a';
*p++ = 'n';
}
}
else
{
int sign = 0;
if (signbit (arg)) /* arg < 0.0 or negative zero */
{
sign = -1;
arg = -arg;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
if (arg > 0.0 && arg + arg == arg)
{
if (dp->conversion >= 'A'
&& dp->conversion <= 'Z')
{
*p++ = 'I';
*p++ = 'N';
*p++ = 'F';
}
else
{
*p++ = 'i';
*p++ = 'n';
*p++ = 'f';
}
}
else
{
# if NEED_PRINTF_DOUBLE
pad_ptr = p;
if (dp->conversion == 'f'
|| dp->conversion == 'F')
{
char *digits;
size_t ndigits;
digits =
scale10_round_decimal_double (arg,
precision);
if (digits == NULL)
goto out_of_memory;
ndigits = strlen (digits);
if (ndigits > precision)
do
{
--ndigits;
*p++ = digits[ndigits];
}
while (ndigits > precision);
else
*p++ = '0';
/* Here ndigits <= precision. */
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > ndigits; precision--)
*p++ = '0';
while (ndigits > 0)
{
--ndigits;
*p++ = digits[ndigits];
}
}
free (digits);
}
else if (dp->conversion == 'e'
|| dp->conversion == 'E')
{
int exponent;
if (arg == 0.0)
{
exponent = 0;
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
}
else
{
/* arg > 0.0. */
int adjusted;
char *digits;
size_t ndigits;
exponent = floorlog10 (arg);
adjusted = 0;
for (;;)
{
digits =
scale10_round_decimal_double (arg,
(int)
precision
-
exponent);
if (digits == NULL)
goto out_of_memory;
ndigits = strlen (digits);
if (ndigits == precision + 1)
break;
if (ndigits < precision
|| ndigits > precision + 2)
/* The exponent was not guessed
precisely enough. */
abort ();
if (adjusted)
/* None of two values of exponent is
the right one. Prevent an endless
loop. */
abort ();
free (digits);
if (ndigits == precision)
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = precision+1. */
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
while (ndigits > 0)
{
--ndigits;
*p++ = digits[ndigits];
}
}
free (digits);
}
*p++ = dp->conversion; /* 'e' or 'E' */
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
{ '%', '+', '.', '3', 'd', '\0' };
# else
{ '%', '+', '.', '2', 'd', '\0' };
# endif
SNPRINTF (p, 6 + 1, decimal_format,
exponent);
}
while (*p != '\0')
p++;
# else
{
static const char decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
"%+.3d";
# else
"%+.2d";
# endif
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, decimal_format,
exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, decimal_format,
exponent);
for (ep = expbuf; (*p = *ep) != '\0';
ep++)
p++;
}
}
# endif
}
else if (dp->conversion == 'g'
|| dp->conversion == 'G')
{
if (precision == 0)
precision = 1;
/* precision >= 1. */
if (arg == 0.0)
/* The exponent is 0, >= -4, < precision.
Use fixed-point notation. */
{
size_t ndigits = precision;
/* Number of trailing zeroes that have to be
dropped. */
size_t nzeroes =
(flags & FLAG_ALT ? 0 : precision - 1);
--ndigits;
*p++ = '0';
if ((flags & FLAG_ALT)
|| ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = '0';
}
}
}
else
{
/* arg > 0.0. */
int exponent;
int adjusted;
char *digits;
size_t ndigits;
size_t nzeroes;
exponent = floorlog10 (arg);
adjusted = 0;
for (;;)
{
digits =
scale10_round_decimal_double (arg,
(int)
(precision
-
1) -
exponent);
if (digits == NULL)
goto out_of_memory;
ndigits = strlen (digits);
if (ndigits == precision)
break;
if (ndigits < precision - 1
|| ndigits > precision + 1)
/* The exponent was not guessed
precisely enough. */
abort ();
if (adjusted)
/* None of two values of exponent is
the right one. Prevent an endless
loop. */
abort ();
free (digits);
if (ndigits < precision)
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = precision. */
/* Determine the number of trailing zeroes
that have to be dropped. */
nzeroes = 0;
if ((flags & FLAG_ALT) == 0)
while (nzeroes < ndigits
&& digits[nzeroes] == '0')
nzeroes++;
/* The exponent is now determined. */
if (exponent >= -4
&& exponent < (long) precision)
{
/* Fixed-point notation:
max(exponent,0)+1 digits, then the
decimal point, then the remaining
digits without trailing zeroes. */
if (exponent >= 0)
{
size_t count = exponent + 1;
/* Note: count <= precision = ndigits. */
for (; count > 0; count--)
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT)
|| ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
}
else
{
size_t count = -exponent - 1;
*p++ = '0';
*p++ = decimal_point_char ();
for (; count > 0; count--)
*p++ = '0';
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
}
else
{
/* Exponential notation. */
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT)
|| ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
*p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
# if WIDE_CHAR_VERSION
{
static const wchar_t
decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
{ '%', '+', '.', '3', 'd', '\0' };
# else
{ '%', '+', '.', '2', 'd', '\0' };
# endif
SNPRINTF (p, 6 + 1, decimal_format,
exponent);
}
while (*p != '\0')
p++;
# else
{
static const char decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
"%+.3d";
# else
"%+.2d";
# endif
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p,
decimal_format,
exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, decimal_format,
exponent);
for (ep = expbuf;
(*p = *ep) != '\0'; ep++)
p++;
}
}
# endif
}
free (digits);
}
}
else
abort ();
# else
/* arg is finite. */
if (!(arg == 0.0))
abort ();
pad_ptr = p;
if (dp->conversion == 'f'
|| dp->conversion == 'F')
{
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
}
else if (dp->conversion == 'e'
|| dp->conversion == 'E')
{
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
*p++ = dp->conversion; /* 'e' or 'E' */
*p++ = '+';
/* Produce the same number of exponent digits as
the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
*p++ = '0';
# endif
*p++ = '0';
*p++ = '0';
}
else if (dp->conversion == 'g'
|| dp->conversion == 'G')
{
*p++ = '0';
if (flags & FLAG_ALT)
{
size_t ndigits =
(precision > 0 ? precision - 1 : 0);
*p++ = decimal_point_char ();
for (; ndigits > 0; --ndigits)
*p++ = '0';
}
}
else
abort ();
# endif
}
}
}
# endif
/* The generated string now extends from tmp to p, with the
zero padding insertion point being at pad_ptr. */
if (has_width && p - tmp < width)
{
size_t pad = width - (p - tmp);
DCHAR_T *end = p + pad;
if (flags & FLAG_LEFT)
{
/* Pad with spaces on the right. */
for (; pad > 0; pad--)
*p++ = ' ';
}
else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
{
/* Pad with zeroes. */
DCHAR_T *q = end;
while (p > pad_ptr)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = '0';
}
else
{
/* Pad with spaces on the left. */
DCHAR_T *q = end;
while (p > tmp)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = ' ';
}
p = end;
}
{
size_t count = p - tmp;
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
code above! */
abort ();
/* Make room for the result. */
if (count >= allocated - length)
{
size_t n = xsum (length, count);
ENSURE_ALLOCATION (n);
}
/* Append the result. */
memcpy (result + length, tmp, count * sizeof (DCHAR_T));
if (tmp != tmpbuf)
free (tmp);
length += count;
}
}
#endif
else
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int has_width;
size_t width;
#endif
#if !USE_SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
int has_precision;
size_t precision;
#endif
#if NEED_PRINTF_UNBOUNDED_PRECISION
int prec_ourselves;
#else
# define prec_ourselves 0
#endif
#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int pad_ourselves;
#else
# define pad_ourselves 0
#endif
TCHAR_T *fbp;
unsigned int prefix_count;
int prefixes[2];
#if !USE_SNPRINTF
size_t tmp_length;
TCHAR_T tmpbuf[700];
TCHAR_T *tmp;
#endif
#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
width = (unsigned int) (-arg);
}
else
width = arg;
}
else
{
const FCHAR_T *digitp = dp->width_start;
do
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
has_width = 1;
}
#endif
#if !USE_SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
has_precision = 0;
precision = 6;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
int arg;
if (!
(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
precision = arg;
has_precision = 1;
}
}
else
{
const FCHAR_T *digitp = dp->precision_start + 1;
precision = 0;
while (digitp != dp->precision_end)
precision =
xsum (xtimes (precision, 10), *digitp++ - '0');
has_precision = 1;
}
}
#endif
#if !USE_SNPRINTF
/* Allocate a temporary buffer of sufficient size for calling
sprintf. */
{
switch (dp->conversion)
{
case 'd':
case 'i':
case 'u':
# if HAVE_LONG_LONG_INT
if (type == TYPE_LONGLONGINT
|| type == TYPE_ULONGLONGINT)
tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.30103 /* binary -> decimal */
) + 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.30103 /* binary -> decimal */
) + 1; /* turn floor into ceil */
else
tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.30103 /* binary -> decimal */
) + 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Multiply by 2, as an estimate for FLAG_GROUP. */
tmp_length = xsum (tmp_length, tmp_length);
/* Add 1, to account for a leading sign. */
tmp_length = xsum (tmp_length, 1);
break;
case 'o':
# if HAVE_LONG_LONG_INT
if (type == TYPE_LONGLONGINT
|| type == TYPE_ULONGLONGINT)
tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.333334 /* binary -> octal */
) + 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.333334 /* binary -> octal */
) + 1; /* turn floor into ceil */
else
tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.333334 /* binary -> octal */
) + 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Add 1, to account for a leading sign. */
tmp_length = xsum (tmp_length, 1);
break;
case 'x':
case 'X':
# if HAVE_LONG_LONG_INT
if (type == TYPE_LONGLONGINT
|| type == TYPE_ULONGLONGINT)
tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
) + 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
) + 1; /* turn floor into ceil */
else
tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
) + 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Add 2, to account for a leading sign or alternate form. */
tmp_length = xsum (tmp_length, 2);
break;
case 'f':
case 'F':
if (type == TYPE_LONGDOUBLE)
tmp_length = (unsigned int) (LDBL_MAX_EXP * 0.30103 /* binary -> decimal */
* 2 /* estimate for FLAG_GROUP */
) + 1 /* turn floor into ceil */
+ 10; /* sign, decimal point etc. */
else
tmp_length = (unsigned int) (DBL_MAX_EXP * 0.30103 /* binary -> decimal */
* 2 /* estimate for FLAG_GROUP */
) + 1 /* turn floor into ceil */
+ 10; /* sign, decimal point etc. */
tmp_length = xsum (tmp_length, precision);
break;
case 'e':
case 'E':
case 'g':
case 'G':
tmp_length = 12; /* sign, decimal point, exponent etc. */
tmp_length = xsum (tmp_length, precision);
break;
case 'a':
case 'A':
if (type == TYPE_LONGDOUBLE)
tmp_length = (unsigned int) (LDBL_DIG * 0.831 /* decimal -> hexadecimal */
) + 1; /* turn floor into ceil */
else
tmp_length = (unsigned int) (DBL_DIG * 0.831 /* decimal -> hexadecimal */
) + 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Account for sign, decimal point etc. */
tmp_length = xsum (tmp_length, 12);
break;
case 'c':
# if HAVE_WINT_T && !WIDE_CHAR_VERSION
if (type == TYPE_WIDE_CHAR)
tmp_length = MB_CUR_MAX;
else
# endif
tmp_length = 1;
break;
case 's':
# if HAVE_WCHAR_T
if (type == TYPE_WIDE_STRING)
{
tmp_length =
local_wcslen (a.arg[dp->arg_index].a.
a_wide_string);
# if !WIDE_CHAR_VERSION
tmp_length = xtimes (tmp_length, MB_CUR_MAX);
# endif
}
else
# endif
tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
break;
case 'p':
tmp_length = (unsigned int) (sizeof (void *) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
) + 1 /* turn floor into ceil */
+ 2; /* account for leading 0x */
break;
default:
abort ();
}
# if ENABLE_UNISTDIO
/* Padding considers the number of characters, therefore the
number of elements after padding may be
> max (tmp_length, width)
but is certainly
<= tmp_length + width. */
tmp_length = xsum (tmp_length, width);
# else
/* Padding considers the number of elements, says POSIX. */
if (tmp_length < width)
tmp_length = width;
# endif
tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
}
if (tmp_length <= sizeof (tmpbuf) / sizeof (TCHAR_T))
tmp = tmpbuf;
else
{
size_t tmp_memsize =
xtimes (tmp_length, sizeof (TCHAR_T));
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
tmp = (TCHAR_T *) malloc (tmp_memsize);
if (tmp == NULL)
/* Out of memory. */
goto out_of_memory;
}
#endif
/* Decide whether to handle the precision ourselves. */
#if NEED_PRINTF_UNBOUNDED_PRECISION
switch (dp->conversion)
{
case 'd':
case 'i':
case 'u':
case 'o':
case 'x':
case 'X':
case 'p':
prec_ourselves = has_precision && (precision > 0);
break;
default:
prec_ourselves = 0;
break;
}
#endif
/* Decide whether to perform the padding ourselves. */
#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
switch (dp->conversion)
{
# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
/* If we need conversion from TCHAR_T[] to DCHAR_T[], we need
to perform the padding after this conversion. Functions
with unistdio extensions perform the padding based on
character count rather than element count. */
case 'c':
case 's':
# endif
# if NEED_PRINTF_FLAG_ZERO
case 'f':
case 'F':
case 'e':
case 'E':
case 'g':
case 'G':
case 'a':
case 'A':
# endif
pad_ourselves = 1;
break;
default:
pad_ourselves = prec_ourselves;
break;
}
#endif
/* Construct the format string for calling snprintf or
sprintf. */
fbp = buf;
*fbp++ = '%';
#if NEED_PRINTF_FLAG_GROUPING
/* The underlying implementation doesn't support the ' flag.
Produce no grouping characters in this case; this is
acceptable because the grouping is locale dependent. */
#else
if (flags & FLAG_GROUP)
*fbp++ = '\'';
#endif
if (flags & FLAG_LEFT)
*fbp++ = '-';
if (flags & FLAG_SHOWSIGN)
*fbp++ = '+';
if (flags & FLAG_SPACE)
*fbp++ = ' ';
if (flags & FLAG_ALT)
*fbp++ = '#';
if (!pad_ourselves)
{
if (flags & FLAG_ZERO)
*fbp++ = '0';
if (dp->width_start != dp->width_end)
{
size_t n = dp->width_end - dp->width_start;
/* The width specification is known to consist only
of standard ASCII characters. */
if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
{
memcpy (fbp, dp->width_start,
n * sizeof (TCHAR_T));
fbp += n;
}
else
{
const FCHAR_T *mp = dp->width_start;
do
*fbp++ = (unsigned char) *mp++;
while (--n > 0);
}
}
}
if (!prec_ourselves)
{
if (dp->precision_start != dp->precision_end)
{
size_t n = dp->precision_end - dp->precision_start;
/* The precision specification is known to consist only
of standard ASCII characters. */
if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
{
memcpy (fbp, dp->precision_start,
n * sizeof (TCHAR_T));
fbp += n;
}
else
{
const FCHAR_T *mp = dp->precision_start;
do
*fbp++ = (unsigned char) *mp++;
while (--n > 0);
}
}
}
switch (type)
{
#if HAVE_LONG_LONG_INT
case TYPE_LONGLONGINT:
case TYPE_ULONGLONGINT:
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
*fbp++ = 'I';
*fbp++ = '6';
*fbp++ = '4';
break;
# else
*fbp++ = 'l';
/*FALLTHROUGH*/
# endif
#endif
case TYPE_LONGINT:
case TYPE_ULONGINT:
#if HAVE_WINT_T
case TYPE_WIDE_CHAR:
#endif
#if HAVE_WCHAR_T
case TYPE_WIDE_STRING:
#endif
*fbp++ = 'l';
break;
case TYPE_LONGDOUBLE:
*fbp++ = 'L';
break;
default:
break;
}
#if NEED_PRINTF_DIRECTIVE_F
if (dp->conversion == 'F')
*fbp = 'f';
else
#endif
*fbp = dp->conversion;
#if USE_SNPRINTF
# if !(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3))
fbp[1] = '%';
fbp[2] = 'n';
fbp[3] = '\0';
# else
/* On glibc2 systems from glibc >= 2.3 - probably also older
ones - we know that snprintf's returns value conforms to
ISO C 99: the gl_SNPRINTF_DIRECTIVE_N test passes.
Therefore we can avoid using %n in this situation.
On glibc2 systems from 2004-10-18 or newer, the use of %n
in format strings in writable memory may crash the program
(if compiled with _FORTIFY_SOURCE=2), so we should avoid it
in this situation. */
fbp[1] = '\0';
# endif
#else
fbp[1] = '\0';
#endif
/* Construct the arguments for calling snprintf or sprintf. */
prefix_count = 0;
if (!pad_ourselves && dp->width_arg_index != ARG_NONE)
{
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
prefixes[prefix_count++] =
a.arg[dp->width_arg_index].a.a_int;
}
if (dp->precision_arg_index != ARG_NONE)
{
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
prefixes[prefix_count++] =
a.arg[dp->precision_arg_index].a.a_int;
}
#if USE_SNPRINTF
/* The SNPRINTF result is appended after result[0..length].
The latter is an array of DCHAR_T; SNPRINTF appends an
array of TCHAR_T to it. This is possible because
sizeof (TCHAR_T) divides sizeof (DCHAR_T) and
alignof (TCHAR_T) <= alignof (DCHAR_T). */
# define TCHARS_PER_DCHAR (sizeof (DCHAR_T) / sizeof (TCHAR_T))
/* Ensure that maxlen below will be >= 2. Needed on BeOS,
where an snprintf() with maxlen==1 acts like sprintf(). */
ENSURE_ALLOCATION (xsum (length,
(2 + TCHARS_PER_DCHAR - 1)
/ TCHARS_PER_DCHAR));
/* Prepare checking whether snprintf returns the count
via %n. */
*(TCHAR_T *) (result + length) = '\0';
#endif
for (;;)
{
int count = -1;
#if USE_SNPRINTF
int retcount = 0;
size_t maxlen = allocated - length;
/* SNPRINTF can fail if its second argument is
> INT_MAX. */
if (maxlen > INT_MAX / TCHARS_PER_DCHAR)
maxlen = INT_MAX / TCHARS_PER_DCHAR;
maxlen = maxlen * TCHARS_PER_DCHAR;
# define SNPRINTF_BUF(arg) \
switch (prefix_count) \
{ \
case 0: \
retcount = SNPRINTF ((TCHAR_T *) (result + length), \
maxlen, buf, \
arg, &count); \
break; \
case 1: \
retcount = SNPRINTF ((TCHAR_T *) (result + length), \
maxlen, buf, \
prefixes[0], arg, &count); \
break; \
case 2: \
retcount = SNPRINTF ((TCHAR_T *) (result + length), \
maxlen, buf, \
prefixes[0], prefixes[1], arg, \
&count); \
break; \
default: \
abort (); \
}
#else
# define SNPRINTF_BUF(arg) \
switch (prefix_count) \
{ \
case 0: \
count = sprintf (tmp, buf, arg); \
break; \
case 1: \
count = sprintf (tmp, buf, prefixes[0], arg); \
break; \
case 2: \
count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
arg); \
break; \
default: \
abort (); \
}
#endif
switch (type)
{
case TYPE_SCHAR:
{
int arg = a.arg[dp->arg_index].a.a_schar;
SNPRINTF_BUF (arg);
}
break;
case TYPE_UCHAR:
{
unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
SNPRINTF_BUF (arg);
}
break;
case TYPE_SHORT:
{
int arg = a.arg[dp->arg_index].a.a_short;
SNPRINTF_BUF (arg);
}
break;
case TYPE_USHORT:
{
unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
SNPRINTF_BUF (arg);
}
break;
case TYPE_INT:
{
int arg = a.arg[dp->arg_index].a.a_int;
SNPRINTF_BUF (arg);
}
break;
case TYPE_UINT:
{
unsigned int arg = a.arg[dp->arg_index].a.a_uint;
SNPRINTF_BUF (arg);
}
break;
case TYPE_LONGINT:
{
long int arg = a.arg[dp->arg_index].a.a_longint;
SNPRINTF_BUF (arg);
}
break;
case TYPE_ULONGINT:
{
unsigned long int arg =
a.arg[dp->arg_index].a.a_ulongint;
SNPRINTF_BUF (arg);
}
break;
#if HAVE_LONG_LONG_INT
case TYPE_LONGLONGINT:
{
long long int arg =
a.arg[dp->arg_index].a.a_longlongint;
SNPRINTF_BUF (arg);
}
break;
case TYPE_ULONGLONGINT:
{
unsigned long long int arg =
a.arg[dp->arg_index].a.a_ulonglongint;
SNPRINTF_BUF (arg);
}
break;
#endif
case TYPE_DOUBLE:
{
double arg = a.arg[dp->arg_index].a.a_double;
SNPRINTF_BUF (arg);
}
break;
case TYPE_LONGDOUBLE:
{
long double arg =
a.arg[dp->arg_index].a.a_longdouble;
SNPRINTF_BUF (arg);
}
break;
case TYPE_CHAR:
{
int arg = a.arg[dp->arg_index].a.a_char;
SNPRINTF_BUF (arg);
}
break;
#if HAVE_WINT_T
case TYPE_WIDE_CHAR:
{
wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
SNPRINTF_BUF (arg);
}
break;
#endif
case TYPE_STRING:
{
const char *arg = a.arg[dp->arg_index].a.a_string;
SNPRINTF_BUF (arg);
}
break;
#if HAVE_WCHAR_T
case TYPE_WIDE_STRING:
{
const wchar_t *arg =
a.arg[dp->arg_index].a.a_wide_string;
SNPRINTF_BUF (arg);
}
break;
#endif
case TYPE_POINTER:
{
void *arg = a.arg[dp->arg_index].a.a_pointer;
SNPRINTF_BUF (arg);
}
break;
default:
abort ();
}
#if USE_SNPRINTF
/* Portability: Not all implementations of snprintf()
are ISO C 99 compliant. Determine the number of
bytes that snprintf() has produced or would have
produced. */
if (count >= 0)
{
/* Verify that snprintf() has NUL-terminated its
result. */
if (count < maxlen
&& ((TCHAR_T *) (result + length))[count] != '\0')
abort ();
/* Portability hack. */
if (retcount > count)
count = retcount;
}
else
{
/* snprintf() doesn't understand the '%n'
directive. */
if (fbp[1] != '\0')
{
/* Don't use the '%n' directive; instead, look
at the snprintf() return value. */
fbp[1] = '\0';
continue;
}
else
{
/* Look at the snprintf() return value. */
if (retcount < 0)
{
/* HP-UX 10.20 snprintf() is doubly deficient:
It doesn't understand the '%n' directive,
*and* it returns -1 (rather than the length
that would have been required) when the
buffer is too small. */
size_t bigger_need =
xsum (xtimes (allocated, 2), 12);
ENSURE_ALLOCATION (bigger_need);
continue;
}
else
count = retcount;
}
}
#endif
/* Attempt to handle failure. */
if (count < 0)
{
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EINVAL;
return NULL;
}
#if USE_SNPRINTF
/* Handle overflow of the allocated buffer.
If such an overflow occurs, a C99 compliant snprintf()
returns a count >= maxlen. However, a non-compliant
snprintf() function returns only count = maxlen - 1. To
cover both cases, test whether count >= maxlen - 1. */
if ((unsigned int) count + 1 >= maxlen)
{
/* If maxlen already has attained its allowed maximum,
allocating more memory will not increase maxlen.
Instead of looping, bail out. */
if (maxlen == INT_MAX / TCHARS_PER_DCHAR)
goto overflow;
else
{
/* Need at least (count + 1) * sizeof (TCHAR_T)
bytes. (The +1 is for the trailing NUL.)
But ask for (count + 2) * sizeof (TCHAR_T)
bytes, so that in the next round, we likely get
maxlen > (unsigned int) count + 1
and so we don't get here again.
And allocate proportionally, to avoid looping
eternally if snprintf() reports a too small
count. */
size_t n = xmax (xsum (length,
((unsigned int) count + 2
+ TCHARS_PER_DCHAR - 1)
/ TCHARS_PER_DCHAR),
xtimes (allocated, 2));
ENSURE_ALLOCATION (n);
continue;
}
}
#endif
#if NEED_PRINTF_UNBOUNDED_PRECISION
if (prec_ourselves)
{
/* Handle the precision. */
TCHAR_T *prec_ptr =
# if USE_SNPRINTF
(TCHAR_T *) (result + length);
# else
tmp;
# endif
size_t prefix_count;
size_t move;
prefix_count = 0;
/* Put the additional zeroes after the sign. */
if (count >= 1
&& (*prec_ptr == '-' || *prec_ptr == '+'
|| *prec_ptr == ' '))
prefix_count = 1;
/* Put the additional zeroes after the 0x prefix if
(flags & FLAG_ALT) || (dp->conversion == 'p'). */
else if (count >= 2
&& prec_ptr[0] == '0'
&& (prec_ptr[1] == 'x'
|| prec_ptr[1] == 'X'))
prefix_count = 2;
move = count - prefix_count;
if (precision > move)
{
/* Insert zeroes. */
size_t insert = precision - move;
TCHAR_T *prec_end;
# if USE_SNPRINTF
size_t n = xsum (length,
(count + insert +
TCHARS_PER_DCHAR -
1) / TCHARS_PER_DCHAR);
length +=
(count + TCHARS_PER_DCHAR -
1) / TCHARS_PER_DCHAR;
ENSURE_ALLOCATION (n);
length -=
(count + TCHARS_PER_DCHAR -
1) / TCHARS_PER_DCHAR;
prec_ptr = (TCHAR_T *) (result + length);
# endif
prec_end = prec_ptr + count;
prec_ptr += prefix_count;
while (prec_end > prec_ptr)
{
prec_end--;
prec_end[insert] = prec_end[0];
}
prec_end += insert;
do
*--prec_end = '0';
while (prec_end > prec_ptr);
count += insert;
}
}
#endif
#if !DCHAR_IS_TCHAR
# if !USE_SNPRINTF
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
code above! */
abort ();
# endif
/* Convert from TCHAR_T[] to DCHAR_T[]. */
if (dp->conversion == 'c' || dp->conversion == 's')
{
/* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING
TYPE_WIDE_STRING.
The result string is not certainly ASCII. */
const TCHAR_T *tmpsrc;
DCHAR_T *tmpdst;
size_t tmpdst_len;
/* This code assumes that TCHAR_T is 'char'. */
typedef int TCHAR_T_verify
[2 * (sizeof (TCHAR_T) == 1) - 1];
# if USE_SNPRINTF
tmpsrc = (TCHAR_T *) (result + length);
# else
tmpsrc = tmp;
# endif
tmpdst = NULL;
tmpdst_len = 0;
if (DCHAR_CONV_FROM_ENCODING (locale_charset (),
iconveh_question_mark,
tmpsrc, count,
NULL,
&tmpdst, &tmpdst_len)
< 0)
{
int saved_errno = errno;
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
ENSURE_ALLOCATION (xsum (length, tmpdst_len));
DCHAR_CPY (result + length, tmpdst, tmpdst_len);
free (tmpdst);
count = tmpdst_len;
}
else
{
/* The result string is ASCII.
Simple 1:1 conversion. */
# if USE_SNPRINTF
/* If sizeof (DCHAR_T) == sizeof (TCHAR_T), it's a
no-op conversion, in-place on the array starting
at (result + length). */
if (sizeof (DCHAR_T) != sizeof (TCHAR_T))
# endif
{
const TCHAR_T *tmpsrc;
DCHAR_T *tmpdst;
size_t n;
# if USE_SNPRINTF
if (result == resultbuf)
{
tmpsrc = (TCHAR_T *) (result + length);
/* ENSURE_ALLOCATION will not move tmpsrc
(because it's part of resultbuf). */
ENSURE_ALLOCATION (xsum (length, count));
}
else
{
/* ENSURE_ALLOCATION will move the array
(because it uses realloc(). */
ENSURE_ALLOCATION (xsum (length, count));
tmpsrc = (TCHAR_T *) (result + length);
}
# else
tmpsrc = tmp;
ENSURE_ALLOCATION (xsum (length, count));
# endif
tmpdst = result + length;
/* Copy backwards, because of overlapping. */
tmpsrc += count;
tmpdst += count;
for (n = count; n > 0; n--)
*--tmpdst = (unsigned char) *--tmpsrc;
}
}
#endif
#if DCHAR_IS_TCHAR && !USE_SNPRINTF
/* Make room for the result. */
if (count > allocated - length)
{
/* Need at least count elements. But allocate
proportionally. */
size_t n =
xmax (xsum (length, count), xtimes (allocated, 2));
ENSURE_ALLOCATION (n);
}
#endif
/* Here count <= allocated - length. */
/* Perform padding. */
#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
if (pad_ourselves && has_width)
{
size_t w;
# if ENABLE_UNISTDIO
/* Outside POSIX, it's preferrable to compare the width
against the number of _characters_ of the converted
value. */
w = DCHAR_MBSNLEN (result + length, count);
# else
/* The width is compared against the number of _bytes_
of the converted value, says POSIX. */
w = count;
# endif
if (w < width)
{
size_t pad = width - w;
# if USE_SNPRINTF
/* Make room for the result. */
if (xsum (count, pad) > allocated - length)
{
/* Need at least count + pad elements. But
allocate proportionally. */
size_t n = xmax (xsum3 (length, count, pad),
xtimes (allocated, 2));
length += count;
ENSURE_ALLOCATION (n);
length -= count;
}
/* Here count + pad <= allocated - length. */
# endif
{
# if !DCHAR_IS_TCHAR || USE_SNPRINTF
DCHAR_T *const rp = result + length;
# else
DCHAR_T *const rp = tmp;
# endif
DCHAR_T *p = rp + count;
DCHAR_T *end = p + pad;
# if NEED_PRINTF_FLAG_ZERO
DCHAR_T *pad_ptr;
# if !DCHAR_IS_TCHAR
if (dp->conversion == 'c'
|| dp->conversion == 's')
/* No zero-padding for string directives. */
pad_ptr = NULL;
else
# endif
{
pad_ptr = (*rp == '-' ? rp + 1 : rp);
/* No zero-padding of "inf" and "nan". */
if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
|| (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
pad_ptr = NULL;
}
# endif
/* The generated string now extends from rp to p,
with the zero padding insertion point being at
pad_ptr. */
count = count + pad; /* = end - rp */
if (flags & FLAG_LEFT)
{
/* Pad with spaces on the right. */
for (; pad > 0; pad--)
*p++ = ' ';
}
# if NEED_PRINTF_FLAG_ZERO
else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
{
/* Pad with zeroes. */
DCHAR_T *q = end;
while (p > pad_ptr)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = '0';
}
# endif
else
{
/* Pad with spaces on the left. */
DCHAR_T *q = end;
while (p > rp)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = ' ';
}
}
}
}
#endif
#if DCHAR_IS_TCHAR && !USE_SNPRINTF
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
code above! */
abort ();
#endif
/* Here still count <= allocated - length. */
#if !DCHAR_IS_TCHAR || USE_SNPRINTF
/* The snprintf() result did fit. */
#else
/* Append the sprintf() result. */
memcpy (result + length, tmp, count * sizeof (DCHAR_T));
#endif
#if !USE_SNPRINTF
if (tmp != tmpbuf)
free (tmp);
#endif
#if NEED_PRINTF_DIRECTIVE_F
if (dp->conversion == 'F')
{
/* Convert the %f result to upper case for %F. */
DCHAR_T *rp = result + length;
size_t rc;
for (rc = count; rc > 0; rc--, rp++)
if (*rp >= 'a' && *rp <= 'z')
*rp = *rp - 'a' + 'A';
}
#endif
length += count;
break;
}
}
}
}
/* Add the final NUL. */
ENSURE_ALLOCATION (xsum (length, 1));
result[length] = '\0';
if (result != resultbuf && length + 1 < allocated)
{
/* Shrink the allocated memory if possible. */
DCHAR_T *memory;
memory =
(DCHAR_T *) realloc (result, (length + 1) * sizeof (DCHAR_T));
if (memory != NULL)
result = memory;
}
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
*lengthp = length;
/* Note that we can produce a big string of a length > INT_MAX. POSIX
says that snprintf() fails with errno = EOVERFLOW in this case, but
that's only because snprintf() returns an 'int'. This function does
not have this limitation. */
return result;
overflow:
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EOVERFLOW;
return NULL;
out_of_memory:
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
out_of_memory_1:
CLEANUP ();
errno = ENOMEM;
return NULL;
}
}
#undef TCHARS_PER_DCHAR
#undef SNPRINTF
#undef USE_SNPRINTF
#undef DCHAR_CPY
#undef PRINTF_PARSE
#undef DIRECTIVES
#undef DIRECTIVE
#undef DCHAR_IS_TCHAR
#undef TCHAR_T
#undef DCHAR_T
#undef FCHAR_T
#undef VASNPRINTF
+81
View File
@@ -0,0 +1,81 @@
/* vsprintf with automatic memory allocation.
Copyright (C) 2002-2004, 2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _VASNPRINTF_H
#define _VASNPRINTF_H
/* Get va_list. */
#include <stdarg.h>
/* Get size_t. */
#include <stddef.h>
#ifndef __attribute__
/* This feature is available in gcc versions 2.5 and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
# define __attribute__(Spec) /* empty */
# endif
/* The __-protected variants of `format' and `printf' attributes
are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
# define __format__ format
# define __printf__ printf
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Write formatted output to a string dynamically allocated with malloc().
You can pass a preallocated buffer for the result in RESULTBUF and its
size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
If successful, return the address of the string (this may be = RESULTBUF
if no dynamic memory allocation was necessary) and set *LENGTHP to the
number of resulting bytes, excluding the trailing NUL. Upon error, set
errno and return NULL.
When dynamic memory allocation occurs, the preallocated buffer is left
alone (with possibly modified contents). This makes it possible to use
a statically allocated or stack-allocated buffer, like this:
char buf[100];
size_t len = sizeof (buf);
char *output = vasnprintf (buf, &len, format, args);
if (output == NULL)
... error handling ...;
else
{
... use the output string ...;
if (output != buf)
free (output);
}
*/
#if REPLACE_VASNPRINTF
# define asnprintf rpl_asnprintf
# define vasnprintf rpl_vasnprintf
#endif
extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
__attribute__ ((__format__ (__printf__, 3, 4)));
extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
__attribute__ ((__format__ (__printf__, 3, 0)));
#ifdef __cplusplus
}
#endif
#endif /* _VASNPRINTF_H */
+56
View File
@@ -0,0 +1,56 @@
/* Formatted output to strings.
Copyright (C) 1999, 2002, 2006-2007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <config.h>
/* Specification. */
#ifdef IN_LIBASPRINTF
# include "vasprintf.h"
#else
# include <stdio.h>
#endif
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include "vasnprintf.h"
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
#ifndef EOVERFLOW
# define EOVERFLOW E2BIG
#endif
int
vasprintf (char **resultp, const char *format, va_list args)
{
size_t length;
char *result = vasnprintf (NULL, &length, format, args);
if (result == NULL)
return -1;
if (length > INT_MAX)
{
free (result);
errno = EOVERFLOW;
return -1;
}
*resultp = result;
/* Return the number of resulting bytes, excluding the trailing NUL. */
return length;
}
+109
View File
@@ -0,0 +1,109 @@
/* xsize.h -- Checked size_t computations.
Copyright (C) 2003 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _XSIZE_H
#define _XSIZE_H
/* Get size_t. */
#include <stddef.h>
/* Get SIZE_MAX. */
#include <limits.h>
#if HAVE_STDINT_H
# include <stdint.h>
#endif
/* The size of memory objects is often computed through expressions of
type size_t. Example:
void* p = malloc (header_size + n * element_size).
These computations can lead to overflow. When this happens, malloc()
returns a piece of memory that is way too small, and the program then
crashes while attempting to fill the memory.
To avoid this, the functions and macros in this file check for overflow.
The convention is that SIZE_MAX represents overflow.
malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
implementation that uses mmap --, it's recommended to use size_overflow_p()
or size_in_bounds_p() before invoking malloc().
The example thus becomes:
size_t size = xsum (header_size, xtimes (n, element_size));
void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
*/
/* Convert an arbitrary value >= 0 to type size_t. */
#define xcast_size_t(N) \
((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
/* Sum of two sizes, with overflow check. */
static inline size_t
#if __GNUC__ >= 3
__attribute__ ((__pure__))
#endif
xsum (size_t size1, size_t size2)
{
size_t sum = size1 + size2;
return (sum >= size1 ? sum : SIZE_MAX);
}
/* Sum of three sizes, with overflow check. */
static inline size_t
#if __GNUC__ >= 3
__attribute__ ((__pure__))
#endif
xsum3 (size_t size1, size_t size2, size_t size3)
{
return xsum (xsum (size1, size2), size3);
}
/* Sum of four sizes, with overflow check. */
static inline size_t
#if __GNUC__ >= 3
__attribute__ ((__pure__))
#endif
xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
{
return xsum (xsum (xsum (size1, size2), size3), size4);
}
/* Maximum of two sizes, with overflow check. */
static inline size_t
#if __GNUC__ >= 3
__attribute__ ((__pure__))
#endif
xmax (size_t size1, size_t size2)
{
/* No explicit check is needed here, because for any n:
max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */
return (size1 >= size2 ? size1 : size2);
}
/* Multiplication of a count with an element size, with overflow check.
The count must be >= 0 and the element size must be > 0.
This is a macro, not an inline function, so that it works correctly even
when N is of a wider tupe and N > SIZE_MAX. */
#define xtimes(N, ELSIZE) \
((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
/* Check for overflow. */
#define size_overflow_p(SIZE) \
((SIZE) == SIZE_MAX)
/* Check against overflow. */
#define size_in_bounds_p(SIZE) \
((SIZE) != SIZE_MAX)
#endif /* _XSIZE_H */