Build support for Microsoft Windows.
This commit is contained in:
		@@ -21,10 +21,15 @@ artifacts {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
library {
 | 
			
		||||
    linkage.set( [Linkage.STATIC, Linkage.SHARED] )
 | 
			
		||||
    linkage.set( [ Linkage.SHARED ] )
 | 
			
		||||
 | 
			
		||||
    // Reconfigure the toolchain from C++ to C.
 | 
			
		||||
    toolChains {
 | 
			
		||||
        withType( VisualCpp ) {
 | 
			
		||||
            eachPlatform {
 | 
			
		||||
                cppCompiler.withArguments { addAll( ["/TC", "/DMPW_SODIUM=1"] ) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        withType( GccCompatibleToolChain ) {
 | 
			
		||||
            eachPlatform {
 | 
			
		||||
                cppCompiler.withArguments { addAll( ["-x", "c", "-std=c11", "-Werror", "-DMPW_SODIUM=1"] ) }
 | 
			
		||||
@@ -52,7 +57,7 @@ library {
 | 
			
		||||
 | 
			
		||||
            // Depend on libsodium from `lib`; run `lib/bin/build_libsodium-${platform}` first.
 | 
			
		||||
            add( includePathConfiguration.name,
 | 
			
		||||
                 files( "../../../lib/libsodium/build-${platform}~/out/include" ) )
 | 
			
		||||
                 files( "../../../lib/libsodium/src/libsodium/include" ) )
 | 
			
		||||
            add( linkLibraries.name,
 | 
			
		||||
                 fileTree( "../../../lib/libsodium/build-${platform}~/out/lib" ) )
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -206,7 +206,7 @@ static bool mpw_marshal_write_flat(
 | 
			
		||||
        if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
 | 
			
		||||
            mpw_string_pushf( out, "%s  %8ld  %lu:%lu:%lu  %25s\t%25s\t%s\n",
 | 
			
		||||
                    dateString, (long)site->uses, (long)site->type, (long)site->algorithm, (long)site->counter,
 | 
			
		||||
                    loginContent?: "", site->name, content?: "" );
 | 
			
		||||
                    loginContent? loginContent: "", site->name, content? content: "" );
 | 
			
		||||
        mpw_free_strings( &content, &loginContent, NULL );
 | 
			
		||||
    }
 | 
			
		||||
    mpw_free( &masterKey, MPMasterKeySize );
 | 
			
		||||
@@ -871,21 +871,14 @@ const MPMarshalFormat mpw_formatWithName(
 | 
			
		||||
    if (!formatName || !strlen( formatName ))
 | 
			
		||||
        return MPMarshalFormatNone;
 | 
			
		||||
 | 
			
		||||
    // Lower-case to standardize it.
 | 
			
		||||
    size_t stdFormatNameSize = strlen( formatName );
 | 
			
		||||
    char stdFormatName[stdFormatNameSize + 1];
 | 
			
		||||
    for (size_t c = 0; c < stdFormatNameSize; ++c)
 | 
			
		||||
        stdFormatName[c] = (char)tolower( formatName[c] );
 | 
			
		||||
    stdFormatName[stdFormatNameSize] = '\0';
 | 
			
		||||
 | 
			
		||||
    if (strncmp( mpw_nameForFormat( MPMarshalFormatNone ), stdFormatName, strlen( stdFormatName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForFormat( MPMarshalFormatNone ), formatName, strlen( formatName ) ) == 0)
 | 
			
		||||
        return MPMarshalFormatNone;
 | 
			
		||||
    if (strncmp( mpw_nameForFormat( MPMarshalFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForFormat( MPMarshalFormatFlat ), formatName, strlen( formatName ) ) == 0)
 | 
			
		||||
        return MPMarshalFormatFlat;
 | 
			
		||||
    if (strncmp( mpw_nameForFormat( MPMarshalFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForFormat( MPMarshalFormatJSON ), formatName, strlen( formatName ) ) == 0)
 | 
			
		||||
        return MPMarshalFormatJSON;
 | 
			
		||||
 | 
			
		||||
    dbg( "Not a format name: %s", stdFormatName );
 | 
			
		||||
    dbg( "Not a format name: %s", formatName );
 | 
			
		||||
    return (MPMarshalFormat)ERR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -53,38 +53,31 @@ const MPResultType mpw_typeWithName(const char *typeName) {
 | 
			
		||||
            return MPResultTypeDeriveKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Lower-case typeName to standardize it.
 | 
			
		||||
    size_t stdTypeNameSize = strlen( typeName );
 | 
			
		||||
    char stdTypeName[stdTypeNameSize + 1];
 | 
			
		||||
    for (size_t c = 0; c < stdTypeNameSize; ++c)
 | 
			
		||||
        stdTypeName[c] = (char)tolower( typeName[c] );
 | 
			
		||||
    stdTypeName[stdTypeNameSize] = '\0';
 | 
			
		||||
 | 
			
		||||
    // Find what password type is represented by the type name.
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeTemplateMaximum ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateMaximum ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeTemplateMaximum;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeTemplateLong ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateLong ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeTemplateLong;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeTemplateMedium ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateMedium ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeTemplateMedium;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeTemplateBasic ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateBasic ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeTemplateBasic;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeTemplateShort ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateShort ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeTemplateShort;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeTemplatePIN ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplatePIN ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeTemplatePIN;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeTemplateName ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateName ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeTemplateName;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeTemplatePhrase ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplatePhrase ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeTemplatePhrase;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeStatefulPersonal ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeStatefulPersonal ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeStatefulPersonal;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeStatefulDevice ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeStatefulDevice ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeStatefulDevice;
 | 
			
		||||
    if (strncmp( mpw_nameForType( MPResultTypeDeriveKey ), stdTypeName, strlen( stdTypeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForType( MPResultTypeDeriveKey ), typeName, strlen( typeName ) ) == 0)
 | 
			
		||||
        return MPResultTypeDeriveKey;
 | 
			
		||||
 | 
			
		||||
    dbg( "Not a generated type name: %s", stdTypeName );
 | 
			
		||||
    dbg( "Not a generated type name: %s", typeName );
 | 
			
		||||
    return (MPResultType)ERR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -129,35 +122,35 @@ const char **mpw_templatesForType(MPResultType type, size_t *count) {
 | 
			
		||||
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case MPResultTypeTemplateMaximum:
 | 
			
		||||
            return mpw_alloc_array( count, const char *,
 | 
			
		||||
                    "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" );
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno", NULL );
 | 
			
		||||
        case MPResultTypeTemplateLong:
 | 
			
		||||
            return mpw_alloc_array( count, const char *,
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno",
 | 
			
		||||
                    "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno",
 | 
			
		||||
                    "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno",
 | 
			
		||||
                    "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno",
 | 
			
		||||
                    "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno",
 | 
			
		||||
                    "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno",
 | 
			
		||||
                    "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" );
 | 
			
		||||
                    "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno", NULL );
 | 
			
		||||
        case MPResultTypeTemplateMedium:
 | 
			
		||||
            return mpw_alloc_array( count, const char *,
 | 
			
		||||
                    "CvcnoCvc", "CvcCvcno" );
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    "CvcnoCvc", "CvcCvcno", NULL );
 | 
			
		||||
        case MPResultTypeTemplateShort:
 | 
			
		||||
            return mpw_alloc_array( count, const char *,
 | 
			
		||||
                    "Cvcn" );
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    "Cvcn", NULL );
 | 
			
		||||
        case MPResultTypeTemplateBasic:
 | 
			
		||||
            return mpw_alloc_array( count, const char *,
 | 
			
		||||
                    "aaanaaan", "aannaaan", "aaannaaa" );
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    "aaanaaan", "aannaaan", "aaannaaa", NULL );
 | 
			
		||||
        case MPResultTypeTemplatePIN:
 | 
			
		||||
            return mpw_alloc_array( count, const char *,
 | 
			
		||||
                    "nnnn" );
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    "nnnn", NULL );
 | 
			
		||||
        case MPResultTypeTemplateName:
 | 
			
		||||
            return mpw_alloc_array( count, const char *,
 | 
			
		||||
                    "cvccvcvcv" );
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    "cvccvcvcv", NULL );
 | 
			
		||||
        case MPResultTypeTemplatePhrase:
 | 
			
		||||
            return mpw_alloc_array( count, const char *,
 | 
			
		||||
                    "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" );
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv", NULL );
 | 
			
		||||
        default: {
 | 
			
		||||
            dbg( "Unknown generated type: %d", type );
 | 
			
		||||
            return NULL;
 | 
			
		||||
@@ -177,21 +170,14 @@ const char *mpw_templateForType(MPResultType type, uint8_t templateIndex) {
 | 
			
		||||
 | 
			
		||||
const MPKeyPurpose mpw_purposeWithName(const char *purposeName) {
 | 
			
		||||
 | 
			
		||||
    // Lower-case and trim optionally leading "generated" string from typeName to standardize it.
 | 
			
		||||
    size_t stdPurposeNameSize = strlen( purposeName );
 | 
			
		||||
    char stdPurposeName[stdPurposeNameSize + 1];
 | 
			
		||||
    for (size_t c = 0; c < stdPurposeNameSize; ++c)
 | 
			
		||||
        stdPurposeName[c] = (char)tolower( purposeName[c] );
 | 
			
		||||
    stdPurposeName[stdPurposeNameSize] = '\0';
 | 
			
		||||
 | 
			
		||||
    if (strncmp( mpw_nameForPurpose( MPKeyPurposeAuthentication ), stdPurposeName, strlen( stdPurposeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForPurpose( MPKeyPurposeAuthentication ), purposeName, strlen( purposeName ) ) == 0)
 | 
			
		||||
        return MPKeyPurposeAuthentication;
 | 
			
		||||
    if (strncmp( mpw_nameForPurpose( MPKeyPurposeIdentification ), stdPurposeName, strlen( stdPurposeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForPurpose( MPKeyPurposeIdentification ), purposeName, strlen( purposeName ) ) == 0)
 | 
			
		||||
        return MPKeyPurposeIdentification;
 | 
			
		||||
    if (strncmp( mpw_nameForPurpose( MPKeyPurposeRecovery ), stdPurposeName, strlen( stdPurposeName ) ) == 0)
 | 
			
		||||
    if (mpw_strncasecmp( mpw_nameForPurpose( MPKeyPurposeRecovery ), purposeName, strlen( purposeName ) ) == 0)
 | 
			
		||||
        return MPKeyPurposeRecovery;
 | 
			
		||||
 | 
			
		||||
    dbg( "Not a purpose name: %s", stdPurposeName );
 | 
			
		||||
    dbg( "Not a purpose name: %s", purposeName );
 | 
			
		||||
    return (MPKeyPurpose)ERR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,25 @@ void mpw_uint64(const uint64_t number, uint8_t buf[8]) {
 | 
			
		||||
    buf[7] = (uint8_t)((number >> 0L) & UINT8_MAX);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char **mpw_strings(size_t *count, const char *strings, ...) {
 | 
			
		||||
 | 
			
		||||
    va_list args;
 | 
			
		||||
    va_start( args, strings );
 | 
			
		||||
    char **array = NULL;
 | 
			
		||||
    size_t arraySize = 0;
 | 
			
		||||
    for (const char *string; string = va_arg( args, const char * );) {
 | 
			
		||||
        size_t cursor = arraySize;
 | 
			
		||||
        if (!mpw_realloc( &array, &arraySize, sizeof(string) )) {
 | 
			
		||||
            mpw_free( &array, arraySize );
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        array[cursor] = string;
 | 
			
		||||
    }
 | 
			
		||||
    va_end( args );
 | 
			
		||||
 | 
			
		||||
    return array;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool mpw_push_buf(uint8_t **buffer, size_t *bufferSize, const void *pushBuffer, const size_t pushSize) {
 | 
			
		||||
 | 
			
		||||
    if (!buffer || !bufferSize || !pushBuffer || !pushSize)
 | 
			
		||||
@@ -275,14 +294,15 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    // IV = zero
 | 
			
		||||
    uint8_t iv[AES_BLOCKLEN];
 | 
			
		||||
    mpw_zero( iv, sizeof iv );
 | 
			
		||||
    static uint8_t *iv = NULL;
 | 
			
		||||
    if (!iv)
 | 
			
		||||
        iv = calloc( AES_BLOCKLEN, sizeof( uint8_t ) );
 | 
			
		||||
 | 
			
		||||
    // Add PKCS#7 padding
 | 
			
		||||
    uint32_t aesSize = ((uint32_t)*bufSize + AES_BLOCKLEN - 1) & -AES_BLOCKLEN; // round up to block size.
 | 
			
		||||
    if (encrypt && !(*bufSize % AES_BLOCKLEN)) // add pad block if plain text fits block size.
 | 
			
		||||
        encrypt += AES_BLOCKLEN;
 | 
			
		||||
    uint8_t aesBuf[aesSize];
 | 
			
		||||
    uint8_t *aesBuf = malloc( aesSize );
 | 
			
		||||
    memcpy( aesBuf, buf, *bufSize );
 | 
			
		||||
    memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
 | 
			
		||||
    uint8_t *resultBuf = malloc( aesSize );
 | 
			
		||||
@@ -291,8 +311,7 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
 | 
			
		||||
        AES_CBC_encrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
 | 
			
		||||
    else
 | 
			
		||||
        AES_CBC_decrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
 | 
			
		||||
    mpw_zero( aesBuf, aesSize );
 | 
			
		||||
    mpw_zero( iv, AES_BLOCKLEN );
 | 
			
		||||
    mpw_free( aesBuf, aesSize );
 | 
			
		||||
 | 
			
		||||
    // Truncate PKCS#7 padding
 | 
			
		||||
    if (encrypt)
 | 
			
		||||
@@ -496,3 +515,15 @@ char *mpw_strndup(const char *src, size_t max) {
 | 
			
		||||
 | 
			
		||||
    return dst;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int *mpw_strncasecmp(const char *s1, const char *s2, size_t max) {
 | 
			
		||||
 | 
			
		||||
    if (s1 && s2 && max)
 | 
			
		||||
        for (; --max > 0; ++s1, ++s2) {
 | 
			
		||||
            int cmp = tolower( *(unsigned char *)s1 ) - tolower( *(unsigned char *)s2 );
 | 
			
		||||
            if (!cmp || *s1 == '\0')
 | 
			
		||||
                return cmp;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -33,36 +33,36 @@ extern int mpw_verbosity;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef mpw_log
 | 
			
		||||
#define mpw_log(level, ...) ({ \
 | 
			
		||||
#define mpw_log(level, format, ...) do { \
 | 
			
		||||
    if (mpw_verbosity >= level) { \
 | 
			
		||||
        mpw_log_do( level, ##__VA_ARGS__ ); \
 | 
			
		||||
    }; })
 | 
			
		||||
        mpw_log_do( level, format, ##__VA_ARGS__ ); \
 | 
			
		||||
    }; } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef trc
 | 
			
		||||
/** Logging internal state. */
 | 
			
		||||
#define trc_level 3
 | 
			
		||||
#define trc(...) mpw_log( trc_level, ##__VA_ARGS__ )
 | 
			
		||||
#define trc(format, ...) mpw_log( trc_level, format, ##__VA_ARGS__ )
 | 
			
		||||
 | 
			
		||||
/** Logging state and events interesting when investigating issues. */
 | 
			
		||||
#define dbg_level 2
 | 
			
		||||
#define dbg(...) mpw_log( dbg_level, ##__VA_ARGS__ )
 | 
			
		||||
#define dbg(format, ...) mpw_log( dbg_level, format, ##__VA_ARGS__ )
 | 
			
		||||
 | 
			
		||||
/** User messages. */
 | 
			
		||||
#define inf_level 1
 | 
			
		||||
#define inf(...) mpw_log( inf_level, ##__VA_ARGS__ )
 | 
			
		||||
#define inf(format, ...) mpw_log( inf_level, format, ##__VA_ARGS__ )
 | 
			
		||||
 | 
			
		||||
/** Recoverable issues and user suggestions. */
 | 
			
		||||
#define wrn_level 0
 | 
			
		||||
#define wrn(...) mpw_log( wrn_level, ##__VA_ARGS__ )
 | 
			
		||||
#define wrn(format, ...) mpw_log( wrn_level, format, ##__VA_ARGS__ )
 | 
			
		||||
 | 
			
		||||
/** Unrecoverable issues. */
 | 
			
		||||
#define err_level -1
 | 
			
		||||
#define err(...) mpw_log( err_level, ##__VA_ARGS__ )
 | 
			
		||||
#define err(format, ...) mpw_log( err_level, format, ##__VA_ARGS__ )
 | 
			
		||||
 | 
			
		||||
/** Issues that lead to abortion. */
 | 
			
		||||
#define ftl_level -2
 | 
			
		||||
#define ftl(...) mpw_log( ftl_level, ##__VA_ARGS__ )
 | 
			
		||||
#define ftl(format, ...) mpw_log( ftl_level, format, ##__VA_ARGS__ )
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef min
 | 
			
		||||
@@ -98,14 +98,8 @@ void mpw_uint32(const uint32_t number, uint8_t buf[4]);
 | 
			
		||||
void mpw_uint64(const uint64_t number, uint8_t buf[8]);
 | 
			
		||||
 | 
			
		||||
/** Allocate a new array of _type, assign its element count to _count if not NULL and populate it with the varargs. */
 | 
			
		||||
#define mpw_alloc_array(_count, _type, ...) ({ \
 | 
			
		||||
    _type stackElements[] = { __VA_ARGS__ }; \
 | 
			
		||||
    if (_count) \
 | 
			
		||||
        *_count = sizeof( stackElements ) / sizeof( _type ); \
 | 
			
		||||
    _type *allocElements = malloc( sizeof( stackElements ) ); \
 | 
			
		||||
    memcpy( allocElements, stackElements, sizeof( stackElements ) ); \
 | 
			
		||||
    allocElements; \
 | 
			
		||||
 })
 | 
			
		||||
const char **mpw_strings(
 | 
			
		||||
        size_t *count, const char *strings, ...);
 | 
			
		||||
 | 
			
		||||
/** Push a buffer onto a buffer.  reallocs the given buffer and appends the given buffer. */
 | 
			
		||||
bool mpw_push_buf(
 | 
			
		||||
@@ -150,6 +144,20 @@ bool __mpw_free_string(
 | 
			
		||||
        ({ __typeof__(strings) _s = strings; const char *__s = *_s; (void)__s; __mpw_free_strings( (char **)_s, __VA_ARGS__ ); })
 | 
			
		||||
bool __mpw_free_strings(
 | 
			
		||||
        char **strings, ...);
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
#undef mpw_realloc
 | 
			
		||||
#define mpw_realloc(buffer, bufferSize, deltaSize) \
 | 
			
		||||
        __mpw_realloc( (const void **)buffer, bufferSize, deltaSize )
 | 
			
		||||
#undef mpw_free
 | 
			
		||||
#define mpw_free(buffer, bufferSize) \
 | 
			
		||||
        __mpw_free( (void **)buffer, bufferSize )
 | 
			
		||||
#undef mpw_free_string
 | 
			
		||||
#define mpw_free_string(string) \
 | 
			
		||||
        __mpw_free_string( (char **)string )
 | 
			
		||||
#undef mpw_free_strings
 | 
			
		||||
#define mpw_free_strings(strings, ...) \
 | 
			
		||||
        __mpw_free_strings( (char **)strings, __VA_ARGS__ )
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//// Cryptographic functions.
 | 
			
		||||
 | 
			
		||||
@@ -207,5 +215,7 @@ const size_t mpw_utf8_strlen(const char *utf8String);
 | 
			
		||||
char *mpw_strdup(const char *src);
 | 
			
		||||
/** Drop-in for POSIX strndup(3). */
 | 
			
		||||
char *mpw_strndup(const char *src, size_t max);
 | 
			
		||||
/** Drop-in for POSIX strncasecmp(3). */
 | 
			
		||||
int *mpw_strncasecmp(const char *s1, const char *s2, size_t max);
 | 
			
		||||
 | 
			
		||||
#endif // _MPW_UTIL_H
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user