Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenstreams.c
Go to the documentation of this file.
00001 /* 00002 * Implementation of the Microsoft Installer (msi.dll) 00003 * 00004 * Copyright 2007 James Hawkins 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include <stdarg.h> 00022 00023 #define COBJMACROS 00024 00025 #include "windef.h" 00026 #include "winbase.h" 00027 #include "winerror.h" 00028 #include "msi.h" 00029 #include "msiquery.h" 00030 #include "objbase.h" 00031 #include "msipriv.h" 00032 #include "query.h" 00033 00034 #include "wine/debug.h" 00035 #include "wine/unicode.h" 00036 00037 WINE_DEFAULT_DEBUG_CHANNEL(msidb); 00038 00039 #define NUM_STREAMS_COLS 2 00040 00041 typedef struct tabSTREAM 00042 { 00043 UINT str_index; 00044 IStream *stream; 00045 } STREAM; 00046 00047 typedef struct tagMSISTREAMSVIEW 00048 { 00049 MSIVIEW view; 00050 MSIDATABASE *db; 00051 STREAM **streams; 00052 UINT max_streams; 00053 UINT num_rows; 00054 UINT row_size; 00055 } MSISTREAMSVIEW; 00056 00057 static BOOL streams_set_table_size(MSISTREAMSVIEW *sv, UINT size) 00058 { 00059 if (size >= sv->max_streams) 00060 { 00061 sv->max_streams *= 2; 00062 sv->streams = msi_realloc_zero(sv->streams, sv->max_streams * sizeof(STREAM *)); 00063 if (!sv->streams) 00064 return FALSE; 00065 } 00066 00067 return TRUE; 00068 } 00069 00070 static STREAM *create_stream(MSISTREAMSVIEW *sv, LPCWSTR name, BOOL encoded, IStream *stm) 00071 { 00072 STREAM *stream; 00073 WCHAR decoded[MAX_STREAM_NAME_LEN]; 00074 00075 stream = msi_alloc(sizeof(STREAM)); 00076 if (!stream) 00077 return NULL; 00078 00079 if (encoded) 00080 { 00081 decode_streamname(name, decoded); 00082 TRACE("stream -> %s %s\n", debugstr_w(name), debugstr_w(decoded)); 00083 name = decoded; 00084 } 00085 00086 stream->str_index = msi_addstringW(sv->db->strings, name, -1, 1, StringNonPersistent); 00087 stream->stream = stm; 00088 return stream; 00089 } 00090 00091 static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT *val) 00092 { 00093 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00094 00095 TRACE("(%p, %d, %d, %p)\n", view, row, col, val); 00096 00097 if (col != 1) 00098 return ERROR_INVALID_PARAMETER; 00099 00100 if (row >= sv->num_rows) 00101 return ERROR_NO_MORE_ITEMS; 00102 00103 *val = sv->streams[row]->str_index; 00104 00105 return ERROR_SUCCESS; 00106 } 00107 00108 static UINT STREAMS_fetch_stream(struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm) 00109 { 00110 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00111 00112 TRACE("(%p, %d, %d, %p)\n", view, row, col, stm); 00113 00114 if (row >= sv->num_rows) 00115 return ERROR_FUNCTION_FAILED; 00116 00117 IStream_AddRef(sv->streams[row]->stream); 00118 *stm = sv->streams[row]->stream; 00119 00120 return ERROR_SUCCESS; 00121 } 00122 00123 static UINT STREAMS_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec ) 00124 { 00125 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00126 00127 TRACE("%p %d %p\n", sv, row, rec); 00128 00129 return msi_view_get_row( sv->db, view, row, rec ); 00130 } 00131 00132 static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask) 00133 { 00134 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00135 STREAM *stream; 00136 IStream *stm; 00137 STATSTG stat; 00138 LPWSTR encname = NULL, name = NULL; 00139 USHORT *data = NULL; 00140 HRESULT hr; 00141 ULONG count; 00142 UINT r = ERROR_FUNCTION_FAILED; 00143 00144 TRACE("(%p, %d, %p, %08x)\n", view, row, rec, mask); 00145 00146 if (row > sv->num_rows) 00147 return ERROR_FUNCTION_FAILED; 00148 00149 r = MSI_RecordGetIStream(rec, 2, &stm); 00150 if (r != ERROR_SUCCESS) 00151 return r; 00152 00153 hr = IStream_Stat(stm, &stat, STATFLAG_NONAME); 00154 if (FAILED(hr)) 00155 { 00156 WARN("failed to stat stream: %08x\n", hr); 00157 goto done; 00158 } 00159 00160 if (stat.cbSize.QuadPart >> 32) 00161 { 00162 WARN("stream too large\n"); 00163 goto done; 00164 } 00165 00166 data = msi_alloc(stat.cbSize.QuadPart); 00167 if (!data) 00168 goto done; 00169 00170 hr = IStream_Read(stm, data, stat.cbSize.QuadPart, &count); 00171 if (FAILED(hr) || count != stat.cbSize.QuadPart) 00172 { 00173 WARN("failed to read stream: %08x\n", hr); 00174 goto done; 00175 } 00176 00177 name = strdupW(MSI_RecordGetString(rec, 1)); 00178 if (!name) 00179 { 00180 WARN("failed to retrieve stream name\n"); 00181 goto done; 00182 } 00183 00184 encname = encode_streamname(FALSE, name); 00185 msi_destroy_stream(sv->db, encname); 00186 00187 r = write_stream_data(sv->db->storage, name, data, count, FALSE); 00188 if (r != ERROR_SUCCESS) 00189 { 00190 WARN("failed to write stream data: %d\n", r); 00191 goto done; 00192 } 00193 00194 stream = create_stream(sv, name, FALSE, NULL); 00195 if (!stream) 00196 goto done; 00197 00198 hr = IStorage_OpenStream(sv->db->storage, encname, 0, 00199 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream); 00200 if (FAILED(hr)) 00201 { 00202 WARN("failed to open stream: %08x\n", hr); 00203 goto done; 00204 } 00205 00206 sv->streams[row] = stream; 00207 00208 done: 00209 msi_free(name); 00210 msi_free(data); 00211 msi_free(encname); 00212 00213 IStream_Release(stm); 00214 00215 return r; 00216 } 00217 00218 static UINT STREAMS_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary) 00219 { 00220 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00221 UINT i; 00222 00223 TRACE("(%p, %p, %d, %d)\n", view, rec, row, temporary); 00224 00225 if (!streams_set_table_size(sv, ++sv->num_rows)) 00226 return ERROR_FUNCTION_FAILED; 00227 00228 if (row == -1) 00229 row = sv->num_rows - 1; 00230 00231 /* shift the rows to make room for the new row */ 00232 for (i = sv->num_rows - 1; i > row; i--) 00233 { 00234 sv->streams[i] = sv->streams[i - 1]; 00235 } 00236 00237 return STREAMS_set_row(view, row, rec, 0); 00238 } 00239 00240 static UINT STREAMS_delete_row(struct tagMSIVIEW *view, UINT row) 00241 { 00242 FIXME("(%p %d): stub!\n", view, row); 00243 return ERROR_SUCCESS; 00244 } 00245 00246 static UINT STREAMS_execute(struct tagMSIVIEW *view, MSIRECORD *record) 00247 { 00248 TRACE("(%p, %p)\n", view, record); 00249 return ERROR_SUCCESS; 00250 } 00251 00252 static UINT STREAMS_close(struct tagMSIVIEW *view) 00253 { 00254 TRACE("(%p)\n", view); 00255 return ERROR_SUCCESS; 00256 } 00257 00258 static UINT STREAMS_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *cols) 00259 { 00260 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00261 00262 TRACE("(%p, %p, %p)\n", view, rows, cols); 00263 00264 if (cols) *cols = NUM_STREAMS_COLS; 00265 if (rows) *rows = sv->num_rows; 00266 00267 return ERROR_SUCCESS; 00268 } 00269 00270 static UINT STREAMS_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name, 00271 UINT *type, BOOL *temporary, LPCWSTR *table_name ) 00272 { 00273 TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary, 00274 table_name); 00275 00276 if (n == 0 || n > NUM_STREAMS_COLS) 00277 return ERROR_INVALID_PARAMETER; 00278 00279 switch (n) 00280 { 00281 case 1: 00282 if (name) *name = szName; 00283 if (type) *type = MSITYPE_STRING | MSITYPE_VALID | MAX_STREAM_NAME_LEN; 00284 break; 00285 00286 case 2: 00287 if (name) *name = szData; 00288 if (type) *type = MSITYPE_STRING | MSITYPE_VALID | MSITYPE_NULLABLE; 00289 break; 00290 } 00291 if (table_name) *table_name = szStreams; 00292 if (temporary) *temporary = FALSE; 00293 return ERROR_SUCCESS; 00294 } 00295 00296 static UINT streams_find_row(MSISTREAMSVIEW *sv, MSIRECORD *rec, UINT *row) 00297 { 00298 LPCWSTR str; 00299 UINT r, i, id, data; 00300 00301 str = MSI_RecordGetString(rec, 1); 00302 r = msi_string2idW(sv->db->strings, str, &id); 00303 if (r != ERROR_SUCCESS) 00304 return r; 00305 00306 for (i = 0; i < sv->num_rows; i++) 00307 { 00308 STREAMS_fetch_int(&sv->view, i, 1, &data); 00309 00310 if (data == id) 00311 { 00312 *row = i; 00313 return ERROR_SUCCESS; 00314 } 00315 } 00316 00317 return ERROR_FUNCTION_FAILED; 00318 } 00319 00320 static UINT streams_modify_update(struct tagMSIVIEW *view, MSIRECORD *rec) 00321 { 00322 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00323 UINT r, row; 00324 00325 r = streams_find_row(sv, rec, &row); 00326 if (r != ERROR_SUCCESS) 00327 return ERROR_FUNCTION_FAILED; 00328 00329 return STREAMS_set_row(view, row, rec, 0); 00330 } 00331 00332 static UINT streams_modify_assign(struct tagMSIVIEW *view, MSIRECORD *rec) 00333 { 00334 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00335 UINT r, row; 00336 00337 r = streams_find_row(sv, rec, &row); 00338 if (r == ERROR_SUCCESS) 00339 return streams_modify_update(view, rec); 00340 00341 return STREAMS_insert_row(view, rec, -1, FALSE); 00342 } 00343 00344 static UINT STREAMS_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec, UINT row) 00345 { 00346 UINT r; 00347 00348 TRACE("%p %d %p\n", view, eModifyMode, rec); 00349 00350 switch (eModifyMode) 00351 { 00352 case MSIMODIFY_ASSIGN: 00353 r = streams_modify_assign(view, rec); 00354 break; 00355 00356 case MSIMODIFY_INSERT: 00357 r = STREAMS_insert_row(view, rec, -1, FALSE); 00358 break; 00359 00360 case MSIMODIFY_UPDATE: 00361 r = streams_modify_update(view, rec); 00362 break; 00363 00364 case MSIMODIFY_VALIDATE_NEW: 00365 case MSIMODIFY_INSERT_TEMPORARY: 00366 case MSIMODIFY_REFRESH: 00367 case MSIMODIFY_REPLACE: 00368 case MSIMODIFY_MERGE: 00369 case MSIMODIFY_DELETE: 00370 case MSIMODIFY_VALIDATE: 00371 case MSIMODIFY_VALIDATE_FIELD: 00372 case MSIMODIFY_VALIDATE_DELETE: 00373 FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec ); 00374 r = ERROR_CALL_NOT_IMPLEMENTED; 00375 break; 00376 00377 default: 00378 r = ERROR_INVALID_DATA; 00379 } 00380 00381 return r; 00382 } 00383 00384 static UINT STREAMS_delete(struct tagMSIVIEW *view) 00385 { 00386 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00387 UINT i; 00388 00389 TRACE("(%p)\n", view); 00390 00391 for (i = 0; i < sv->num_rows; i++) 00392 { 00393 if (sv->streams[i]) 00394 { 00395 if (sv->streams[i]->stream) 00396 IStream_Release(sv->streams[i]->stream); 00397 msi_free(sv->streams[i]); 00398 } 00399 } 00400 00401 msi_free(sv->streams); 00402 msi_free(sv); 00403 00404 return ERROR_SUCCESS; 00405 } 00406 00407 static UINT STREAMS_find_matching_rows(struct tagMSIVIEW *view, UINT col, 00408 UINT val, UINT *row, MSIITERHANDLE *handle) 00409 { 00410 MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; 00411 UINT index = PtrToUlong(*handle); 00412 00413 TRACE("(%p, %d, %d, %p, %p)\n", view, col, val, row, handle); 00414 00415 if (col == 0 || col > NUM_STREAMS_COLS) 00416 return ERROR_INVALID_PARAMETER; 00417 00418 while (index < sv->num_rows) 00419 { 00420 if (sv->streams[index]->str_index == val) 00421 { 00422 *row = index; 00423 break; 00424 } 00425 00426 index++; 00427 } 00428 00429 *handle = UlongToPtr(++index); 00430 00431 if (index > sv->num_rows) 00432 return ERROR_NO_MORE_ITEMS; 00433 00434 return ERROR_SUCCESS; 00435 } 00436 00437 static const MSIVIEWOPS streams_ops = 00438 { 00439 STREAMS_fetch_int, 00440 STREAMS_fetch_stream, 00441 STREAMS_get_row, 00442 STREAMS_set_row, 00443 STREAMS_insert_row, 00444 STREAMS_delete_row, 00445 STREAMS_execute, 00446 STREAMS_close, 00447 STREAMS_get_dimensions, 00448 STREAMS_get_column_info, 00449 STREAMS_modify, 00450 STREAMS_delete, 00451 STREAMS_find_matching_rows, 00452 NULL, 00453 NULL, 00454 NULL, 00455 NULL, 00456 NULL, 00457 NULL, 00458 }; 00459 00460 static INT add_streams_to_table(MSISTREAMSVIEW *sv) 00461 { 00462 IEnumSTATSTG *stgenum = NULL; 00463 STATSTG stat; 00464 STREAM *stream = NULL; 00465 HRESULT hr; 00466 UINT r, count = 0, size; 00467 LPWSTR encname; 00468 00469 hr = IStorage_EnumElements(sv->db->storage, 0, NULL, 0, &stgenum); 00470 if (FAILED(hr)) 00471 return -1; 00472 00473 sv->max_streams = 1; 00474 sv->streams = msi_alloc_zero(sizeof(STREAM *)); 00475 if (!sv->streams) 00476 return -1; 00477 00478 while (TRUE) 00479 { 00480 size = 0; 00481 hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &size); 00482 if (FAILED(hr) || !size) 00483 break; 00484 00485 if (stat.type != STGTY_STREAM) 00486 { 00487 CoTaskMemFree(stat.pwcsName); 00488 continue; 00489 } 00490 00491 /* table streams are not in the _Streams table */ 00492 if (*stat.pwcsName == 0x4840) 00493 { 00494 CoTaskMemFree(stat.pwcsName); 00495 continue; 00496 } 00497 00498 stream = create_stream(sv, stat.pwcsName, TRUE, NULL); 00499 if (!stream) 00500 { 00501 count = -1; 00502 CoTaskMemFree(stat.pwcsName); 00503 break; 00504 } 00505 00506 /* these streams appear to be unencoded */ 00507 if (*stat.pwcsName == 0x0005) 00508 { 00509 r = msi_get_raw_stream(sv->db, stat.pwcsName, &stream->stream); 00510 } 00511 else 00512 { 00513 encname = encode_streamname(FALSE, stat.pwcsName); 00514 r = msi_get_raw_stream(sv->db, encname, &stream->stream); 00515 msi_free(encname); 00516 } 00517 CoTaskMemFree(stat.pwcsName); 00518 00519 if (r != ERROR_SUCCESS) 00520 { 00521 WARN("unable to get stream %u\n", r); 00522 count = -1; 00523 break; 00524 } 00525 00526 if (!streams_set_table_size(sv, ++count)) 00527 { 00528 count = -1; 00529 break; 00530 } 00531 00532 sv->streams[count - 1] = stream; 00533 } 00534 00535 IEnumSTATSTG_Release(stgenum); 00536 return count; 00537 } 00538 00539 UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view) 00540 { 00541 MSISTREAMSVIEW *sv; 00542 INT rows; 00543 00544 TRACE("(%p, %p)\n", db, view); 00545 00546 sv = msi_alloc_zero( sizeof(MSISTREAMSVIEW) ); 00547 if (!sv) 00548 return ERROR_FUNCTION_FAILED; 00549 00550 sv->view.ops = &streams_ops; 00551 sv->db = db; 00552 rows = add_streams_to_table(sv); 00553 if (rows < 0) 00554 { 00555 msi_free( sv ); 00556 return ERROR_FUNCTION_FAILED; 00557 } 00558 sv->num_rows = rows; 00559 00560 *view = (MSIVIEW *)sv; 00561 00562 return ERROR_SUCCESS; 00563 } Generated on Fri May 25 2012 04:23:22 for ReactOS by
1.7.6.1
|