#include "headers.hxx" #include "..\CSVDSReader.hpp" #include "..\constants.hpp" #include "..\global.hpp" #include String escape(const wchar_t *str) { LOG_FUNCTION(escape); String dest; wchar_t strNum[5]; while(*str!=0) { wsprintf(strNum,L"\\x%x",*str); dest+=String(strNum); str++; } return dest; } String issues; bool isPropertyInChangeList ( String, //property, const objectChanges &//changes ) { /*objectChanges::const_iterator begin,end; begin=changes.begin(); end=changes.end(); while(begin!=end) { changeList::const_iterator beginChanges,endChanges; beginChanges=begin->second.begin(); endChanges=begin->second.end(); while(beginChanges!=endChanges) { if (property.icompare(beginChanges->property)==0) return true; beginChanges++; } begin++; }*/ return false; } bool isObjectPropertyInChangeList ( String object, String property, const objectChanges &changes ) { objectChanges::const_iterator begin,end; begin=changes.begin(); end=changes.end(); while(begin!=end) { changeList::const_iterator beginChanges,endChanges; beginChanges=begin->second.begin(); endChanges=begin->second.end(); while(beginChanges!=endChanges) { if ( property.icompare(beginChanges->property)==0 && object.icompare(beginChanges->object)==0 ) { return true; } beginChanges++; } begin++; } return false; } HRESULT getCommonProperties ( const mapOfPositions& pp1, const mapOfPositions& pp2, StringList &commonProperties ) { LOG_FUNCTION(getCommonProperties); HRESULT hr=S_OK; do { if(pp1.size()!=0) { mapOfPositions::const_iterator begin=pp1.begin(),end=pp1.end(); while(begin!=end) { if(pp2.find(begin->first)==pp2.end()) { error=L"The property:" + begin->first + L" was found only in Old. \r\n" + L"This program does not take into account" + L" the removal of properties from Old to New.\r\n" L"You should pass the Old csv file as the" L" first command line argument."; hr=E_FAIL; break; } begin++; } BREAK_ON_FAILED_HRESULT(hr); } if(pp2.size()!=0) { mapOfPositions::const_iterator begin=pp2.begin(),end=pp2.end(); while(begin!=end) { if(pp1.find(begin->first)==pp1.end()) { //bugbug - No Longer possible /*if (!isPropertyInChangeList(begin->first,changes)) { issues += L"The property:" + begin->first + L" was found only in New but is not a global" L" change. \r\nThis program does not generate entries" L" for properties only in New.\r\n\r\n\r\n"; }*/ } else { commonProperties.push_back(begin->first); } begin++; } BREAK_ON_FAILED_HRESULT(hr); } } while (0); return hr; } HRESULT addReplace ( const enum TYPE_OF_CHANGE type, const long locale, const String &object, const String &property, const String &valueOld, const String &valueNew, const HANDLE fileOut ) { LOG_FUNCTION(addReplace); ASSERT( type==REPLACE_W2K_MULTIPLE_VALUE || type==REPLACE_W2K_SINGLE_VALUE ); HRESULT hr=S_OK; do { String entry; entry=String::format ( L"\r\n" L"\r\n" L" addChange\r\n" L" (\r\n" L" 0x%1!x!,\r\n" L" L\"%2\",\r\n" L" L\"%3\",\r\n" L" //%4 \r\n" L" L\"%5\",\r\n" L" //%6 \r\n" L" L\"%7\",\r\n" L" %8\r\n" L" );", locale, //1 object.c_str(), //2 property.c_str(), //3 valueOld.c_str(), //4 escape(valueOld.c_str()).c_str(), //5 valueNew.c_str(), //6 escape(valueNew.c_str()).c_str(), //7 (type==REPLACE_W2K_SINGLE_VALUE) ? //8 L"REPLACE_Old_SINGLE_VALUE": L"REPLACE_Old_MULTIPLE_VALUE" ); AnsiString ansiEntry; String::ConvertResult res=entry.convert(ansiEntry); if(res!=String::CONVERT_SUCCESSFUL) { error=L"Ansi conversion failure"; hr=E_FAIL; break; } hr = FS::Write(fileOut,ansiEntry); } while(0); return hr; } bool findI ( const StringList &list, const String &value ) { LOG_FUNCTION(findI); for ( StringList::const_iterator current=list.begin(),end=list.end(); current!=end; current++ ) { //if(current->icompare(value)==0) if(*current==value) { return true; } } return false; } bool findIPartial ( const StringList &list, const String &value, String &valueFound ) { LOG_FUNCTION(findIPartial); for ( StringList::const_iterator current=list.begin(),end=list.end(); current!=end; current++ ) { if(value.size()<=current->size()) { //if(value.icompare( current->substr(0,value.size()) )==0) if( value == current->substr(0,value.size()) ) { valueFound=*current; return true; } } } return false; } HRESULT dealWithMultipleValues ( const long locale, const String& object, const String& property, const StringList &valuesNew, const StringList &valuesOld, const HANDLE fileOut ) { LOG_FUNCTION(dealWithMultipleValues); StringList::const_iterator bgOld=valuesOld.begin(); StringList::const_iterator endOld=valuesOld.end(); HRESULT hr=S_OK; do { while(bgOld!=endOld) { if (!findI(valuesNew,*bgOld)) { // The value was not found in New // The beginning of the value should be found String beforeComma,valueFound; size_t pos=bgOld->find(L','); if(pos==String::npos || pos==0) { error=String::format ( L"(%1!x!,%2,%3) should have comma after 1st position", locale, object.c_str(), property.c_str() ); hr=E_FAIL; break; } // pos+1 will include the comma beforeComma=bgOld->substr(0,pos+1); if( beforeComma.icompare(L"cn,")==0 && object.icompare(L"domainDNS-Display")==0 && property.icompare(L"attributeDisplayNames")==0 ) { // We are opening this exception since // this is the only value that had its beforeComma // part changed. beforeComma=L"dc,"; } if(!findIPartial(valuesNew,beforeComma,valueFound)) { error=String::format ( L"(%1!x!,%2,%3) Value %4 is not in New", locale, object.c_str(), property.c_str(), beforeComma.c_str() ); hr=E_FAIL; break; } hr=addReplace ( REPLACE_W2K_MULTIPLE_VALUE, locale, object.c_str(), property.c_str(), *bgOld, valueFound, fileOut ); BREAK_ON_FAILED_HRESULT(hr); } bgOld++; } BREAK_ON_FAILED_HRESULT(hr); } while(0); return hr; } // the function bellow is auxiliary in testing // how well csvreader performs its tasks of // reading properties. It dumps csvName to fileOut HRESULT dumpCsv ( const String &csvName, const long *locales, const HANDLE fileOut ) { LOG_FUNCTION(dumpCsv); HRESULT hr=S_OK; do { CSVDSReader csv; hr=csv.read(csvName.c_str(),locales); BREAK_ON_FAILED_HRESULT(hr); const mapOfPositions& pp1=csv.getProperties(); // First we dump all the properties mapOfPositions::iterator begin=pp1.begin(); mapOfPositions::iterator end=pp1.end(); mapOfProperties prop; StringList emptyList; while(begin!=end) { hr=FS::Write(fileOut,begin->first); BREAK_ON_FAILED_HRESULT(hr); hr=FS::Write(fileOut,L","); BREAK_ON_FAILED_HRESULT(hr); prop[begin->first]=emptyList; begin++; } BREAK_ON_FAILED_HRESULT(hr); hr=FS::Write(fileOut,L"\r\n"); BREAK_ON_FAILED_HRESULT(hr); bool flagEOF=false; // Now we will enumerate all csv lines hr=csv.initializeGetNext(); BREAK_ON_FAILED_HRESULT(hr); do { long loc; String obj; hr=csv.getNextObject(loc,obj,prop); BREAK_ON_FAILED_HRESULT(hr); if(hr==S_FALSE) flagEOF=true; if(loc==0) continue; // now we enumerate each Value set from a property mapOfProperties::iterator begin=prop.begin(); mapOfProperties::iterator end=prop.end(); mapOfProperties::iterator last=prop.end(); last--; while(begin!=end) { if(begin->second.size()!=0) { StringList::iterator curValue=begin->second.begin(); StringList::iterator endValue=begin->second.end(); StringList::iterator lastValue=endValue; lastValue--; if( begin->second.size()>1 || begin->second.begin()->find(L',')!=String::npos ) { hr=FS::Write(fileOut,L"\""); BREAK_ON_FAILED_HRESULT(hr); } while(curValue!=endValue) { hr=FS::Write(fileOut,*curValue); BREAK_ON_FAILED_HRESULT(hr); if(curValue!=lastValue) { hr=FS::Write(fileOut,L";"); BREAK_ON_FAILED_HRESULT(hr); } curValue++; } BREAK_ON_FAILED_HRESULT(hr); if( begin->second.size()>1 || begin->second.begin()->find(L',')!=String::npos ) { hr=FS::Write(fileOut,L"\""); BREAK_ON_FAILED_HRESULT(hr); } } if(begin!=last) { hr=FS::Write(fileOut,L","); BREAK_ON_FAILED_HRESULT(hr); } begin++; } BREAK_ON_FAILED_HRESULT(hr); hr=FS::Write(fileOut,L"\r\n"); BREAK_ON_FAILED_HRESULT(hr); } while(!flagEOF); } while(0); return hr; } // Compare the Old and New csv files to check for // differences in their common properties that will generate // REPLACE_Old entries in fileOut. locales has the set of locales // expected to be present in both the csv files. HRESULT generateChanges ( const String &csvOldName, const String &csvNewName, const long *locales, const HANDLE fileOut ) { LOG_FUNCTION(generateChanges); HRESULT hr=S_OK; // bugbug No Longer Necessary // Let's add the new objects in a StringList // to later use findI to skip csv lines with // new objects StringList newNewObjects; for(long t=0;*NEW_WHISTLER_OBJECTS[t]!=0;t++) { newNewObjects.push_back(NEW_WHISTLER_OBJECTS[t]); } do { CSVDSReader csvOld; hr=csvOld.read(csvOldName.c_str(),locales); BREAK_ON_FAILED_HRESULT(hr); CSVDSReader csvNew; hr=csvNew.read(csvNewName.c_str(),locales); BREAK_ON_FAILED_HRESULT(hr); // Now we get the common properties as a StringList const mapOfPositions& pp1=csvOld.getProperties(); const mapOfPositions& pp2=csvNew.getProperties(); StringList commonProperties; // bugbug. Get uncommon too and write them as // global ADD_ALL_CSV_VALUES changes hr=getCommonProperties ( pp1, pp2, commonProperties ); BREAK_ON_FAILED_HRESULT(hr); // 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 propOld,propNew; long locOld,locNew; String objOld,objNew; hr=csvOld.getNextObject(locOld,objOld,propOld); if(objOld==L"remoteStorageServicePoint-Display") { flagEOF=flagEOF; } LOG(locOld); LOG(objOld); BREAK_ON_FAILED_HRESULT(hr); if(hr==S_FALSE) flagEOF=true; // The loop bellow skips csv lines with new objects. do { //bugbug instead of skipping add locale dependent NEW_OBJECT //changes. It will require no parameters since it will use //the latest csv. The loop goes untill the objects are the same //or the new has ended. If the old has ended, clear its object // to go on with the new hr=csvNew.getNextObject(locNew,objNew,propNew); BREAK_ON_FAILED_HRESULT(hr); } while(hr!=S_FALSE && findI(newNewObjects,objNew)); //bugbug if the new has ended BREAK_ON_FAILED_HRESULT(hr); if(hr==S_FALSE) flagEOF=true; if(locNew==0 && locOld==0) continue; // This means blank lines on both csvs. // Blank lines would be common only in the end of // the file, but I don't care for them in the middle as long as they are // in the same number in both the New and Old csvs. // If we have blank lines in only one of the files, the if // bellow will flag it as any other assynchronous result if( (objOld != objNew) || (locOld != locNew) ) { error=String::format ( "(%1,%2!x!) should be the same as (%3,%4!x!).", objOld.c_str(), locOld, objNew.c_str(), locNew ); hr=E_FAIL; break; } // now let's check the differences in the common properties StringList::iterator curCommon=commonProperties.begin(); StringList::iterator endCommon=commonProperties.end(); for(;curCommon!=endCommon;curCommon++) { //bugbug no longer possible /* if (isObjectPropertyInChangeList(objOld,*curCommon,changes) ) { // It is already taken care of by a global change continue; }*/ const StringList &valuesOld=propOld[*curCommon]; const StringList &valuesNew=propNew[*curCommon]; long Oldlen=valuesOld.size(); long Newlen=valuesNew.size(); if (Oldlen!=Newlen) { error=String::format ( L"(%1!x!,%2,%3) should have the same Old(%4!d!) " L"and New(%5!d!) number of values", locOld, objOld.c_str(), curCommon->c_str(), Oldlen, Newlen ); hr=E_FAIL; break; } if(Oldlen==1) // and, therefore, Newlen==1 { if( valuesNew.begin()->icompare(*valuesOld.begin()) != 0 ) { hr=addReplace ( REPLACE_W2K_SINGLE_VALUE, locOld, objOld.c_str(), curCommon->c_str(), *valuesOld.begin(), *valuesNew.begin(), fileOut ); BREAK_ON_FAILED_HRESULT(hr); } } else if(Oldlen > 1) { hr=dealWithMultipleValues ( locOld, objOld.c_str(), curCommon->c_str(), valuesNew, valuesOld, fileOut ); BREAK_ON_FAILED_HRESULT(hr); } // else both are 0 and replacements are not needed } BREAK_ON_FAILED_HRESULT(hr); } while(!flagEOF); BREAK_ON_FAILED_HRESULT(hr); } while(0); return hr; } void chk() { HRESULT hr=S_OK; HANDLE file=NULL; String errors; do { hr=FS::CreateFile("c:\\public\\dcpromoOld.csv", file, GENERIC_READ); if(FAILED(hr)) break; int countLine=0; bool flagEof=false; while(!flagEof) { String line; hr=ReadLine(file,line); if(hr==EOF_HRESULT) { hr=S_OK; flagEof=true; } if(line.empty()) continue; if(IsNLSDefinedString(COMPARE_STRING,0,NULL,line.c_str(),line.length())==FALSE) { errors+=String::format(L"line:%1!d! ", countLine+1); wchar_t str[2]; str[1]=0; for(int countColumn=0;countColumn void printGUID(const GUID& g) { printf("{%x,%x,%x,{%x,%x,%x,%x,%x,%x,%x,%x}}\n",g.Data1,g.Data2,g.Data3, g.Data4[0],g.Data4[1],g.Data4[2],g.Data4[3],g.Data4[4],g.Data4[5], g.Data4[6],g.Data4[7]); wchar_t *str; if(UuidToString((UUID*)&g,&str)==RPC_S_OK) { wprintf(L" %s\n\n",str); RpcStringFree(&str); } } void __cdecl main( void ) { GUID g1={0,0,1,0,1,2,3,4,5,6,7}; printGUID(g1); if(UuidFromString(L"baddb31b-b428-4103-ae78-3bba5541a20d",&g1)==RPC_S_OK) { printGUID(g1); } else { printf("UUID string is not valid"); } } /* void __cdecl main(int argc,char *argv[]) { if(argc!=7) { printf("\nThis program generates a new set of changes to be " "used in dcpromo.lib by comparing the new and previous" " csv files. Usage:\n\n\"preBuild.exe GUID oldDcpromo " "newDcpromo old409 new409 targetFolder\"\n\n" "GUID is the identifier for this set of changes, for example:\n" "{0x4444C516,0xF43A,0x4c12,0x9C,0x4B,0xB5,0xC0,0x64,0x94," "0x1D,0x61}\n\n" "oldDcpromo is the previous dcpromo.csv\n" "newDcpromo is the new dcpromo.csv\n" "old409 is the previous 409.csv\n" "new409 is the new 409.csv\n\n" "targetFolder is the sources file for dcpromo.lib," " where guids.cpp, and " "changes.NNN.cpp will be generated and where the sources " "file for the display specifier upgrade library is. " "An entry like: \"changes.NNN.cpp \\\" will be added " "at the end targetFolder\\sources.\n\n"); } else printf(argv[1]); } */ /* int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, //hPrevInstance LPSTR, //lpszCmdLine int //nCmdShow ) { LOG_FUNCTION(WinMain); chk(); return 0; hResourceModuleHandle=hInstance; int argv; LPWSTR *argc=CommandLineToArgvW(GetCommandLine(),&argv); String usage; usage = L"Usage: OldRepl folder outputFile\r\n" L"Example: obj\\i386\\OldRepl .\\ ..\\setReplacements.cpp\r\n" L"folder must have four files: \r\n" L" win2k.dcpromo.csv\r\n" L" whistler.dcpromo.csv\r\n" L" win2k.409.csv\r\n" L" whistler.409.csv\r\n" L" Don't forget to checkout the output file if\r\n" L" it is under source control.\r\n"; if(argv!=3) { MessageBox(NULL,usage.c_str(),L"Two arguments required.",MB_OK); return 0; } String path = FS::NormalizePath(argc[1]); String outFileName = FS::NormalizePath(argc[2]); String dcpromoNew = path+L"whistler.dcpromo.csv"; String dcpromoOld = path+L"win2k.dcpromo.csv"; String csv409New = path+L"whistler.409.csv"; String csv409Old = path+L"win2k.409.csv"; if( !FS::FileExists(dcpromoNew) || !FS::FileExists(dcpromoOld) || !FS::FileExists(csv409New) || !FS::FileExists(csv409Old) ) { MessageBox(NULL,usage.c_str(),L"Some file doesn't exist",MB_OK); return 0; } HANDLE outFile=INVALID_HANDLE_VALUE; HRESULT hr=S_OK; hr=FS::CreateFile( outFileName, outFile, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS); if FAILED(hr) { MessageBox(NULL,L"Problems to create output file",L"Error",MB_OK); LOG_HRESULT(hr); return hr; } do { AnsiString header; header = "// This file is generated by OldRepl.exe\r\n" "// Copyright (c) 2001 Microsoft Corporation\r\n" "// Jun 2001 lucios\r\n" "\r\n" "#include \"headers.hxx\"\r\n" "#include \"constants.hpp\"\r\n" "\r\n" "void setReplacementChanges()\r\n" "{"; hr = FS::Write(outFile,header); BREAK_ON_FAILED_HRESULT(hr); hr=generateChanges ( dcpromoOld, dcpromoNew, LOCALEIDS, outFile ); BREAK_ON_FAILED_HRESULT(hr); hr=generateChanges ( csv409Old, csv409New, LOCALE409, outFile ); BREAK_ON_FAILED_HRESULT(hr); AnsiString tail="\r\n}\r\n"; hr = FS::Write(outFile,tail); BREAK_ON_FAILED_HRESULT(hr); //hr=dumpCsv(dcpromoOld,LOCALEIDS,outFile); //hr=dumpCsv(csv409Old,LOCALE409,outFile); //BREAK_ON_FAILED_HRESULT(hr); } while(0); CloseHandle(outFile); if(FAILED(hr)) { MessageBox(NULL,error.c_str(),L"Error",MB_OK); } else { MessageBox(NULL,L"Generation Successful",L"Success",MB_OK); } return 1; } */