/*********************************************************************** * msidbExportStream * * Exports a stream to a file with an .idb extension. * * Examples (note wildcard escape for *nix/bash): * msidb -d <pathtomsi>.msi -f <workdir> -x <streamname> * msidb -d <pathtomsi>.msi -f <workdir> -x data.cab **********************************************************************/ static BOOL msidbExportStream(LPCWSTR dbfile, LPCWSTR wdir, LPCWSTR streamName) { static const char ext[] = {'.', 'i', 'd', 'b', 0}; UINT r, len; MSIHANDLE dbhandle, streamListView, rec; char queryBuffer[100]; FILE *fp = 0; char *streamNameA = strdupWtoA(CP_ACP, streamName); char *wdirA = strdupWtoA(CP_ACP, wdir); char *streamFileA = 0; char streamPath[MAX_PATH]; char *dataBuffer; DWORD dataLen = 0; r = MsiOpenDatabaseW(dbfile, (LPCWSTR) MSIDBOPEN_READONLY, &dbhandle); if (r != ERROR_SUCCESS) return FALSE; sprintf(queryBuffer, "SELECT * FROM _Streams WHERE Name = '%s'", streamNameA); MsiDatabaseOpenView(dbhandle, queryBuffer, &streamListView); MsiViewExecute(streamListView, 0); r = MsiViewFetch(streamListView, &rec); if (r != ERROR_SUCCESS) return FALSE; if (MsiRecordReadStream(rec, 2, 0, &dataLen) != ERROR_SUCCESS) return FALSE; dataBuffer = malloc(dataLen); if (!dataBuffer) return FALSE; if (MsiRecordReadStream(rec, 2, dataBuffer, &dataLen) != ERROR_SUCCESS) return FALSE; len = strlen(streamNameA) + 5; streamFileA = malloc(len); if (streamFileA == NULL) return FALSE; strcpy(streamFileA, streamNameA); strcat(streamFileA, ext); strcpy(streamPath, wdirA); strcat(streamPath, PATH_DELIMITER); strcat(streamPath, streamFileA); fp = fopen(streamPath , "wb"); if (fp != NULL) { fwrite(dataBuffer, 1, dataLen, fp); fclose(fp); } free(streamFileA); MsiCloseHandle(rec); MsiViewClose(streamListView); MsiCloseHandle(streamListView); MsiCloseHandle(dbhandle); free(wdirA); free(streamNameA); return TRUE; }
static BOOL msidbExportStorage(LPCWSTR dbfile, LPCWSTR wdir, LPWSTR storageName) { UINT r, len; MSIHANDLE dbhandle, view, rec; char queryBuffer[100]; char *storageNameA = strdupWtoA(CP_ACP, storageName); char *wdirA = strdupWtoA(CP_ACP, wdir); char *storagePath = NULL; char *dataBuffer; DWORD dataLen = 0; FILE *fp = NULL; sprintf(queryBuffer, "SELECT * FROM _Storages WHERE Name = '%s'", storageNameA); r = MsiOpenDatabaseW(dbfile, (LPWSTR) MSIDBOPEN_READONLY, &dbhandle); if (r != ERROR_SUCCESS) return FALSE; MsiDatabaseOpenView(dbhandle, queryBuffer, &view); MsiViewExecute(view, 0); r = MsiViewFetch(view, &rec); if (r != ERROR_SUCCESS) return FALSE; if ((r = MsiRecordReadStream(rec, 2, 0, &dataLen)) != ERROR_SUCCESS) { return FALSE; } if ((dataBuffer = malloc(dataLen)) == NULL) return FALSE; if (MsiRecordReadStream(rec, 2, dataBuffer, &dataLen) != ERROR_SUCCESS) return FALSE; len = strlen(wdirA) + strlen(storageNameA) + 2; storagePath = malloc(len * sizeof(WCHAR)); if (storagePath == NULL) return FALSE; strcpy(storagePath, wdirA); strcat(storagePath, "/"); strcat(storagePath, storageNameA); fp = fopen(storagePath , "wb"); if (fp != NULL) { fwrite(dataBuffer, 1, dataLen, fp); fclose(fp); } free(storagePath); MsiCloseHandle(rec); MsiViewClose(view); MsiCloseHandle(view); MsiCloseHandle(dbhandle); free(storageNameA); free(wdirA); return TRUE; }
/** * Extracts the jar file from the MSI database binary field * * @param hModule Specify the handle for the MSI database */ void ExtractBinaryFile (MSIHANDLE hModule, const char* pFieldName, const char* pDstFileName) { char cSelectSql[MAX_PATH_SIZE] = {0}; MSIHANDLE hRecord, hView, hDatabase; // get hView & hDatabase hDatabase = MsiGetActiveDatabase(hModule); sprintf(cSelectSql, "select * from Binary where `Name`='%s'", pFieldName); MsiDatabaseOpenView(hDatabase, cSelectSql, &hView); MsiViewExecute(hView, NULL); char szTemp[256] = {0}; DWORD dwLength = 256; if (MsiViewFetch(hView, &hRecord) != ERROR_SUCCESS) { return; } MsiRecordGetString(hRecord, 1, szTemp, &dwLength); if (strncmp(szTemp, pFieldName, strlen(pFieldName))) { return; } // write into installer.jar #define BUFFERSIZE 1024 char szBuffer[BUFFERSIZE] = {0}; DWORD cbBuf = BUFFERSIZE; DWORD countWrite = 0; FILE* fp = NULL; fp = fopen(pDstFileName, "wb+"); if (NULL == fp) { return; } do { if (MsiRecordReadStream(hRecord, 2, szBuffer, &cbBuf) !=ERROR_SUCCESS) break; // error countWrite = fwrite(szBuffer, 1, cbBuf, fp); } while (countWrite == BUFFERSIZE); fclose(fp); // close all handles MsiCloseHandle(hRecord); MsiViewClose(hView); MsiCloseHandle(hView); MsiCloseHandle(hDatabase); }
static void test_msirecord(void) { DWORD r, sz; INT i; MSIHANDLE h; char buf[10]; WCHAR bufW[10]; const char str[] = "hello"; const WCHAR strW[] = { 'h','e','l','l','o',0}; char filename[MAX_PATH]; /* check behaviour with an invalid record */ r = MsiRecordGetFieldCount(0); ok(r==-1, "field count for invalid record not -1\n"); SetLastError(0); r = MsiRecordIsNull(0, 0); ok(r==0, "invalid handle not considered to be non-null...\n"); ok(GetLastError()==0, "MsiRecordIsNull set LastError\n"); r = MsiRecordGetInteger(0,0); ok(r == MSI_NULL_INTEGER, "got integer from invalid record\n"); r = MsiRecordSetInteger(0,0,0); ok(r == ERROR_INVALID_HANDLE, "MsiRecordSetInteger returned wrong error\n"); r = MsiRecordSetInteger(0,-1,0); ok(r == ERROR_INVALID_HANDLE, "MsiRecordSetInteger returned wrong error\n"); SetLastError(0); h = MsiCreateRecord(-1); ok(h==0, "created record with -1 elements\n"); h = MsiCreateRecord(0x10000); ok(h==0, "created record with 0x10000 elements\n"); /* doesn't set LastError */ ok(GetLastError()==0, "MsiCreateRecord set last error\n"); r = MsiRecordClearData(0); ok(r == ERROR_INVALID_HANDLE, "MsiRecordClearData returned wrong error\n"); r = MsiRecordDataSize(0,0); ok(r == 0, "MsiRecordDataSize returned wrong error\n"); /* check behaviour of a record with 0 elements */ h = MsiCreateRecord(0); ok(h!=0, "couldn't create record with zero elements\n"); r = MsiRecordGetFieldCount(h); ok(r==0, "field count should be zero\n"); r = MsiRecordIsNull(h,0); ok(r, "new record wasn't null\n"); r = MsiRecordIsNull(h,1); ok(r, "out of range record wasn't null\n"); r = MsiRecordIsNull(h,-1); ok(r, "out of range record wasn't null\n"); r = MsiRecordDataSize(h,0); ok(r==0, "size of null record is 0\n"); sz = sizeof buf; strcpy(buf,"x"); r = MsiRecordGetString(h, 0, buf, &sz); ok(r==ERROR_SUCCESS, "failed to get null string\n"); ok(sz==0, "null string too long\n"); ok(buf[0]==0, "null string not set\n"); /* same record, but add an integer to it */ r = MsiRecordSetInteger(h, 0, 0); ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 0\n"); r = MsiRecordIsNull(h,0); ok(r==0, "new record is null after setting an integer\n"); r = MsiRecordDataSize(h,0); ok(r==sizeof(DWORD), "size of integer record is 4\n"); r = MsiRecordSetInteger(h, 0, 1); ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 1\n"); r = MsiRecordSetInteger(h, 1, 1); ok(r == ERROR_INVALID_PARAMETER, "set integer at 1\n"); r = MsiRecordSetInteger(h, -1, 0); ok(r == ERROR_INVALID_PARAMETER, "set integer at -1\n"); r = MsiRecordIsNull(h,0); ok(r==0, "new record is null after setting an integer\n"); r = MsiRecordGetInteger(h, 0); ok(r == 1, "failed to get integer\n"); /* same record, but add a string to it */ r = MsiRecordSetString(h, 0, NULL); ok(r == ERROR_SUCCESS, "Failed to set null string at 0\n"); r = MsiRecordIsNull(h, 0); ok(r == TRUE, "null string not null field\n"); r = MsiRecordSetString(h, 0, ""); ok(r == ERROR_SUCCESS, "Failed to set empty string at 0\n"); r = MsiRecordIsNull(h, 0); ok(r == TRUE, "null string not null field\n"); r = MsiRecordSetString(h,0,str); ok(r == ERROR_SUCCESS, "Failed to set string at 0\n"); r = MsiRecordGetInteger(h, 0); ok(r == MSI_NULL_INTEGER, "should get invalid integer\n"); r = MsiRecordDataSize(h,0); ok(r==sizeof str-1, "size of string record is strlen\n"); buf[0]=0; sz = sizeof buf; r = MsiRecordGetString(h,0,buf,&sz); ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); ok(0==strcmp(buf,str), "MsiRecordGetString returned the wrong string\n"); ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n"); buf[0]=0; sz = sizeof str - 2; r = MsiRecordGetString(h,0,buf,&sz); ok(r == ERROR_MORE_DATA, "small buffer should yield ERROR_MORE_DATA\n"); ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n"); ok(0==strncmp(buf,str,sizeof str-3), "MsiRecordGetString returned the wrong string\n"); ok(buf[sizeof str - 3]==0, "string wasn't nul terminated\n"); buf[0]=0; sz = sizeof str; r = MsiRecordGetString(h,0,buf,&sz); ok(r == ERROR_SUCCESS, "wrong error\n"); ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n"); ok(0==strcmp(buf,str), "MsiRecordGetString returned the wrong string\n"); memset(bufW, 0, sizeof bufW); sz = 5; r = MsiRecordGetStringW(h,0,bufW,&sz); ok(r == ERROR_MORE_DATA, "wrong error\n"); ok(sz == 5, "MsiRecordGetString returned the wrong length\n"); ok(0==memcmp(bufW,strW,8), "MsiRecordGetString returned the wrong string\n"); sz = 0; bufW[0] = 'x'; r = MsiRecordGetStringW(h,0,bufW,&sz); ok(r == ERROR_MORE_DATA, "wrong error\n"); ok(sz == 5, "MsiRecordGetString returned the wrong length\n"); ok('x'==bufW[0], "MsiRecordGetString returned the wrong string\n"); memset(buf, 0, sizeof buf); sz = 5; r = MsiRecordGetStringA(h,0,buf,&sz); ok(r == ERROR_MORE_DATA, "wrong error\n"); ok(sz == 5, "MsiRecordGetString returned the wrong length\n"); ok(0==memcmp(buf,str,4), "MsiRecordGetString returned the wrong string\n"); sz = 0; buf[0] = 'x'; r = MsiRecordGetStringA(h,0,buf,&sz); ok(r == ERROR_MORE_DATA, "wrong error\n"); ok(sz == 5, "MsiRecordGetString returned the wrong length\n"); ok('x'==buf[0], "MsiRecordGetString returned the wrong string\n"); /* same record, check we can wipe all the data */ r = MsiRecordClearData(h); ok(r == ERROR_SUCCESS, "Failed to clear record\n"); r = MsiRecordClearData(h); ok(r == ERROR_SUCCESS, "Failed to clear record again\n"); r = MsiRecordIsNull(h,0); ok(r, "cleared record wasn't null\n"); /* same record, try converting strings to integers */ i = MsiRecordSetString(h,0,"42"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == 42, "should get invalid integer\n"); i = MsiRecordSetString(h,0,"-42"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == -42, "should get invalid integer\n"); i = MsiRecordSetString(h,0," 42"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == MSI_NULL_INTEGER, "should get invalid integer\n"); i = MsiRecordSetString(h,0,"42 "); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == MSI_NULL_INTEGER, "should get invalid integer\n"); i = MsiRecordSetString(h,0,"42.0"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == MSI_NULL_INTEGER, "should get invalid integer\n"); i = MsiRecordSetString(h,0,"0x42"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == MSI_NULL_INTEGER, "should get invalid integer\n"); i = MsiRecordSetString(h,0,"1000000000000000"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == -1530494976, "should get truncated integer\n"); i = MsiRecordSetString(h,0,"2147483647"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == 2147483647, "should get maxint\n"); i = MsiRecordSetString(h,0,"-2147483647"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == -2147483647, "should get -maxint-1\n"); i = MsiRecordSetString(h,0,"4294967297"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == 1, "should get one\n"); i = MsiRecordSetString(h,0,"foo"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == MSI_NULL_INTEGER, "should get zero\n"); i = MsiRecordSetString(h,0,""); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == MSI_NULL_INTEGER, "should get zero\n"); i = MsiRecordSetString(h,0,"+1"); ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); i = MsiRecordGetInteger(h, 0); ok(i == MSI_NULL_INTEGER, "should get zero\n"); /* same record, try converting integers to strings */ r = MsiRecordSetInteger(h, 0, 32); ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 32\n"); sz = 1; r = MsiRecordGetString(h, 0, NULL, &sz); ok(r == ERROR_SUCCESS, "failed to get string from integer\n"); ok(sz == 2, "length wrong\n"); buf[0]=0; sz = sizeof buf; r = MsiRecordGetString(h, 0, buf, &sz); ok(r == ERROR_SUCCESS, "failed to get string from integer\n"); ok(0==strcmp(buf,"32"), "failed to get string from integer\n"); r = MsiRecordSetInteger(h, 0, -32); ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 32\n"); buf[0]=0; sz = 1; r = MsiRecordGetString(h, 0, NULL, &sz); ok(r == ERROR_SUCCESS, "failed to get string from integer\n"); ok(sz == 3, "length wrong\n"); sz = sizeof buf; r = MsiRecordGetString(h, 0, buf, &sz); ok(r == ERROR_SUCCESS, "failed to get string from integer\n"); ok(0==strcmp(buf,"-32"), "failed to get string from integer\n"); buf[0]=0; /* same record, now try streams */ r = MsiRecordSetStream(h, 0, NULL); ok(r == ERROR_INVALID_PARAMETER, "set NULL stream\n"); sz = sizeof buf; r = MsiRecordReadStream(h, 0, buf, &sz); ok(r == ERROR_INVALID_DATATYPE, "read non-stream type\n"); ok(sz == sizeof buf, "set sz\n"); r = MsiRecordDataSize( h, -1); ok(r == 0,"MsiRecordDataSize returned wrong size\n"); r = MsiRecordDataSize( h, 0); ok(r == 4,"MsiRecordDataSize returned wrong size\n"); /* same record, now close it */ r = MsiCloseHandle(h); ok(r == ERROR_SUCCESS, "Failed to close handle\n"); /* now try streams in a new record - need to create a file to play with */ r = create_temp_file(filename); if(!r) return; /* streams can't be inserted in field 0 for some reason */ h = MsiCreateRecord(2); ok(h, "couldn't create a two field record\n"); r = MsiRecordSetStream(h, 0, filename); ok(r == ERROR_INVALID_PARAMETER, "added stream to field 0\n"); r = MsiRecordSetStream(h, 1, filename); ok(r == ERROR_SUCCESS, "failed to add stream to record\n"); r = MsiRecordReadStream(h, 1, buf, NULL); ok(r == ERROR_INVALID_PARAMETER, "should return error\n"); /* http://test.winehq.org/data/200503181000/98_jmelgarejo98casa/msi:record.txt */ DeleteFile(filename); /* Windows 98 doesn't like this at all, so don't check return. */ r = MsiRecordReadStream(h, 1, NULL, NULL); ok(r == ERROR_INVALID_PARAMETER, "should return error\n"); sz = sizeof buf; r = MsiRecordReadStream(h, 1, NULL, &sz); ok(r == ERROR_SUCCESS, "failed to read stream\n"); ok(sz==26,"couldn't get size of stream\n"); sz = 0; r = MsiRecordReadStream(h, 1, buf, &sz); ok(r == ERROR_SUCCESS, "failed to read stream\n"); ok(sz==0,"short read\n"); sz = sizeof buf; r = MsiRecordReadStream(h, 1, buf, &sz); ok(r == ERROR_SUCCESS, "failed to read stream\n"); ok(sz==sizeof buf,"short read\n"); ok(!strncmp(buf,"abcdefghij",10), "read the wrong thing\n"); sz = sizeof buf; r = MsiRecordReadStream(h, 1, buf, &sz); ok(r == ERROR_SUCCESS, "failed to read stream\n"); ok(sz==sizeof buf,"short read\n"); ok(!strncmp(buf,"klmnopqrst",10), "read the wrong thing\n"); memset(buf,0,sizeof buf); sz = sizeof buf; r = MsiRecordReadStream(h, 1, buf, &sz); ok(r == ERROR_SUCCESS, "failed to read stream\n"); ok(sz==6,"short read\n"); ok(!strcmp(buf,"uvwxyz"), "read the wrong thing\n"); memset(buf,0,sizeof buf); sz = sizeof buf; r = MsiRecordReadStream(h, 1, buf, &sz); ok(r == ERROR_SUCCESS, "failed to read stream\n"); ok(sz==0,"size non-zero at end of stream\n"); ok(buf[0]==0, "read something at end of the stream\n"); r = MsiRecordSetStream(h, 1, NULL); ok(r == ERROR_SUCCESS, "failed to reset stream\n"); sz = 0; r = MsiRecordReadStream(h, 1, NULL, &sz); ok(r == ERROR_SUCCESS, "bytes left wrong after reset\n"); ok(sz==26,"couldn't get size of stream\n"); r = MsiRecordDataSize(h,1); ok(r == 26,"MsiRecordDataSize returned wrong size\n"); /* now close the stream record */ r = MsiCloseHandle(h); ok(r == ERROR_SUCCESS, "Failed to close handle\n"); DeleteFile(filename); /* Delete it for sure, when everything else is closed. */ }