infparse.c 8.15 KB
Newer Older
1 2 3
/*
 * SetupX .inf file parsing functions
 *
4
 * Copyright 2000 Andreas Mohr for CodeWeavers
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library 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 library 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 library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
 *
20 21 22 23 24 25
 * FIXME:
 * - return values ???
 * - this should be reimplemented at some point to have its own
 *   file parsing instead of using profile functions,
 *   as some SETUPX exports probably demand that
 *   (IpSaveRestorePosition, IpFindNextMatchLine, ...).
26 27
 */

28
#include <stdarg.h>
29
#include <string.h>
30
#include <stdlib.h>
Steven Edwards's avatar
Steven Edwards committed
31

32 33
#include "windef.h"
#include "winbase.h"
34
#include "winreg.h"
35
#include "winternl.h"
36 37 38
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
39
#include "setupapi.h"
Steven Edwards's avatar
Steven Edwards committed
40
#include "setupx16.h"
41
#include "wine/debug.h"
42

43
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
44

45 46
#define MAX_HANDLES 16384
#define FIRST_HANDLE 32
47

48
static HINF handles[MAX_HANDLES];
49

Andreas Mohr's avatar
Andreas Mohr committed
50

51 52 53 54
static RETERR16 alloc_hinf16( HINF hinf, HINF16 *hinf16 )
{
    int i;
    for (i = 0; i < MAX_HANDLES; i++)
55
    {
56 57 58 59 60 61
        if (!handles[i])
        {
            handles[i] = hinf;
            *hinf16 = i + FIRST_HANDLE;
            return OK;
        }
62
    }
63
    return ERR_IP_OUT_OF_HANDLES;
64 65
}

66
static HINF get_hinf( HINF16 hinf16 )
Andreas Mohr's avatar
Andreas Mohr committed
67
{
68 69 70
    int idx = hinf16 - FIRST_HANDLE;
    if (idx < 0 || idx >= MAX_HANDLES) return 0;
    return handles[idx];
Andreas Mohr's avatar
Andreas Mohr committed
71 72
}

73 74

static HINF free_hinf16( HINF16 hinf16 )
75
{
76 77 78 79 80 81 82
    HINF ret;
    int idx = hinf16 - FIRST_HANDLE;

    if (idx < 0 || idx >= MAX_HANDLES) return 0;
    ret = handles[idx];
    handles[idx] = 0;
    return ret;
83 84
}

85 86
/* convert last error code to a RETERR16 value */
static RETERR16 get_last_error(void)
87
{
88
    switch(GetLastError())
89
    {
90 91 92 93 94 95
    case ERROR_EXPECTED_SECTION_NAME:
    case ERROR_BAD_SECTION_NAME_LINE:
    case ERROR_SECTION_NAME_TOO_LONG: return ERR_IP_INVALID_SECT_NAME;
    case ERROR_SECTION_NOT_FOUND: return ERR_IP_SECT_NOT_FOUND;
    case ERROR_LINE_NOT_FOUND: return ERR_IP_LINE_NOT_FOUND;
    default: return IP_ERROR;  /* FIXME */
96 97 98
    }
}

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
/* string substitution support, duplicated from setupapi/parser.c */

static const char *get_string_subst( HINF hinf, const char *str, unsigned int *len,
                                     char subst[MAX_INF_STRING_LENGTH], BOOL no_trailing_slash )
{
    int dirid;
    char *end;
    INFCONTEXT context;
    char buffer[MAX_INF_STRING_LENGTH];

    if (!*len)  /* empty string (%%) is replaced by single percent */
    {
        *len = 1;
        return "%";
    }
    memcpy( buffer, str, *len );
    buffer[*len] = 0;

    if (SetupFindFirstLineA( hinf, "Strings", buffer, &context ) &&
118
        SetupGetStringFieldA( &context, 1, subst, MAX_INF_STRING_LENGTH, NULL ))
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    {
        *len = strlen( subst );
        return subst;
    }

    /* check for integer id */
    dirid = strtoul( buffer, &end, 10 );
    if (!*end && !CtlGetLddPath16( dirid, subst ))
    {
        *len = strlen( subst );
        if (no_trailing_slash && *len && subst[*len - 1] == '\\') *len -= 1;
        return subst;
    }
    return NULL;
}

static unsigned int string_subst( HINF hinf, const char *text, char *buffer )
{
    const char *start, *subst, *p;
    unsigned int len, total = 0;
    int inside = 0;
    unsigned int size = MAX_INF_STRING_LENGTH;
    char tmp[MAX_INF_STRING_LENGTH];

    for (p = start = text; *p; p++)
    {
        if (*p != '%') continue;
        inside = !inside;
        if (inside)  /* start of a %xx% string */
        {
            len = p - start;
            if (len > size - 1) len = size - 1;
            if (buffer) memcpy( buffer + total, start, len );
            total += len;
            size -= len;
            start = p;
        }
        else /* end of the %xx% string, find substitution */
        {
            len = p - start - 1;
            subst = get_string_subst( hinf, start + 1, &len, tmp, p[1] == '\\' );
            if (!subst)
            {
                subst = start;
                len = p - start + 1;
            }
            if (len > size - 1) len = size - 1;
            if (buffer) memcpy( buffer + total, subst, len );
            total += len;
            size -= len;
            start = p + 1;
        }
    }

    if (start != p) /* unfinished string, copy it */
    {
        len = p - start;
        if (len > size - 1) len = size - 1;
        if (buffer) memcpy( buffer + total, start, len );
        total += len;
    }
    if (buffer && size) buffer[total] = 0;
    return total;
}

