00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <QFile>
00010 #include <QDomDocument>
00011 #include <QTextStream>
00012 #include <QTextCodec>
00013 #include <QStringList>
00014 #include <stdlib.h>
00015
00016 #define WIX_ATTR_ID "Id"
00017 #define WIX_ATTR_DIRACTION "uninstall"
00018 #define WIX_ATTR_REGACTION "createAndRemoveOnUninstall"
00019 #define WIX_ATTR_VALUE "Value"
00020 #define WIX_ATTR_KEY "KeyPath"
00021 #define WIX_ATTR_GUID "Guid"
00022 #define WIX_ATTR_NAME "Name"
00023 #define WIX_ATTR_REG_TYPE "Type"
00024 #define WIX_ATTR_REG_NAME "Name"
00025 #define WIX_ATTR_REG_ROOT "Root"
00026 #define WIX_ATTR_REG_KEYPATH "Key"
00027 #define WIX_ATTR_REG_ACTION "Action"
00028 #define WIX_REG_KEY_TYPE "integer"
00029 #define WIX_TAG_FILE "File"
00030 #define WIX_TAG_DIR "Directory"
00031 #define WIX_TAG_FEATURE "Feature"
00032 #define WIX_TAG_COMPONENT "Component"
00033 #define WIX_TAG_COMPONENT_REF "ComponentRef"
00034 #define WIX_TAG_CREATEDIR "CreateFolder"
00035 #define WIX_TAG_REMOVEDIR "RemoveFolder"
00036 #define WIX_TAG_REGKEY "RegistryKey"
00037 #define WIX_TAG_REGVAL "RegistryValue"
00038
00039 typedef void (*TraverseCallback)(void *cbdata, QDomElement e);
00040
00041
00042
00043
00044
00045
00046
00047
00048 typedef struct s_SpliceData {
00049 QString dtag;
00050 QString did;
00051 QDomElement splice;
00052 } SpliceData;
00053
00054
00055
00056
00057
00058 typedef struct s_ReplaceData {
00059 QString dtag;
00060 QString did;
00061 QString dprop;
00062 QString newtag;
00063 QString newprop;
00064 QString newpropval;
00065 } ReplaceData;
00066
00067
00068
00069 typedef struct s_AddData {
00070 QString dtag;
00071 QString did;
00072 QString newtag;
00073 QString newprop;
00074 QString newpropval;
00075 } AddData;
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 typedef struct s_UserLocalData {
00087 QString keypath;
00088 QString featureid;
00089 QStringList newcomps;
00090 } UserLocalData;
00091
00092
00093
00094
00095
00096
00097 bool
00098 do_walkdoc(QDomNode n,
00099 TraverseCallback cb,
00100 void * cbdata,
00101 QString *errorMessage)
00102 {
00103 QTextStream error(stderr);
00104 if ( !n.isNull() ) {
00105 if ( n.isElement() ) {
00106 QDomElement e = n.toElement();
00107 (*cb)(cbdata, e);
00108 }
00109 if ( n.hasChildNodes() ) {
00110 QDomNodeList subnodes = n.childNodes();
00111 int i = 0;
00112 while (i < subnodes.count()) {
00113 do_walkdoc(subnodes.item(i++), cb, cbdata, errorMessage);
00114 }
00115 }
00116 }
00117 return true;
00118 }
00119
00120 bool
00121 walkdoc(QDomDocument *doc,
00122 TraverseCallback cb,
00123 void * cbdata,
00124 QString *errorMessage)
00125 {
00126 QTextStream error(stderr);
00127 QDomNode n = doc->documentElement();
00128 do_walkdoc(n, cb, cbdata, errorMessage);
00129 return true;
00130 }
00131
00132 void
00133 splicefunc(void *cbdata,
00134 QDomElement e)
00135 {
00136 SpliceData *d = reinterpret_cast<SpliceData *>(cbdata);
00137 QString eid = e.attribute(WIX_ATTR_ID);
00138
00139 if (e.tagName().compare(d->dtag) == 0) {
00140
00141 if (d->did.isEmpty() ||
00142 (eid.size() && !eid.compare(d->did)) ) {
00143
00144
00145
00146
00147 if (d->splice.hasChildNodes()) {
00148 QDomNodeList subnodes = d->splice.childNodes();
00149 int i = 0;
00150 while (i < subnodes.count()) {
00151 e.appendChild(e.ownerDocument().importNode(subnodes.item(i++), true));
00152 }
00153 }
00154 else {
00155 e.appendChild(e.ownerDocument().importNode(d->splice, true));
00156 }
00157 }
00158 }
00159 }
00160
00161
00162
00163
00164 bool
00165 docsplice(QDomDocument *doc,
00166 QString arguments,
00167 QString *errorMessage)
00168 {
00169 Q_ASSERT(doc);
00170 Q_ASSERT(errorMessage);
00171 SpliceData cbdata;
00172
00173 QStringList spliceinfo = arguments.split("=");
00174 if (spliceinfo.count() != 2) {
00175 *errorMessage = "Invalid argument for splice command: " + arguments;
00176 return false;
00177 }
00178 if (spliceinfo[0].contains(':')) {
00179
00180 QStringList destinfo = spliceinfo[0].split(":");
00181 cbdata.dtag = destinfo[0];
00182 cbdata.did = destinfo[1];
00183 }
00184 else {
00185 cbdata.dtag = spliceinfo[0];
00186 }
00187
00188 QStringList srcinfo = spliceinfo[1].split(":");
00189 if (srcinfo.count() < 2) {
00190 *errorMessage = "Invalid source argument for splice command: " + arguments;
00191 return false;
00192 }
00193 QFile spliceFile(srcinfo[0]);
00194 if (!spliceFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
00195 *errorMessage = QString("Unable to open '%1' for reading: %2\n")
00196 .arg(srcinfo[0]).arg(spliceFile.errorString());
00197 return false;
00198 }
00199 QTextStream sfiletxt(&spliceFile);
00200 QDomDocument sdoc;
00201 QString parseError;
00202 int badline, badcol;
00203 if (!sdoc.setContent (sfiletxt.readAll(), false, &parseError, &badline, &badcol)) {
00204 *errorMessage = QString("Error parsing splice document '%1' at line %2 and column %3: %4")
00205 .arg(srcinfo[0]).arg(badline).arg(badcol).arg(parseError);
00206 return false;
00207 }
00208
00209 QDomNodeList elist = sdoc.elementsByTagName(srcinfo[1]);
00210 if (elist.count() == 0) {
00211 *errorMessage = QString("Unable to locate splice element '%1' in document.\n").arg(srcinfo[1]);
00212 return false;
00213 }
00214 if (srcinfo.count() == 3) {
00215
00216 for (int i=0; i < elist.count(); i++) {
00217 QString eid = elist.item(i).toElement().attribute(WIX_ATTR_ID);
00218 if (eid.size() && !eid.compare(srcinfo[2])) {
00219 cbdata.splice = elist.item(i).toElement();
00220 }
00221 }
00222 }
00223 else {
00224
00225 cbdata.splice = elist.item(0).toElement();
00226 }
00227 return walkdoc(doc, &splicefunc, &cbdata, errorMessage);
00228 }
00229
00230 void
00231 replacefunc(void *cbdata,
00232 QDomElement e)
00233 {
00234 ReplaceData *d = reinterpret_cast<ReplaceData *>(cbdata);
00235 QString eid = e.attribute(WIX_ATTR_ID);
00236
00237 if (e.tagName().compare(d->dtag) == 0) {
00238
00239 if (d->did.isEmpty() ||
00240 (eid.size() && !eid.compare(d->did)) ) {
00241
00242
00243 if (d->newtag.isNull()) {
00244 QDomNode parent = e.parentNode();
00245 parent.removeChild(e);
00246 }
00247 else {
00248 if (d->newtag.compare(e.tagName())) {
00249 e.setTagName (d->newtag);
00250 }
00251 if (d->newprop.isNull()) {
00252
00253 QDomNamedNodeMap attrs = e.attributes();
00254 for (int i = 0; i < attrs.count(); i++) {
00255 if (attrs.item(i).nodeName().compare(WIX_ATTR_ID)) {
00256 e.removeAttribute(attrs.item(i).nodeName());
00257 }
00258 }
00259 }
00260 else {
00261
00262 QDomNode prop = e.attributeNode(d->newprop);
00263 if (!prop.isNull()) {
00264 e.setAttribute(d->newprop, d->newpropval);
00265 }
00266 }
00267 }
00268 }
00269 }
00270 }
00271
00272
00273
00274
00275 bool
00276 docreplace(QDomDocument *doc,
00277 QString arguments,
00278 QString *errorMessage)
00279 {
00280 Q_ASSERT(doc);
00281 Q_ASSERT(errorMessage);
00282 ReplaceData cbdata;
00283
00284 QStringList replaceinfo = arguments.split("=");
00285 if (replaceinfo.count() < 1) {
00286 *errorMessage = "Invalid argument for replace command: " + arguments;
00287 return false;
00288 }
00289 if (replaceinfo[0].contains(':')) {
00290
00291 QStringList destinfo = replaceinfo[0].split(":");
00292 cbdata.dtag = destinfo[0];
00293 cbdata.did = destinfo[1];
00294 if (destinfo.count() >= 3) {
00295 cbdata.dprop = destinfo[2];
00296 }
00297 }
00298 else {
00299 cbdata.dtag = replaceinfo[0];
00300 }
00301 if (replaceinfo.count() > 1) {
00302 QStringList srcinfo = replaceinfo[1].split(":");
00303 if (srcinfo.count() < 1) {
00304 *errorMessage = "Invalid target argument for replace command: " + arguments;
00305 return false;
00306 }
00307 if (srcinfo.count() >= 1) {
00308 if (srcinfo[0].length()) cbdata.newtag = srcinfo[0];
00309 }
00310 if (srcinfo.count() >= 2) {
00311 if (srcinfo[1].length()) cbdata.newprop = srcinfo[1];
00312 }
00313 if (srcinfo.count() >= 3) {
00314 if (srcinfo[2].length()) cbdata.newpropval = srcinfo[2];
00315 }
00316 }
00317 return walkdoc(doc, &replacefunc, &cbdata, errorMessage);
00318 }
00319
00320 void
00321 addfunc(void *cbdata,
00322 QDomElement e)
00323 {
00324 AddData *d = reinterpret_cast<AddData *>(cbdata);
00325 QString eid = e.attribute(WIX_ATTR_ID);
00326
00327 if (e.tagName().compare(d->dtag) == 0) {
00328
00329 if (d->did.isEmpty() ||
00330 (eid.size() && !eid.compare(d->did)) ) {
00331 if (d->newtag.compare(d->dtag)) {
00332 QDomElement ne = e.ownerDocument().createElement(d->newtag);
00333 if (!d->newprop.isNull()) {
00334 ne.setAttribute(d->newprop, d->newpropval);
00335 }
00336 e.appendChild(ne);
00337 }
00338 else {
00339 e.setAttribute(d->newprop, d->newpropval);
00340 }
00341 }
00342 }
00343 }
00344
00345
00346
00347
00348 bool
00349 docadd(QDomDocument *doc,
00350 QString arguments,
00351 QString *errorMessage)
00352 {
00353 Q_ASSERT(doc);
00354 Q_ASSERT(errorMessage);
00355 AddData cbdata;
00356
00357 QStringList addinfo = arguments.split("=");
00358 if (addinfo.count() < 1) {
00359 *errorMessage = "Invalid argument for add command: " + arguments;
00360 return false;
00361 }
00362 if (addinfo[0].contains(':')) {
00363
00364 QStringList destinfo = addinfo[0].split(":");
00365 cbdata.dtag = destinfo[0];
00366 cbdata.did = destinfo[1];
00367 }
00368 else {
00369 cbdata.dtag = addinfo[0];
00370 }
00371 if (addinfo.count() > 1) {
00372 QStringList srcinfo = addinfo[1].split(":");
00373 if (srcinfo.count() < 1) {
00374 *errorMessage = "Invalid target argument for add command: " + arguments;
00375 return false;
00376 }
00377 if (srcinfo.count() >= 1) {
00378 if (srcinfo[0].length()) cbdata.newtag = srcinfo[0];
00379 }
00380 if (srcinfo.count() >= 2) {
00381 if (srcinfo[1].length()) cbdata.newprop = srcinfo[1];
00382 }
00383 if (srcinfo.count() >= 3) {
00384 if (srcinfo[2].length()) cbdata.newpropval = srcinfo[2];
00385 }
00386 }
00387 return walkdoc(doc, &addfunc, &cbdata, errorMessage);
00388 }
00389
00390 void
00391 createRegLocalComponent(QDomElement e,
00392 QString dirName,
00393 QString keyPath)
00394 {
00395 QDomElement nrk = e.ownerDocument().createElement(WIX_TAG_REGKEY);
00396 QDomElement nrv = e.ownerDocument().createElement(WIX_TAG_REGVAL);
00397 nrk.setAttribute(WIX_ATTR_REG_ROOT, "HKCU");
00398 nrk.setAttribute(WIX_ATTR_REG_ACTION, "createAndRemoveOnUninstall");
00399 nrk.setAttribute(WIX_ATTR_REG_KEYPATH, keyPath);
00400 nrv.setAttribute(WIX_ATTR_REG_TYPE, WIX_REG_KEY_TYPE);
00401 nrv.setAttribute(WIX_ATTR_REG_NAME, dirName);
00402 nrv.setAttribute(WIX_ATTR_VALUE, "1");
00403 nrv.setAttribute(WIX_ATTR_KEY, "yes");
00404 nrk.appendChild(nrv);
00405 e.appendChild(nrk);
00406 }
00407
00408 void
00409 createDirMgmtComponent(QDomElement e,
00410 QString dirName)
00411 {
00412 QDomElement nce;
00413
00414 if (e.elementsByTagName(WIX_TAG_CREATEDIR).count() == 0) {
00415 nce = e.ownerDocument().createElement(WIX_TAG_CREATEDIR);
00416 e.appendChild(nce);
00417 }
00418 nce = e.ownerDocument().createElement(WIX_TAG_REMOVEDIR);
00419 nce.setAttribute("On", WIX_ATTR_DIRACTION);
00420 nce.setAttribute(WIX_ATTR_ID, QString("Remove").append(dirName));
00421 e.appendChild(nce);
00422 }
00423
00424 void
00425 userlocalfunc(void *cbdata,
00426 QDomElement e)
00427 {
00428 UserLocalData *ulinfo = reinterpret_cast<UserLocalData *>(cbdata);
00429 QString eid = e.attribute(WIX_ATTR_ID);
00430
00431 if (e.tagName().compare(WIX_TAG_FILE) == 0) {
00432 e.removeAttribute(WIX_ATTR_KEY);
00433 }
00434 else if (e.tagName().compare(WIX_TAG_COMPONENT) == 0) {
00435
00436
00437
00438
00439 e.removeAttribute(WIX_ATTR_KEY);
00440 }
00441 else if (e.tagName().compare(WIX_TAG_FEATURE) == 0) {
00442
00443 QDomNodeList cnl = e.elementsByTagName(WIX_TAG_COMPONENT_REF);
00444 for (int i = 0; i < cnl.count(); i++) {
00445 QDomElement cre = cnl.item(i).toElement();
00446 if (cre.attribute(WIX_ATTR_ID).compare(WIX_TAG_COMPONENT) == 0) {
00447 e.removeChild(cre);
00448 }
00449 }
00450 if (ulinfo->featureid.compare(e.attribute(WIX_ATTR_ID)) == 0) {
00451
00452 QDomElement ne;
00453 for (int i = 0; i < ulinfo->newcomps.count(); i++) {
00454 QString currid = ulinfo->newcomps[i];
00455 ne = e.ownerDocument().createElement(WIX_TAG_COMPONENT_REF);
00456 ne.setAttribute(WIX_ATTR_ID, currid);
00457 e.appendChild(ne);
00458 }
00459 }
00460 }
00461 else if (e.tagName().compare(WIX_TAG_DIR) == 0) {
00462 QString dirName = e.attribute(WIX_ATTR_NAME);
00463 QString dirId = e.attribute(WIX_ATTR_ID);
00464
00465
00466
00467 if ( e.hasChildNodes() ) {
00468 QDomElement fc;
00469 bool hasComponent = false;
00470 bool hasRegKey;
00471 QDomNodeList subnodes = e.childNodes();
00472 for (int i = 0; i < subnodes.count(); i++) {
00473 hasRegKey = false;
00474 if (subnodes.item(i).isElement()) {
00475 QDomElement ce = subnodes.item(i).toElement();
00476 if (ce.tagName().compare(WIX_TAG_COMPONENT) == 0) {
00477 if (!hasComponent) {
00478 hasComponent = true;
00479 fc = ce;
00480 if (ce.attribute(WIX_ATTR_ID).compare(WIX_TAG_COMPONENT) == 0) {
00481
00482 ce.setAttribute(WIX_ATTR_ID, QString("DCOMP").append(dirName));
00483 ulinfo->newcomps.append(ce.attribute(WIX_ATTR_ID));
00484 }
00485 if (ce.elementsByTagName(WIX_TAG_REMOVEDIR).count() == 0) {
00486 createDirMgmtComponent(ce, ce.attribute(WIX_ATTR_ID));
00487 }
00488 }
00489 QDomNodeList compnodes = ce.childNodes();
00490 for (int j = 0; j < compnodes.count(); j++) {
00491 if (compnodes.item(j).isElement()) {
00492 QDomElement compe = compnodes.item(j).toElement();
00493 if (compe.tagName().compare(WIX_TAG_REGKEY) == 0) {
00494 hasRegKey = true;
00495 }
00496 }
00497 }
00498 if (!hasRegKey) {
00499 createRegLocalComponent(ce, QString("RK").append(ce.attribute(WIX_ATTR_ID)), ulinfo->keypath);
00500 }
00501 }
00502 }
00503 }
00504 if (!hasComponent) {
00505
00506 if (dirId.compare("LocalAppDataFolder") &&
00507 dirId.compare("AppDataFolder") &&
00508 dirId.compare("CommonAppDataFolder") &&
00509 dirId.compare("CommonFilesFolder") &&
00510 dirId.compare("DesktopFolder") &&
00511 dirId.compare("PersonalFolder") &&
00512 dirId.compare("ProgramFilesFolder") &&
00513 dirId.compare("ProgramMenuFolder") &&
00514 dirId.compare("StartMenuFolder") &&
00515 dirId.compare("StartupFolder") &&
00516 dirId.compare("SystemFolder") &&
00517 dirId.compare("TempFolder") &&
00518 dirId.compare("WindowsFolder") ) {
00519
00520
00521
00522
00523 QDomElement ne = e.ownerDocument().createElement(WIX_TAG_COMPONENT);
00524 QString compId = QString("ULDirComp_").append(dirName);
00525 ne.setAttribute(WIX_ATTR_GUID, "*");
00526 ne.setAttribute(WIX_ATTR_ID, compId);
00527 e.appendChild(ne);
00528 createDirMgmtComponent(ne, dirName);
00529 createRegLocalComponent(ne, QString("DRK").append(dirName), ulinfo->keypath);
00530 ulinfo->newcomps.append(compId);
00531 }
00532 }
00533 }
00534 }
00535 }
00536
00537
00538
00539
00540 bool
00541 docuserlocal(QDomDocument *doc,
00542 QString argument,
00543 QString *errorMessage)
00544 {
00545 Q_ASSERT(doc);
00546 Q_ASSERT(errorMessage);
00547 UserLocalData cbdata;
00548
00549 QStringList ulinfo = argument.split(":");
00550 if (ulinfo.count() < 2) {
00551 *errorMessage = "Invalid argument for userlocal command: " + argument;
00552 return false;
00553 }
00554 cbdata.keypath = ulinfo[0];
00555 cbdata.featureid = ulinfo[1];
00556 return walkdoc(doc, &userlocalfunc, &cbdata, errorMessage);
00557 }
00558
00559
00560 void
00561 print_usage_and_exit()
00562 {
00563 QTextStream error(stderr);
00564 error << "usage: wixtool <command> [-q] -i <infile> -o <outfile> <Arg0> [... <ArgN>]" << endl;
00565 error << " command one of: " << endl;
00566 error << " splice Splice children from one document into another." << endl;
00567 error << " replace Replace elements or attributes in a document." << endl;
00568 error << " add Add elements or attributes into a document." << endl;
00569 error << " userlocal Convert File elements into per-user local elements." << endl;
00570 error << " -i <infile> Input or template file" << endl;
00571 error << " -o <outfile> Output file" << endl;
00572 error << endl;
00573 error << " splice args: desttagname[:Id]=file:basetag[:Id]" << endl;
00574 error << " Splice children of basetag in file under desttagname" << endl;
00575 error << endl;
00576 error << " replace args: tagname[:Id]:property=newtagname[:Id]:property:value" << endl;
00577 error << " If newtagname is empty the element is deleted" << endl;
00578 error << " If newproperty is empty the property is deleted" << endl;
00579 error << endl;
00580 error << " add args: desttagname[:Id]=newtagname[:Id]:property:value" << endl;
00581 error << " Add properties or child elements to target" << endl;
00582 error << " If newtagname is empty only properties added to dest" << endl;
00583 error << endl;
00584 error << " userlocal arg: <registry key path>:<dest feature id>" << endl;
00585 error << " Convert KeyPath File elements into the per user local idiom" << endl;
00586 error << " with corresponding Create/RemoveDir and RegistryKey elements." << endl;
00587 error << endl;
00588 error << " NOTE: text content within an element is not accessible." << endl;
00589 error << " Use the Value= attribute syntax if necessary." << endl;
00590 error << " The optional :Id syntax restricts matching to elements with" << endl;
00591 error << " the Id attribute set to the value indicated." << endl;
00592 error.flush();
00593 exit(1);
00594 }
00595
00596 int
00597 main(int argc, char *argv[])
00598 {
00599 QTextStream error(stderr);
00600 QString command, errorMessage;
00601 char *infile = 0, *outfile = 0;
00602 QTextCodec *codec = QTextCodec::codecForName("utf-8");
00603 bool quiet = false;
00604 QStringList commandargs;
00605
00606
00607 if (argc < 6)
00608 print_usage_and_exit();
00609
00610
00611 command = argv[1];
00612 if ( command.compare("splice", Qt::CaseInsensitive) &&
00613 command.compare("replace", Qt::CaseInsensitive) &&
00614 command.compare("add", Qt::CaseInsensitive) &&
00615 command.compare("userlocal", Qt::CaseInsensitive) ) {
00616 print_usage_and_exit();
00617 }
00618
00619
00620 for (int i = 2; i < argc; i++) {
00621 QString arg(argv[i]);
00622 if (!arg.compare("-q", Qt::CaseInsensitive))
00623 quiet = true;
00624 else if (!arg.compare("-i", Qt::CaseInsensitive) && ++i < argc)
00625 infile = argv[i];
00626 else if (!arg.compare("-o", Qt::CaseInsensitive) && ++i < argc)
00627 outfile = argv[i];
00628 else if (infile && outfile) {
00629 commandargs.append(arg);
00630 }
00631 }
00632 if ( !infile || !outfile || !commandargs.count() ) {
00633 print_usage_and_exit();
00634 }
00635
00636
00637 QFile srcFile(infile);
00638 QTextStream sfiletxt(&srcFile);
00639 sfiletxt.setCodec(codec);
00640 if (!srcFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
00641 error << QString("Unable to open '%1' for reading: %2\n").arg(infile)
00642 .arg(srcFile.errorString());
00643 return 2;
00644 }
00645
00646
00647 if (QFile::exists(outfile)) {
00648 if (!QFile::remove(outfile)) {
00649 error << QString("Unable to truncate outfile '%1'\n").arg(outfile);
00650 return 2;
00651 }
00652 }
00653
00654 QDomDocument doc;
00655 QString parseError;
00656 int badline, badcol;
00657 if (!doc.setContent (sfiletxt.readAll(), false, &parseError, &badline, &badcol)) {
00658 error << QString("Error parsing source document '%1' at line %2 and column %3: %4")
00659 .arg(infile).arg(badline).arg(badcol).arg(parseError);
00660 return 3;
00661 }
00662
00663 if (!command.compare("userlocal", Qt::CaseInsensitive)) {
00664 if (!docuserlocal(&doc, commandargs[0], &errorMessage)) {
00665 error << QString("Unable to convert document components to user local: %1\n")
00666 .arg(errorMessage);
00667 return 4;
00668 }
00669 }
00670 else {
00671 for (int i = 0; i < commandargs.count(); i++) {
00672 if (!command.compare("splice", Qt::CaseInsensitive)) {
00673 if (!docsplice(&doc, commandargs[i], &errorMessage)) {
00674 error << QString("Unable to process splice command '%1': %2\n")
00675 .arg(commandargs[i]).arg(errorMessage);
00676 return 4;
00677 }
00678 }
00679 else if (!command.compare("replace", Qt::CaseInsensitive)) {
00680 if (!docreplace(&doc, commandargs[i], &errorMessage)) {
00681 error << QString("Unable to process replace command '%1': %2\n")
00682 .arg(commandargs[i]).arg(errorMessage);
00683 return 4;
00684 }
00685 }
00686 else if (!command.compare("add", Qt::CaseInsensitive)) {
00687 if (!docadd(&doc, commandargs[i], &errorMessage)) {
00688 error << QString("Unable to process add command '%1': %2\n")
00689 .arg(commandargs[i]).arg(errorMessage);
00690 return 4;
00691 }
00692 }
00693 }
00694 }
00695
00696
00697 QFile docFile(outfile);
00698 if (!docFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
00699 error << QString("Unable to open '%1' for writing: %2\n").arg(outfile)
00700 .arg(docFile.errorString());
00701 return 5;
00702 }
00703
00704
00705 QTextStream out(&docFile);
00706 out << doc.toString(4);
00707
00708 return 0;
00709 }
00710