/////////////////////////////////////////////////////// // RADEventsXML::ConstructEventNode // // Creates an XMLEvent node from a RADEvent object // // An example XML node as text: // <Event num="0057" // starttime="0000020010826175602000" endtime="0000020010826175827000" // maxtime="0000020010826175702000" // sum="10941.0" maxvalue="84" // starttimedisplay="2001.08.26 - 17:56:02" // endtimedisplay="2001.08.26 - 17:58:27" // maxtimedisplay="2001.08.26 - 17:57:02" // etype="Channel" // stationname="GRAND 2" /> // // Note: the text attribute values are created from the strings // on the RADEvent object. // // Input: // pEvent - the RADEvent instance // // Returns: // IXMLDOMElement: the constructed Event node, // or a NULL pointer if processing failed. // /////////////////////////////////////////////////////// IXMLDOMElement* RADEventsXML::ConstructEventNode(RADEvent* pEvent) { IXMLDOMElement *pEventElement = NULL; _variant_t var1; _bstr_t bstr1; HRESULT hr; IXMLDOMAttribute *pAttNode=NULL; IXMLDOMNode *pIXMLDOMNode=NULL; IXMLDOMNamedNodeMap* pAttMap = NULL; int j; // construct <Event> bstr1 = "Event"; HRCALL(m_pXMLDom->createElement(bstr1,&pEventElement),"create <Event> "); HRCALL(pEventElement->get_attributes(&pAttMap), "get_attributes: "); for (j = 0; j < eRADAttMax; j++) { var1 = pEvent->values[j]; HRCALL(m_pXMLDom->createAttribute(atts[j], &pAttNode), "create attribute"); HRCALL(pAttNode->put_nodeValue(var1), "node value"); HRCALL(pAttMap->setNamedItem(pAttNode, &pIXMLDOMNode), "set named item"); if (pIXMLDOMNode) pIXMLDOMNode->Release(); } clean: if (pAttMap) pAttMap->Release(); if (pAttNode) pAttNode->Release(); return pEventElement; }
/////////////////////////////////////////////////////// // RADEventsXML::XMLToEvent // // Populates a RADEvent object with string and typed values // from the XML Event node attributes. The RADEvent class declares // the string-to-type conversion operations, per field. The XML node // attribute values are placed on the RADEvent as strings, without // modification from the XML. // // Input: // pEvent - the RADEvent instance // /////////////////////////////////////////////////////// RADEvent* RADEventsXML::XMLToEvent(IXMLDOMNode* pEvent) { HRESULT hr; RADEvent* p = NULL; IXMLDOMNode *pAtt=NULL; IXMLDOMNamedNodeMap* pat = NULL; long l; int al; HRCALL(pEvent->get_attributes(&pat), "get_attributes: "); HRCALL(pat->get_length(&l), "get_length: "); ASSERT(l <= (int)eRADAttMax); p = new RADEvent(); for (al = 0; al < l; al++) { HRCALL(pat->getNamedItem(atts[al], &pAtt), "gni"); if (pAtt) { VARIANT varValue; ::VariantInit(&varValue); pAtt->get_nodeValue(&varValue); p->SetREValue((RADEventField)al, varValue.bstrVal); ::VariantClear(&varValue); pAtt->Release(); } } clean: if (pat) pat->Release(); return p; }
// Helper function to create a DOM instance: MSXML2::IXMLDOMDocument * DomFromCOM() { HRESULT hr; MSXML2::IXMLDOMDocument *pxmldoc = NULL; HRCALL( CoCreateInstance(__uuidof(DOMDocument), NULL, CLSCTX_INPROC_SERVER, __uuidof(MSXML2::IXMLDOMDocument), (void**)&pxmldoc), "Create a new DOMDocument"); HRCALL( pxmldoc->put_async(VARIANT_FALSE), "should never fail"); HRCALL( pxmldoc->put_validateOnParse(VARIANT_FALSE), "should never fail"); HRCALL( pxmldoc->put_resolveExternals(VARIANT_FALSE), "should never fail"); return pxmldoc; clean: if (pxmldoc) { pxmldoc->Release(); } return NULL; }
/////////////////////////////////////////////////////// // ReportParseError // // Utility debui error reporting function. Inoperative in release. // // Input: // pDom - document being parsed // desc - descriptive string for error reporting // /////////////////////////////////////////////////////// void ReportParseError(IXMLDOMDocument *pDom, char *desc) { IXMLDOMParseError *pXMLErr=NULL; BSTR bstrReason = NULL; HRESULT hr; HRCALL(pDom->get_parseError(&pXMLErr), "dom->get_parseError: "); HRCALL(pXMLErr->get_reason(&bstrReason), "parseError->get_reason: "); dprintf("%s %S\n",desc, bstrReason); clean: if (pXMLErr) pXMLErr->Release(); if (bstrReason) SysFreeString(bstrReason); }
/////////////////////////////////////////////////////// // RADEventsXML::AddWhiteSpaceToNode // // Appends a text node, with variable whitespace content, to // the pNode parameter. Used for pleasing decoration of text-based // XML external output, for readability. // // Input/Output: // bstrWs - the whitespace text to append to the node, as a BSTR // pNode - the XML Node to decorate // /////////////////////////////////////////////////////// void RADEventsXML::AddWhiteSpaceToNode( BSTR bstrWs, IXMLDOMNode *pNode) { HRESULT hr; IXMLDOMText *pws=NULL; IXMLDOMNode *pBuf=NULL; HRCALL(this->m_pXMLDom->createTextNode(bstrWs,&pws), " "); HRCALL(pNode->appendChild(pws,&pBuf)," "); clean: if (pws) pws->Release(); pws=NULL; if (pBuf) pBuf->Release(); pBuf=NULL; }
/////////////////////////////////////////////////////// // RADEventsXML::ConstructEventParentNodeTree // // Creates an XMLEvent node for the root of the XML document. // The root node is named "IR", // the Events container node is a child of "IR": // <?xml version="1.0" ?> // <IR> // <Events> // </Events> // <IR> // // // Returns: // IXMLDOMElement: the constructed IR/Eevents node, // or a NULL pointer if processing failed. // /////////////////////////////////////////////////////// IXMLDOMElement* RADEventsXML::ConstructEventParentNodeTree() { IXMLDOMNode *pIXMLDOMNode = NULL; IXMLDOMElement *pIR = NULL; IXMLDOMElement *pEvents = NULL; IXMLDOMProcessingInstruction *pi=NULL; _bstr_t bstr1; _bstr_t bstr2; HRESULT hr; // Create a processing instruction element. <?xml version="1.0" ?> bstr1 = "xml"; bstr2 = "version='1.0'"; HRCALL(m_pXMLDom->createProcessingInstruction( bstr1,bstr2, &pi), "createProcessingInstruction:"); m_pXMLDom->appendChild(pi, &pIXMLDOMNode); // put it first // construct <IR><Events></Events></IR> bstr1 = "Events"; HRCALL(m_pXMLDom->createElement(bstr1,&pEvents),"create <Events> "); bstr1 = "IR"; HRCALL(m_pXMLDom->createElement(bstr1,&pIR),"create <IR>"); HRCALL(pIR->appendChild(pEvents, &pIXMLDOMNode), ""); AddWhiteSpaceToNode(bstr_wsnt, pIR); m_pXMLDom->appendChild(pIR, &pIXMLDOMNode); // attach to DOM clean: if (pi) pi->Release(); if (pIR) pIR->Release(); return pEvents; }
/////////////////////////////////////////////////////// // RADEventsXML::ConstructXMLDoc // // Constructs the XML document from the RADEventList 'rel'. // Note: the current XML document is replaced, not updated, // by this operation. // // Input/Output: // rel - the RADEventsList instance that is converted to an // XML document. // /////////////////////////////////////////////////////// bool RADEventsXML::ConstructXMLDoc(RADEventsList& rel) { _bstr_t bstr; HRESULT hr; IXMLDOMNode *pColNode = NULL; IXMLDOMNode *pIXMLDOMNode = NULL; if (this->m_pXMLDom != NULL) { if (this->m_pIRNode == NULL) // might need to create the entire tree, the file didn't exist // or might need to just create the tree down to the Events level { this->m_pIRNode = ConstructEventParentNodeTree(); } if (this->m_pIRNode == NULL ) return false; // attempt to create IR/Events has failed bstr = m_xcolpath; HRCALL(m_pXMLDom->selectSingleNode(bstr, &pColNode), "selectSingleNode"); if (pColNode == NULL) { pColNode = ConstructColumnsNode(); if (pColNode) { HRCALL(m_pIRNode->appendChild(pColNode,&pIXMLDOMNode), ""); AddWhiteSpaceToNode(bstr_wsnt, m_pIRNode); } else // if (pColNode == NULL) return false; // forced re-selection of the newly constructed node tree has failed } } else return false; // no DOM means punt clean: return ProcessEvents(rel, false); // build the event list on the IR/Events tree }
/////////////////////////////////////////////////////// // RADEventsXML::Populate // // Update the XML document on this object from the external // persistent representation (a file). Then, // for each RADEvent object extracted from the current XML document, // insert it on the RADEventsList. Note: the list is not // emptied or cleared prior to processing. // // Input/Output: // rel - the RADEventsList instance that is populated from // an XML document. // /////////////////////////////////////////////////////// void RADEventsXML::Populate(RADEventsList& rel) { /* using the path and file name, find the XML file, open it in memory, get the event tree from it, extract the n events on the event tree, populate the local data structure with thr n events */ HRESULT hr; IXMLDOMParseError * pObjError = NULL; VARIANT_BOOL status; _variant_t vSrc; _bstr_t bstr; _bstr_t filepath(m_fullpath); DomFromCOM(); if (!m_pXMLDom) goto clean; vSrc = m_fullpath; hr = m_pXMLDom->load(vSrc, &status); if(status!=VARIANT_TRUE) { hr = m_pXMLDom->get_parseError(&pObjError); VARIANT varValue; ::VariantInit(&varValue); hr = pObjError->get_reason( &(varValue.bstrVal)); dprintf("Failed to load DOM from %s. %S\n",m_fullpath, varValue.bstrVal); ::VariantClear(&varValue); goto clean; } if (m_pIRNode) m_pIRNode->Release(); m_pIRNode = NULL; bstr = m_xirevspath; HRCALL(m_pXMLDom->selectSingleNode(bstr, &m_pIRNode), "selectSingleNode"); if (m_pIRNode) { ProcessEvents(rel, true); } clean: if (pObjError) pObjError->Release(); }
/////////////////////////////////////////////////////// // DomFromCOM // // Helper function that creates an empty DOM object. // Every well-defined XML document is based on a DOM root object // // Note: This class uses the MSXML 3.0 Document Object Model. // // Returns: // new empty IXMLDOMDocument*, (or NULL on failure) // /////////////////////////////////////////////////////// void RADEventsXML::DomFromCOM() { HRESULT hr; if (m_pXMLDom) return; // explicitly use the MSXML 3.0 API! Fails if it is not installed HRCALL( CoCreateInstance(__uuidof(DOMDocument30), NULL, CLSCTX_INPROC_SERVER, __uuidof(IXMLDOMDocument), (void**)&m_pXMLDom), "Create a new DOMDocument"); // no validation ... ignore externals ... synchronous evaluation HRCALL( m_pXMLDom->put_async(VARIANT_FALSE), "should never fail"); HRCALL( m_pXMLDom->put_validateOnParse(VARIANT_FALSE), "should never fail"); HRCALL( m_pXMLDom->put_resolveExternals(VARIANT_FALSE), "should never fail"); clean: ; }
/////////////////////////////////////////////////////// // RADEventsXML::ProcessEvents // // Method to process a list of events, either transforming XML // into RADEvents, or RADEvents into XML event nodes. // Invoked by the Populate and Persist methods. // // When transforming the RADEvent objects on the list 'rel' into // XML Event nodes, a new XML Event node is created, and appended // to the XML Events node of the XML document. // // When transforming the XML Events node with XML Event nodes, each // XML Event node is transformed to a RADEvent object, and the RADEvent // object is appended to the RADEventsList 'rel'. // // Input/Output: // rel - the RADEventsList instance // bExtract - processing toggle: // When true, run through the XML event nodes, creating // RADEvent objects on 'rel'. // When false, run through the RADEvent objects, creating // XML event nodes on the XML document. // /////////////////////////////////////////////////////// bool RADEventsXML::ProcessEvents(RADEventsList& rel, bool bExtract) { // if bExtract, we want to read the XML events and populate the list of event objects // first: get count of events nodes // second: // for each event node // get the node // create a RADEvent, using the node attributes to populate it // insert the RADEvent object into the RADEventsList 'rel' // end // else, not bExtract, we want to transform the list of RADEvent objects into an XML document // for each RADEvent on the RADEventsList 'rel, // create a new XML Event Node, using each stirng value as an attribute value // append the XML Event node to the <IR/Events> node // end HRESULT hr; _bstr_t xbstr = m_xirevsevpath; if (bExtract) // converting from XML <Event> to RADEvent { IXMLDOMNodeList* pXMLDomNodeList = NULL; HRCALL(m_pXMLDom->selectNodes(xbstr, &pXMLDomNodeList), "selectNodes"); if (pXMLDomNodeList) { long count = 0; HRCALL(pXMLDomNodeList->get_length(&count), "get_length"); IXMLDOMNode *pEventNode=NULL; for (long i=0; i<count; i++) { HRCALL(pXMLDomNodeList->get_item(i, &pEventNode), "get_item: "); if (bDebug) { BSTR dbg1str; BSTR dbg2str; HRCALL(pEventNode->get_nodeName(&dbg1str), "get_nodeName: "); dprintf("Node (%d), <%S>:\n",i, static_cast<wchar_t*>(dbg1str)); HRCALL(pEventNode->get_xml(&dbg2str), "get_xml: "); dprintf("\t%S\n", static_cast<wchar_t*>(dbg2str)); } RADEvent* p = XMLToEvent(pEventNode); rel.AddToEnd(p); if (bDebug) { dprintf(p->Image()); } if (pEventNode) pEventNode->Release(); } pXMLDomNodeList->Release(); } else { ReportParseError(m_pXMLDom, "Error while calling ProcessEvents/selectNodes "); } } else // converting from RADEvent to XML <Event> { IXMLDOMElement * pE; IXMLDOMNode *pIXMLDOMNode = NULL; long i = 0; POSITION pos = rel.GetHeadPosition(); while( pos != NULL ) { RADEvent* p = (RADEvent*)rel.GetNext( pos ); pE = ConstructEventNode(p); if (pE) { HRCALL(m_pIRNode->appendChild(pE,&pIXMLDOMNode), ""); AddWhiteSpaceToNode(bstr_wsnt, m_pIRNode); i++; } } } clean: if (FAILED(hr)) return false; else return true; }
long findControllerInfoXML(fwi::OHCI1394_DEV_INFO * devInfo) { MSXML2::IXMLDOMNodeList *pNodes=NULL; MSXML2::IXMLDOMNode *pNode=NULL; static VARIANT_BOOL status; static VARIANT var; BSTR bstr = NULL; HRESULT hr; long num_controllers; long num_attributes; BOOL bVendorMatch = FALSE; BOOL bDeviceMatch = FALSE; long lMinutes = 0; MSXML2::IXMLDOMElementPtr pXMLDocElement = NULL; MSXML2::IXMLDOMNodeListPtr pXMLDomNodeList = NULL; VariantInit(&var); // the URL below has a server-side redirect to the actual xml file in the svn repo var = VariantString(L"http://www.tctechnologies.tc/appdata/ohci1394db.xml"); // reload online file if cached data is stale lMinutes = getDBCacheAge(); if ( (lMinutes < 0) || (lMinutes > 10) ) { if (gpXMLDom) gpXMLDom->Release(); gpXMLDom = DomFromCOM(); if (!gpXMLDom) return 1; HRCALL(gpXMLDom->load(var, &status), "dom->load(): "); if (status!=VARIANT_TRUE) { if (&var) VariantClear(&var); return FWI_ERROR_FILE_NOT_FOUND; } else { GetLocalTime(&gLastLoadTime); } } gpXMLDom->get_documentElement(&pXMLDocElement); pXMLDocElement->selectNodes(TEXT("//controller"), &pXMLDomNodeList); pXMLDomNodeList->get_length(&num_controllers); for (long n=0; n<num_controllers; n++) { TCHAR buf[32]; StringCchPrintf( buf, 20, TEXT("//controller[%i]/*"), n); // Query the node-set. HRCALL(gpXMLDom->selectNodes(buf, &pNodes), "selectNodes "); if (!pNodes) { ReportParseError(gpXMLDom, "Error while calling selectNodes "); } else { HRCALL(pNodes->get_length(&num_attributes), "get_length: "); for (long i=0; i<num_attributes; i++) { if (pNode) pNode->Release(); HRCALL(pNodes->get_item(i, &pNode), "get_item: "); if (bstr) SysFreeString(bstr); HRCALL(pNode->get_nodeName(&bstr), "get_nodeName: "); if (_tcsicmp((TCHAR*)bstr,TEXT("vendorid"))==0) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); if (_tcsicmp((TCHAR*)nodeTextStr, devInfo->vendorId)==0) { bVendorMatch = TRUE; } SysFreeString(nodeTextStr); } else if (_tcsicmp((TCHAR*)bstr,TEXT("deviceid"))==0) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); if (_tcsicmp((TCHAR*)nodeTextStr, devInfo->deviceId)==0) { bDeviceMatch = TRUE; } SysFreeString(nodeTextStr); } if (bVendorMatch) { if ( (_tcsicmp((TCHAR*)bstr,TEXT("vendorname"))==0) && (_tcsicmp(TEXT("Unknown"),&devInfo->vendorName[0]))==0 ) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); _tcscpy_s(&devInfo->vendorName[0], VENDOR_SIZE, nodeTextStr); SysFreeString(nodeTextStr); } } if (bVendorMatch && bDeviceMatch) { devInfo->bFound = TRUE; if (_tcsicmp((TCHAR*)bstr,TEXT("chipset"))==0) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); _tcscpy_s(&devInfo->chipset[0], CHIPSET_SIZE, nodeTextStr); SysFreeString(nodeTextStr); } else if (_tcsicmp((TCHAR*)bstr,TEXT("maxtx"))==0) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); _tcscpy_s(&devInfo->maxTx[0], NUM_STR_SIZE, nodeTextStr); SysFreeString(nodeTextStr); } else if (_tcsicmp((TCHAR*)bstr,TEXT("maxrx"))==0) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); _tcscpy_s(&devInfo->maxRx[0], NUM_STR_SIZE, nodeTextStr); SysFreeString(nodeTextStr); } else if (_tcsicmp((TCHAR*)bstr,TEXT("maxspeed"))==0) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); swscanf_s(nodeTextStr, TEXT("%04d"), &devInfo->maxspeed); SysFreeString(nodeTextStr); } else if (_tcsicmp((TCHAR*)bstr,TEXT("notes"))==0) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); _tcscpy_s(&devInfo->notes[0], NOTES_SIZE, nodeTextStr); SysFreeString(nodeTextStr); } else if (_tcsicmp((TCHAR*)bstr,TEXT("support"))==0) { BSTR nodeTextStr; HRCALL(pNode->get_text(&nodeTextStr), "get_text: "); swscanf_s(nodeTextStr, TEXT("%04x"), &devInfo->support); devInfo->bValid = true; SysFreeString(nodeTextStr); if (&var) VariantClear(&var); if (bstr) SysFreeString(bstr); if (pNodes) pNodes->Release(); if (pNode) pNode->Release(); return FWI_NO_ERROR; } } } } } clean: if (&var) VariantClear(&var); if (bstr) SysFreeString(bstr); if (pNodes) pNodes->Release(); if (pNode) pNode->Release(); return FWI_ERROR_END_OF_FILE; }