184

185
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
186
 *		IpOpen (SETUPX.2)
187 188
 *
 */
189
RETERR16 WINAPI IpOpen16( LPCSTR filename, HINF16 *hinf16 )
190
{
191
    HINF hinf = SetupOpenInfFileA( filename, NULL, INF_STYLE_WIN4, NULL );
192
    if (hinf == INVALID_HANDLE_VALUE) return get_last_error();
193
    return alloc_hinf16( hinf, hinf16 );
194 195
}

196

197
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
198
 *		IpClose (SETUPX.4)
199
 */
200
RETERR16 WINAPI IpClose16( HINF16 hinf16 )
201
{
202 203 204 205
    HINF hinf = free_hinf16( hinf16 );
    if (!hinf) return ERR_IP_INVALID_HINF;
    SetupCloseInfFile( hinf );
    return OK;
206 207
}

208

209
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
210
 *		IpGetProfileString (SETUPX.210)
211
 */
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
RETERR16 WINAPI IpGetProfileString16( HINF16 hinf16, LPCSTR section, LPCSTR entry,
                                      LPSTR buffer, WORD buflen )
{
    DWORD required_size;
    HINF hinf = get_hinf( hinf16 );

    if (!hinf) return ERR_IP_INVALID_HINF;
    if (!SetupGetLineTextA( NULL, hinf, section, entry, buffer, buflen, &required_size ))
        return get_last_error();
    TRACE("%p: section %s entry %s ret %s\n",
          hinf, debugstr_a(section), debugstr_a(entry), debugstr_a(buffer) );
    return OK;
}


/***********************************************************************
 *		GenFormStrWithoutPlaceHolders (SETUPX.103)
 *
 * ought to be pretty much implemented, I guess...
 */
void WINAPI GenFormStrWithoutPlaceHolders16( LPSTR dst, LPCSTR src, HINF16 hinf16 )
{
    HINF hinf = get_hinf( hinf16 );

    if (!hinf) return;

238
    string_subst( hinf, src, dst );
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
    TRACE( "%s -> %s\n", debugstr_a(src), debugstr_a(dst) );
}

/***********************************************************************
 *		GenInstall (SETUPX.101)
 *
 * generic installer function for .INF file sections
 *
 * This is not perfect - patch whenever you can !
 *
 * wFlags == GENINSTALL_DO_xxx
 * e.g. NetMeeting:
 * first call GENINSTALL_DO_REGSRCPATH | GENINSTALL_DO_FILES,
 * second call GENINSTALL_DO_LOGCONFIG | CFGAUTO | INI2REG | REG | INI
 */
RETERR16 WINAPI GenInstall16( HINF16 hinf16, LPCSTR section, WORD genflags )
255
{
256 257 258 259 260 261 262 263 264 265 266 267
    UINT flags = 0;
    HINF hinf = get_hinf( hinf16 );
    RETERR16 ret = OK;
    void *context;

    if (!hinf) return ERR_IP_INVALID_HINF;

    if (genflags & GENINSTALL_DO_FILES) flags |= SPINST_FILES;
    if (genflags & GENINSTALL_DO_INI) flags |= SPINST_INIFILES;
    if (genflags & GENINSTALL_DO_REG) flags |= SPINST_REGISTRY;
    if (genflags & GENINSTALL_DO_INI2REG) flags |= SPINST_INI2REG;
    if (genflags & GENINSTALL_DO_LOGCONFIG) flags |= SPINST_LOGCONFIG;
268 269 270
    if (genflags & GENINSTALL_DO_REGSRCPATH) FIXME( "unsupported flag: GENINSTALL_DO_REGSRCPATH\n" );
    if (genflags & GENINSTALL_DO_CFGAUTO) FIXME( "unsupported flag: GENINSTALL_DO_CFGAUTO\n" );
    if (genflags & GENINSTALL_DO_PERUSER) FIXME( "unsupported flag: GENINSTALL_DO_PERUSER\n" );
271 272

    context = SetupInitDefaultQueueCallback( 0 );
273 274 275
    if (!SetupInstallFromInfSectionA( 0, hinf, section, flags, 0, NULL,
                                      SP_COPY_NEWER_OR_SAME, SetupDefaultQueueCallbackA,
                                      context, 0, 0 ))
276 277 278 279
        ret = get_last_error();

    SetupTermDefaultQueueCallback( context );
    return ret;
280
}