ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

streams.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.