#include "headers.hxx" #include "..\CSVDSReader.hpp" #include "..\constants.hpp" #include "..\global.hpp" #include ///////////// Basic Functions /////////////// // included so that sizeof(guids) works properlly #include "..\guids.inc" // used for parameter checking in wmain bool fileExists(const wchar_t *fileName,const wchar_t *mode=L"r") { FILE *f=_wfopen(fileName,mode); if(f==NULL) return false; fclose(f); return true; } // used for parameter checking in wmain #define BREAK_IF_MISSING(hr,fileName) \ if(!fileExists(fileName.c_str())) \ { \ hr=E_FAIL; \ wprintf(L"\n File Missing: %s.\n",fileName.c_str()); \ break; \ } \ // used for parameter checking in wmain #define BREAK_IF_MISSING_OR_READONLY(hr,fileName) \ BREAK_IF_MISSING(hr,fileName) \ if(!fileExists(fileName.c_str(),L"a+")) \ { \ hr=E_FAIL; \ wprintf(L"\n Read Only: %s.\n",fileName.c_str()); \ break; \ } \ // converts outStr to AnsiString and writes to fileOut // Fails if conversion or writing fails HRESULT writeStringAsAnsi(HANDLE fileOut,const String& outStr) { AnsiString ansiStr; String::ConvertResult res=outStr.convert(ansiStr); if(res!=String::CONVERT_SUCCESSFUL) { ASSERT(res==String::CONVERT_SUCCESSFUL); error=L"Ansi conversion failed"; return E_FAIL; } return FS::Write(fileOut,ansiStr); } // converts outStr to AnsiString and writes to fileOut // Fails if conversion or writing fails HRESULT printStringAsAnsi(const String& outStr) { AnsiString ansiStr; String::ConvertResult res=outStr.convert(ansiStr); if(res!=String::CONVERT_SUCCESSFUL) { ASSERT(res==String::CONVERT_SUCCESSFUL); error=L"Ansi conversion failed"; return E_FAIL; } return printf(ansiStr.c_str()); } // performs a-b, keys in a but not in b go to out template void mapKeyDifference ( const map &a, const map &b, map &out ) { out.clear(); map ::const_iterator cur=a.begin(),end=a.end(); while(cur!=end) { if(b.find(cur->first)==b.end()) { out[cur->first]=cur->second; } cur++; } } // true if all keys in a are in b and a.size()=b.size() template bool mapKeyEqual ( const map &a, const map &b ) { if (a.size()!=b.size()) return false; map ::const_iterator cur=a.begin(),end=a.end(); while(cur!=end) { if(b.find(cur->first)==b.end()) { return false; } cur++; } return true; } // performs a ^ b, keys in both a and in b go to out template void mapKeyIntersection ( const map &a, const map &b, map &out ) { out.clear(); map ::const_iterator cur=a.begin(),end=a.end(); while(cur!=end) { if(b.find(cur->first)!=b.end()) { out[cur->first]=cur->second; } cur++; } } String escape(const String &str) { LOG_FUNCTION(escape); String dest; wchar_t strNum[7]; const wchar_t *csr=str.c_str(); while(*csr!=0) { wsprintf(strNum,L"\\x%x",*csr); dest+=String(strNum); csr++; } return dest; } HRESULT parseGUID ( const String& str, long *ordinal, GUID *guid ) { wchar_t *stop; HRESULT hr=S_OK; do { if (str.size()==0 || str[str.size()-1]!='}') { hr=E_FAIL; break; } String strAux=str.substr(0,str.size()-1); const wchar_t *strGuid=strAux.c_str(); *ordinal=wcstol(strGuid,&stop,10); if(*stop!=L',' || *(stop+1)!=L'{' || stop==strGuid) { hr=E_FAIL; break; } if(UuidFromString(stop+2,guid)!=RPC_S_OK) { hr=E_FAIL; break; } } while(0); return hr; } bool isGuid(const String &str) { long ordinal; GUID guid; return SUCCEEDED(parseGUID(str,&ordinal,&guid)); } String makeGuidString(long ordinal,GUID guid) { String ret; wchar_t *wRet; if(UuidToString(&guid,&wRet)!=RPC_S_OK) throw new bad_alloc; ret=String::format(L"%1!d!,{%2}",ordinal,wRet); RpcStringFree(&wRet); return ret; } ///////////// Basic Functions End /////////////// /////////////////////////////////////////////////// // Return the differences and commonalities between the // properties in oldCsv and newCsv. Uses csvName to specify // the csv in error messages. // Failure cases: // no common properties // properties in oldCsv not in newCsv HRESULT getPropertyChanges ( const CSVDSReader &oldCsv, const CSVDSReader &newCsv, mapOfPositions &commonProperties, mapOfPositions &newProperties, const wchar_t *csvName ) { const mapOfPositions &oldProps=oldCsv.getProperties(); const mapOfPositions &newProps=newCsv.getProperties(); mapKeyIntersection(oldProps,newProps,commonProperties); if(commonProperties.size()==0) { error=String::format(L"No comon %1!s! properties!",csvName); return E_FAIL; } mapOfPositions deletedProps; mapKeyDifference(oldProps,newProps,deletedProps); if(deletedProps.size()!=0) { error=String::format ( L"Properties only in the old %1!s! are not supported, since" L"there is no operation to delete a property. there are %2!d!" L"properties like this and \"%3!s!\" is the first property.", csvName,deletedProps.size(), deletedProps.begin()->first ); return E_FAIL; } mapKeyDifference(newProps,oldProps,newProperties); if(newProperties.size()==0) { wprintf(L"No new %s properties.\n",csvName); return S_OK; } return S_OK; } // Adds to commonProperties the commonProperties between oldDcpromo // and newDcpromo. and to new properties the properties in oldDcPromo // not in newDcpromo // Failure cases: // dcpromo's common properties are not the same as 409's // dcpromo's new properties are not the same as 409's HRESULT getAllPropertyChanges ( const CSVDSReader &oldDcpromo, const CSVDSReader &newDcpromo, const CSVDSReader &old409, const CSVDSReader &new409, mapOfPositions &commonProperties, mapOfPositions &newProperties ) { HRESULT hr=S_OK; do { hr=getPropertyChanges( oldDcpromo, newDcpromo, commonProperties, newProperties, L"dcpromo" ); BREAK_ON_FAILED_HRESULT(hr); mapOfPositions prop409New,prop409Common; hr=getPropertyChanges( old409, new409, prop409Common, prop409New, L"409" ); BREAK_ON_FAILED_HRESULT(hr); if(!mapKeyEqual(prop409New,newProperties)) { error=L"409 and dcpromo new properties are not the same."; hr=E_FAIL; break; } if(!mapKeyEqual(prop409Common,commonProperties)) { error=L"409 and dcpromo common properties are not the same."; hr=E_FAIL; break; } } while (0); return hr; } // Writes the very begining of a computer generated // file header to fileOut HRESULT writeHeader(const HANDLE fileOut) { char* header; header ="// This file is generated by preBuild.exe\r\n" "// Copyright (c) 2001 Microsoft Corporation\r\n" "// Nov 2001 lucios\r\n" "\r\n" "#include \"headers.hxx\"\r\n" "#include \"constants.hpp\"\r\n" "\r\n"; return FS::Write(fileOut,AnsiString(header)); } // Writes the nsetLocaleDependentChangesN function declaration to fileOut, // where N is the guidNumber. HRESULT writeChangesHeader(const HANDLE fileOut,int guidNumber) { String locDepStr=String::format ( "\r\nvoid setChanges%1!d!()\r\n{\r\n", guidNumber ); return writeStringAsAnsi(fileOut,locDepStr); } // Add an entry for the object/locale to fileOut. HRESULT writeChange ( HANDLE fileOut, long locale, const String &object, const String &property, const String &arg1, const String &arg2, const String &operation, int guidNumber ) { String entry=String::format ( L"\r\n" L" addChange\r\n" L" (\r\n" L" guids[%1!d!],\r\n" L" 0x%2!x!,\r\n" L" L\"%3\",\r\n" L" L\"%4\",\r\n" L" //%5\r\n" L" L\"%6\",\r\n" L" //%7\n" L" L\"%8\",\r\n" L" %9\r\n" L" );\r\n\r\n", guidNumber, locale, object.c_str(), property.c_str(), arg1.c_str(), escape(arg1).c_str(), arg2.c_str(), escape(arg2).c_str(), operation.c_str() ); return writeStringAsAnsi(fileOut,entry); } HRESULT dealWithSingleValue ( HANDLE fileOut, long locale, const String &object, const String &property, const StringList &valuesOld, const StringList &valuesNew, int guidNumber ) { // both sizes 0 is ok. if (valuesOld.size()==0 && valuesNew.size()==0) return S_OK; if (valuesOld.size()!=1 && valuesNew.size()!=1) { // In the future we might want to add ADD_VALUE and REMOVE_VALUE // operations, for now we just want to be flagged. error = String::format ( L"Error in locale %1!x!, object %2," L"property %3.Number of values should be 1,1 " L"instead of %4,%5.", locale, object.c_str(), property.c_str(), valuesOld.size(), valuesNew.size() ); return E_FAIL; } // Now we know we have a single value in each if(*valuesOld.begin()!=*valuesNew.begin()) { return ( writeChange ( fileOut, locale, object, property, *valuesOld.begin(), *valuesNew.begin(), L"REPLACE_W2K_SINGLE_VALUE", guidNumber ) ); } return S_OK; } // These are values in the form "root,rest" // if a value has the same root but a different rest we need to add // a REPLACE_MULTIPLE_VALUE_OPERATION // rotts in new that are not in old and roots in old that are not in new // should be printed for manual inclusion since we don't know how to deal // with them. typedef map< String, String, less, Burnslib::Heap::Allocator > rootToRest; HRESULT dealWithMultipleValue ( HANDLE fileOut, long locale, const String &object, const String &property, const StringList &valuesOld, const StringList &valuesNew, int guidNumber ) { HRESULT hr=S_OK; rootToRest newRoots, oldRoots; do { if(valuesOld.size()!=valuesNew.size()) { error= String::format ( L"Error in locale %1!x!, object %2," L"property %3. Old has %4 values and new has %5. " L"They should have the same number of values.", locale, object.c_str(), property.c_str(), valuesOld.size(), valuesNew.size() ); hr=E_FAIL; break; } // first lets add all roots and rests in maps // Starting by the old values... StringList::const_iterator csr,end; for(csr=valuesOld.begin(),end=valuesOld.end();csr!=end;csr++) { const String& value=*csr; long pos=value.find(L','); if(pos==String::npos) continue; String root=value.substr(0,pos); String rest=value.substr(pos+1); oldRoots[root]=rest; } BREAK_ON_FAILED_HRESULT(hr); //...And then the new values for(csr=valuesNew.begin(),end=valuesNew.end();csr!=end;csr++) { const String& value=*csr; long pos=value.find(L','); if(pos==String::npos) continue; String root=value.substr(0,pos); String rest=value.substr(pos+1); newRoots[root]=rest; } BREAK_ON_FAILED_HRESULT(hr); // now lets check all the values in one that are not in the other... rootToRest::iterator csrRoot=oldRoots.begin(),endRoot=oldRoots.end(); rootToRest oldRootsNotInNew; for(;csrRoot!=endRoot;csrRoot++) { if(newRoots.find(csrRoot->first)==newRoots.end()) { oldRootsNotInNew[csrRoot->first]=csrRoot->second; } } BREAK_ON_FAILED_HRESULT(hr); // ..and the values in other that are not in one, and... rootToRest newRootsNotInOld; csrRoot=newRoots.begin(),endRoot=newRoots.end(); for(;csrRoot!=endRoot;csrRoot++) { if(oldRoots.find(csrRoot->first)==oldRoots.end()) { newRootsNotInOld[csrRoot->first]=csrRoot->second; } } BREAK_ON_FAILED_HRESULT(hr); // ..if we have such values we need to investigate it further if(!oldRootsNotInNew.empty() || !newRootsNotInOld.empty()) { // if we have exactly one "old value" not in "new" and one // "new value" not in "old" we are going to assume that the // "old value" should be replaced by the "new value"... if(oldRootsNotInNew.size()==1 && newRootsNotInOld.size()==1) { String arg1=String::format ( L"%1,%2", oldRootsNotInNew.begin()->first.c_str(), oldRootsNotInNew.begin()->second.c_str() ); String arg2=String::format ( L"%1,%2", newRootsNotInOld.begin()->first.c_str(), newRootsNotInOld.begin()->second.c_str() ); String outStr=String::format ( L"\nAssuming change from:\"%1\" to \"%2\" for " L"locale %3!lx!, object %4 and property %5.\n", arg1.c_str(), arg2.c_str(), locale, object.c_str(), property.c_str() ); // We are ignoring the result returned here. printStringAsAnsi(outStr); hr=writeChange ( fileOut, locale, object, property, arg1, arg2, L"REPLACE_W2K_MULTIPLE_VALUE", guidNumber ); BREAK_ON_FAILED_HRESULT(hr); } else // ...otherwise we flag it as an error. { error= String::format ( L"Error in locale %1!x!, object %2," L"property %3. There are %4 old values with the pre comma " L"string not present in the new values and %5 new values " L"with the pre comma string not present in the old values." L"Without a common root it is not possible to know what " L"replacement to make.", object.c_str(), property.c_str(), newRootsNotInOld.size(), oldRootsNotInNew.size() ); hr=E_FAIL; break; } } //Now we detect changes for common root values csrRoot=newRoots.begin(),endRoot=newRoots.end(); for(;csrRoot!=endRoot;csrRoot++) { const String& newRoot=csrRoot->first; const String& newRest=csrRoot->second; // if the new root is in old and the value changed if( oldRoots.find(newRoot)!=oldRoots.end() && newRest!=oldRoots[newRoot] ) { hr=writeChange ( fileOut, locale, object, property, String::format(L"%1,%2",newRoot.c_str(), oldRoots[newRoot].c_str()).c_str(), String::format(L"%1,%2",newRoot.c_str(), newRest.c_str()).c_str(), L"REPLACE_W2K_MULTIPLE_VALUE", guidNumber ); BREAK_ON_FAILED_HRESULT(hr); } } BREAK_ON_FAILED_HRESULT(hr); } while (0); return hr; } // if any value in valuesOld or valuesNew does not ressemble a GUID, fails // since, in order to call this function, we've already checked that at least // one in valuesOld or valuesNew ressembles a GUID. // if x,{xxx} is y,{xxx} fails // if x,{xxx} is x,{yyy} in the new csv REPLACE_GUID // all {guids} in old not in new(not replaced) REMOVE_GUID // all {guids} in new not in old(not replaced) ADD_GUID typedef map< GUID, long, GUIDLess, Burnslib::Heap::Allocator > guidToOrd; typedef map< long, GUID, less, Burnslib::Heap::Allocator > ordToGuid; HRESULT dealWithGuids ( HANDLE fileOut, long locale, const String &object, const String &property, const StringList &valuesOld, const StringList &valuesNew, int guidNumber ) { HRESULT hr=S_OK; do { guidToOrd guidToOrdNew; guidToOrd guidToOrdOld; ordToGuid ordToGuidOld; guidToOrd replacements; GUID oldGuid;long oldOrd; GUID guid;long ordinal; // First lets add the guids and ordinals to auxilliary maps // starting with the old values... StringList::const_iterator cur,end; cur=valuesOld.begin();end=valuesOld.end(); for(;cur!=end;cur++) { const String &guidValue=*cur; hr=parseGUID(guidValue,&ordinal,&guid); if(FAILED(hr)) { error= String::format ( L"Error in locale %1!x!, object %2," L"property %3. Failed to parse old guid: %4", locale, object.c_str(), property.c_str(), guidValue.c_str() ); break; } guidToOrdOld[guid]=ordinal; ordToGuidOld[ordinal]=guid; } BREAK_ON_FAILED_HRESULT(hr); // ...and then the new values. cur=valuesNew.begin();end=valuesNew.end(); for(;cur!=end;cur++) { const String &guidValue=*cur; hr=parseGUID(guidValue,&ordinal,&guid); if(FAILED(hr)) { error= String::format ( L"Error in locale %1!x!, object %2," L"property %3. Failed to parse new guid: %4", locale, object.c_str(), property.c_str(), guidValue.c_str() ); break; } guidToOrdNew[guid]=ordinal; } BREAK_ON_FAILED_HRESULT(hr); // Lets treat replacements and additions first guidToOrd::iterator csr,endCsr; csr=guidToOrdNew.begin(); endCsr=guidToOrdNew.end(); for(;csr!=endCsr;csr++) { GUID newGuid=csr->first; long newOrd=csr->second; // this flag is used not to add a replacement bool newGuidWasReplaced=false; //... if ordinal is in old... if( ordToGuidOld.find(newOrd)!=ordToGuidOld.end() ) { GUID oldGuid=ordToGuidOld[newOrd]; // ...with a different GUID, this means a replacement. if(oldGuid!=newGuid) { hr=writeChange ( fileOut, locale, object, property, makeGuidString(newOrd,oldGuid), makeGuidString(newOrd,newGuid), L"REPLACE_GUID", guidNumber ); BREAK_ON_FAILED_HRESULT(hr); replacements[oldGuid]=newOrd; newGuidWasReplaced=true; } // we have no else because if both the ordinal and guid // are the same there is nothing to do. } // if new guid is also in old... if( guidToOrdOld.find(newGuid)!=guidToOrdOld.end() ) { long oldOrd=guidToOrdOld[newGuid]; //...with a different ordinal we have a situation we are not // prepared to deal with for now if(oldOrd!=newOrd) { error= String::format ( L"Error in locale %1!x!, object %2," L"property %3. Guid:%4 has different ordinals in " L"new and old (ordinal=%5!d!) csv files.", locale, object.c_str(), property.c_str(), makeGuidString(newOrd,newGuid).c_str(), oldOrd ); break; } // we have no else because if both the ordinal and guid // are the same there is nothing to do. } else { if(!newGuidWasReplaced) { hr=writeChange ( fileOut, locale, object, property, makeGuidString(newOrd,newGuid), "", L"ADD_GUID", guidNumber ); BREAK_ON_FAILED_HRESULT(hr); } } } BREAK_ON_FAILED_HRESULT(hr); // Now let's check for guids only in the old csr=guidToOrdOld.begin(),endCsr=guidToOrdOld.end(); for(;csr!=endCsr;csr++) { oldGuid=csr->first; oldOrd=csr->second; // if oldGuid is not in new and has not already been replaced if( guidToOrdNew.find(oldGuid)==guidToOrdNew.end() && replacements.find(oldGuid)==replacements.end() ) { hr=writeChange ( fileOut, locale, object, property, makeGuidString(oldOrd,oldGuid).c_str(), L"", L"REMOVE_GUID", guidNumber ); BREAK_ON_FAILED_HRESULT(hr); } } BREAK_ON_FAILED_HRESULT(hr); } while(0); return hr; } BOOL MyIsNLSDefinedString ( const String& str, wchar_t *badChar ) { BOOL ret=IsNLSDefinedString ( COMPARE_STRING, 0, NULL, str.c_str(), str.length() ); if(ret==FALSE) { wchar_t s[2]={0}; for(long t=0;tsecond.begin(); StringList::const_iterator endVal=csr->second.end(); for(;csrVal!=endVal;csrVal++) { wchar_t badChar; if( MyIsNLSDefinedString(*csrVal,&badChar) == FALSE ) { String outStr=String::format ( L"\nNon unicode char %1!x! in string:\"%2\" for " L"locale %3!lx!, object %4 and property %5.\n", badChar, csrVal->c_str(), locale, object.c_str(), csr->first.c_str() ); // We are ignoring the result returned here. printStringAsAnsi(outStr); hr=E_FAIL; break; } } BREAK_ON_FAILED_HRESULT(hr); } BREAK_ON_FAILED_HRESULT(hr); } while(0); hr=S_OK; // for now we always return true but we will make this // a critical error when this checking makes to the AD return hr; } // Reads synchronally csvOld and csvNew adding the necessary changes. // Objects only in csvOld will cause failure // For objects only in csvNew call addNewObject to add an ADD_OBJECT entry. // For each common object betweem csvOld and csvNew: // For each object property belonging to newProperties and with a non // empty value add call addAllCsvValues to add an ADD_CSV_VALUES entry. // for each property in the object belonging to commonProperties // valuesOld = value of the property in oldCsv // valuesNew = value of the property in newCsv // if valuesNew and valuesOld are empty skip this value // if either first value of valuesNew or valuesOld ressembles a GUID // call dealWithGuid to add ADD_GUID/REPLACE_GUID/DELETE_GUID as necessary and // and skip to next. // if both valuesNew.size and valuesOld.size <= 1 call dealWithSingleValue // to add REPLACE_SINGLE_VALUE as necessary and skip to next // dealWithMultipleValue to add REPLACE_MULTIPLE_VALUE as necessary and // skip to next. HRESULT addChanges ( HANDLE fileOut, const CSVDSReader &csvOld, const CSVDSReader &csvNew, const mapOfPositions &commonProperties, const mapOfPositions &newProperties, int guidNumber, const wchar_t *csvName ) { HRESULT hr=S_OK; do { // Here we start readding both csv files hr=csvOld.initializeGetNext(); BREAK_ON_FAILED_HRESULT(hr); hr=csvNew.initializeGetNext(); BREAK_ON_FAILED_HRESULT(hr); // The loop bellow will sequentially read objects // in both csv's making sure the same objects are read. bool flagEOF=false; do { mapOfProperties oldValues,newValues; long locOld=0,locNew=0; String objOld,objNew; hr=csvOld.getNextObject(locOld,objOld,oldValues); BREAK_ON_FAILED_HRESULT(hr); if(hr==S_FALSE) {flagEOF=true;hr=S_OK;} hr=checkValues(locOld,objOld,oldValues); BREAK_ON_FAILED_HRESULT(hr); hr=csvNew.getNextObject(locNew,objNew,newValues); BREAK_ON_FAILED_HRESULT(hr); // While we don't find the object from the old csv // in the new csv we add entries for the new objects found while(hr!=S_FALSE && (locNew!=locOld || objNew!=objOld) ) { hr= writeChange ( fileOut, locNew, objNew, L"", L"", L"", L"ADD_OBJECT", guidNumber ); BREAK_ON_FAILED_HRESULT(hr); hr=checkValues(locNew,objNew,newValues); BREAK_ON_FAILED_HRESULT(hr); hr=csvNew.getNextObject(locNew,objNew,newValues); BREAK_ON_FAILED_HRESULT(hr); } BREAK_ON_FAILED_HRESULT(hr); if(hr==S_FALSE) {flagEOF=true;hr=S_OK;} hr=checkValues(locNew,objNew,newValues); BREAK_ON_FAILED_HRESULT(hr); // This means that we searched the whole new csv file and didn't // find the object we've read from the old csv file. if(locNew!=locOld || objNew!=objOld) { error=String::format ( L"Error:%1!d!,%2 was only in the old %3 csv file.", locOld,objOld.c_str(), csvName ); hr=E_FAIL; break; } // From this point on we know the object is // the same in old and new csv files // This happens if we have a blank line at the end of the files if(locNew==0) break; // now let's check the differences in the common properties mapOfPositions::const_iterator cur=newProperties.begin(); mapOfPositions::const_iterator end=newProperties.end(); for(;cur!=end;cur++) { const String& property=cur->first; const StringList &valuesNew=newValues[property]; if(!valuesNew.empty()) { // We only want to use ADD_ALL_CSV_VALUES if it // is not a guid. It will probably be the same as // ADD_ALL_CSV_VALUES for most cases but it is // better policy to keep all guid additions // with an ADD_GUID change. if( isGuid(*valuesNew.begin()) ) { // We know we don't have old values because this is a // new property StringList emptyValues; hr= dealWithGuids ( fileOut, locNew, objNew, property, emptyValues, valuesNew, guidNumber ); BREAK_ON_FAILED_HRESULT(hr); } else { hr= writeChange ( fileOut, locNew, objNew, property, L"", L"", L"ADD_ALL_CSV_VALUES", guidNumber ); BREAK_ON_FAILED_HRESULT(hr); } } } BREAK_ON_FAILED_HRESULT(hr); // now let's check the differences in the common properties cur=commonProperties.begin(); end=commonProperties.end(); for(;cur!=end;cur++) { const String& property=cur->first; const StringList &valuesOld=oldValues[property]; const StringList &valuesNew=newValues[property]; if (valuesOld.empty() && valuesNew.empty()) continue; // The or bellows means either value being guid we want // to deal with them in dealWithGuids. Inside it, all non // guids would trigger an error. if ( ( !valuesOld.empty() && isGuid(*valuesOld.begin()) ) || ( !valuesNew.empty() && isGuid(*valuesNew.begin()) ) ) { hr= dealWithGuids ( fileOut, locNew, objNew, property, valuesOld, valuesNew, guidNumber ); BREAK_ON_FAILED_HRESULT(hr); continue; } // Now we know that we don't have a guid change if(valuesNew.size()<=1 && valuesOld.size()<=1) { hr= dealWithSingleValue ( fileOut, locNew, objNew, property, valuesOld, valuesNew, guidNumber ); BREAK_ON_FAILED_HRESULT(hr); continue; } // Now we know that we don't have GUIDS or single values hr= dealWithMultipleValue ( fileOut, locNew, objNew, property, valuesOld, valuesNew, guidNumber ); BREAK_ON_FAILED_HRESULT(hr); } BREAK_ON_FAILED_HRESULT(hr); } while (flagEOF==false); BREAK_ON_FAILED_HRESULT(hr); } while(0); return hr; } // Writes the whole SetChanges function with the locales // from dcpromo and 409. // Calls writeChangesHeader and then addChanges twice, one // for each csv pair. Finally, calls FS::Write(fileOut,L"\n}");. HRESULT addAllChanges ( HANDLE fileOut, const CSVDSReader &oldDcpromo, const CSVDSReader &newDcpromo, const CSVDSReader &old409, const CSVDSReader &new409, const mapOfPositions &commonProperties, const mapOfPositions &newProperties, int guidNumber ) { HRESULT hr=S_OK; do { hr=writeChangesHeader(fileOut,guidNumber); BREAK_ON_FAILED_HRESULT(hr); hr=addChanges ( fileOut, old409, new409, commonProperties, newProperties, guidNumber, L"409" ); BREAK_ON_FAILED_HRESULT(hr); hr=addChanges ( fileOut, oldDcpromo, newDcpromo, commonProperties, newProperties, guidNumber, L"dcpromo" ); BREAK_ON_FAILED_HRESULT(hr); hr = writeStringAsAnsi(fileOut,L"\r\n}"); BREAK_ON_FAILED_HRESULT(hr); } while(0); return hr; } // writes setChangesNNN.cpp. Sets up by caling getAllPropertyChanges, calls // writeHeader and then addAllChanges // Creates the CSVReader objects corresponding to the 4 first parameters // to pass to writeGlobalChanges and writeGlobalChanges. // guidNumber is repassed to addAllChanges HRESULT writeChanges ( const String &oldDcpromoName, const String &newDcpromoName, const String &old409Name, const String &new409Name, const String &changesCpp, int guidNumber ) { HRESULT hr=S_OK; HANDLE fChanges = INVALID_HANDLE_VALUE; hr=FS::CreateFile ( changesCpp.c_str(), fChanges, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS ); do { if (FAILED(hr)) { wprintf(L"Could not create changes file: %s.",changesCpp.c_str()); break; } do { CSVDSReader oldDcpromo; hr=oldDcpromo.read(oldDcpromoName.c_str(),LOCALEIDS); BREAK_ON_FAILED_HRESULT(hr); CSVDSReader newDcpromo; hr=newDcpromo.read(newDcpromoName.c_str(),LOCALEIDS); BREAK_ON_FAILED_HRESULT(hr); CSVDSReader old409; hr=old409.read(old409Name.c_str(),LOCALE409); BREAK_ON_FAILED_HRESULT(hr); CSVDSReader new409; hr=new409.read(new409Name.c_str(),LOCALE409); BREAK_ON_FAILED_HRESULT(hr); mapOfPositions commonProperties,newProperties; hr=getAllPropertyChanges ( oldDcpromo, newDcpromo, old409, new409, commonProperties, newProperties ); BREAK_ON_FAILED_HRESULT(hr); hr=writeHeader(fChanges); BREAK_ON_FAILED_HRESULT(hr); hr=addAllChanges ( fChanges, oldDcpromo, newDcpromo, old409, new409, commonProperties, newProperties, guidNumber ); BREAK_ON_FAILED_HRESULT(hr); } while(0); CloseHandle(fChanges); } while(0); return hr; } HRESULT writeGuid(HANDLE fOut,const GUID &guid) { return ( writeStringAsAnsi ( fOut, String::format ( " {0x%1!x!,0x%2!x!,0x%3!x!,{0x%4!x!,0x%5!x!,0x%6!x!," "0x%7!x!,0x%8!x!,0x%9!x!,0x%10!x!,0x%11!x!}},\r\n", guid.Data1,guid.Data2,guid.Data3, guid.Data4[0],guid.Data4[1],guid.Data4[2],guid.Data4[3], guid.Data4[4],guid.Data4[5],guid.Data4[6],guid.Data4[7] ).c_str() ) ); } HRESULT writeGuids(const String& guidsInc,const GUID &newGuid) { HRESULT hr=S_OK; HANDLE fOut= INVALID_HANDLE_VALUE; hr=FS::CreateFile ( guidsInc.c_str(), fOut, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS ); do { if (FAILED(hr)) { wprintf(L"Could not create changes file: %s.",guidsInc.c_str()); break; } do { int sizeGuids=sizeof(guids)/sizeof(*guids); hr=FS::Write ( fOut, AnsiString ( "// This file is generated by preBuild.exe\r\n" "// Copyright (c) 2001 Microsoft Corporation\r\n" "// Nov 2001 lucios\r\n\r\n\r\n" "GUID guids[]=\r\n" "{\r\n" ) ); BREAK_ON_FAILED_HRESULT(hr); for(int ix=0;ix