1 if (Garmin == undefined) var Garmin = {}; 2 /** 3 * Copyright � 2007 Garmin Ltd. or its subsidiaries. 4 * 5 * Licensed under the Apache License, Version 2.0 (the 'License') 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an 'AS IS' BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * @fileoverview Garmin.Device A place-holder for Garmin device information. <br/> 18 * Source: 19 * <a href="http://developer.garmin.com/web/communicator-api/garmin/device/GarminDevice.js">Hosted Distribution</a> 20 * <a href="https://svn.garmindeveloper.com/web/trunk/communicator/communicator-api/src/main/webapp/garmin/device/GarminDevice.js">Source Control</a><br/> 21 * 22 * @author Richard Easterling developer.connect.at.garmin.com 23 * @version 1.0 24 */ 25 26 /** Plugin-specific utility functions. 27 * 28 * @class Garmin.PluginUtils 29 * @constructor 30 */ 31 Garmin.PluginUtils = function(){}; //just here for jsdoc 32 Garmin.PluginUtils = { 33 //Garmin.PluginUtils.prototype = { 34 35 initialize: function() { 36 }, 37 38 /** Parse device xml string into device objects. 39 * 40 * Each device object contains the following: 41 * 1) device display name 42 * 2) device number 43 * 3) device XML as an XML document 44 * 45 * This function returns an array of the described Device objects. 46 * 47 * @param garminPlugin - the GarminDevicePlugin object having access to the device XML data. 48 * @param getDetailedDeviceData - boolean indicating if you want to get the entire device XML 49 * as an XML document (rather than the few essentials) 50 */ 51 parseDeviceXml: function(garminPlugin, getDetailedDeviceData) { 52 var xmlDevicesString = garminPlugin.getDevicesXml(); 53 var xmlDevicesDoc = Garmin.XmlConverter.toDocument(xmlDevicesString); 54 55 var deviceList = xmlDevicesDoc.getElementsByTagName("Device"); 56 var devices = new Array(); 57 var numDevices = deviceList.length; 58 59 for( var i=0; i < numDevices; i++ ) { 60 var displayName = deviceList[i].getAttribute("DisplayName"); 61 var deviceNumber = parseInt( deviceList[i].getAttribute("Number") ); 62 var deviceDescriptionDoc = null; 63 if (getDetailedDeviceData) { 64 var deviceDescriptionXml = garminPlugin.getDeviceDescriptionXml(deviceNumber); 65 deviceDescriptionDoc = Garmin.XmlConverter.toDocument(deviceDescriptionXml); 66 } 67 devices.push(Garmin.PluginUtils._createDeviceFromXml(displayName, deviceNumber, deviceDescriptionDoc)); 68 } 69 return devices; 70 }, 71 72 /** Create a Garmin.Device instance for each connected device found. 73 * @private 74 */ 75 _createDeviceFromXml: function(displayName, deviceNumber, deviceDescriptionDoc) { 76 var device = new Garmin.Device(displayName, deviceNumber); 77 78 if(deviceDescriptionDoc) { 79 var partNumber = deviceDescriptionDoc.getElementsByTagName("PartNumber")[0].childNodes[0].nodeValue; 80 var softwareVersion = deviceDescriptionDoc.getElementsByTagName("SoftwareVersion")[0].childNodes[0].nodeValue; 81 var description = deviceDescriptionDoc.getElementsByTagName("Description")[0].childNodes[0].nodeValue; 82 var id = deviceDescriptionDoc.getElementsByTagName("Id")[0].childNodes[0].nodeValue; 83 84 device.setPartNumber(partNumber); 85 device.setSoftwareVersion(softwareVersion); 86 device.setDescription(description); 87 device.setId(id); 88 89 // var dataTypeList = deviceDescriptionDoc.getElementsByTagName("DataType"); 90 var dataTypeList = deviceDescriptionDoc.getElementsByTagName("MassStorageMode")[0].getElementsByTagName("DataType"); 91 var numOfDataTypes = dataTypeList.length; 92 93 for ( var j = 0; j < numOfDataTypes; j++ ) { 94 var dataName = dataTypeList[j].getElementsByTagName("Name")[0].childNodes[0].nodeValue; 95 var dataExt = dataTypeList[j].getElementsByTagName("FileExtension")[0].childNodes[0].nodeValue; 96 97 var dataType = new Garmin.DeviceDataType(dataName, dataExt); 98 var fileList = dataTypeList[j].getElementsByTagName("File"); 99 100 var numOfFiles = fileList.length; 101 102 for ( var k = 0; k < numOfFiles; k++ ) { 103 // Path is an optional element in the schema 104 var pathList = fileList[k].getElementsByTagName("Path"); 105 var transferDir = fileList[k].getElementsByTagName("TransferDirection")[0].childNodes[0].nodeValue; 106 107 if ((transferDir == Garmin.DeviceControl.TRANSFER_DIRECTIONS.read)) { 108 dataType.setReadAccess(true); 109 110 if (pathList.length > 0) { 111 var filePath = pathList[0].childNodes[0].nodeValue; 112 dataType.setReadFilePath(filePath); 113 } 114 } else if ((transferDir == Garmin.DeviceControl.TRANSFER_DIRECTIONS.write)) { 115 dataType.setWriteAccess(true); 116 117 if (pathList.length > 0) { 118 var filePath = pathList[0].childNodes[0].nodeValue; 119 dataType.setWriteFilePath(filePath); 120 } 121 } else if ((transferDir == Garmin.DeviceControl.TRANSFER_DIRECTIONS.both)) { 122 dataType.setReadAccess(true); 123 dataType.setWriteAccess(true); 124 125 if (pathList.length > 0) { 126 var filePath = pathList[0].childNodes[0].nodeValue; 127 dataType.setReadFilePath(filePath); 128 dataType.setWriteFilePath(filePath); 129 } 130 } 131 132 // Deprecated! Need to be removed at some point. 133 if( pathList.length > 0) { 134 var filePath = pathList[0].childNodes[0].nodeValue; 135 dataType.setFilePath(filePath); 136 } 137 138 // Identifier is optional 139 var identifierList = fileList[k].getElementsByTagName("Identifier"); 140 if( identifierList.length > 0) { 141 var identifier = identifierList[0].childNodes[0].nodeValue; 142 dataType.setIdentifier(identifier); 143 } 144 } 145 device.addDeviceDataType(dataType); 146 } 147 } 148 return device; 149 }, 150 151 /** Is this a device XML error message. 152 * @param {String} xml string or Error instance with embedded xml 153 * @type Boolean 154 * @return true if error is device-generared error 155 */ 156 isDeviceErrorXml: function(error) { 157 var msg = (typeof(error)=="string") ? error : error.name + ": " + error.message; 158 return ( (msg.indexOf("<ErrorReport") > 0) ); 159 }, 160 161 /** Best effort to convert XML error message to a String. 162 * @param {String} xml string or Error instance with embedded xml 163 * @type String 164 * @return Human readable interpretation of XML message 165 */ 166 getDeviceErrorMessage: function(error) { 167 var msg = (typeof(error)=="string") ? error : error.name + ": " + error.message; 168 var startPos = msg.indexOf("<ErrorReport"); 169 if (startPos>0) { //strip off any text surrounding the xml 170 var endPos = msg.indexOf("</ErrorReport>") + "</ErrorReport>".length; 171 msg = msg.substring(startPos, endPos); 172 } 173 var xmlDoc = Garmin.XmlConverter.toDocument(msg); 174 var errorMessage = Garmin.PluginUtils._getElementValue(xmlDoc, "Extra"); 175 var sourceFileName = Garmin.PluginUtils._getElementValue(xmlDoc, "SourceFileName"); 176 var sourceFileLine = Garmin.PluginUtils._getElementValue(xmlDoc, "SourceFileLine"); 177 var msg = ""; 178 if (errorMessage) { 179 msg = errorMessage; 180 } else { // gota show something :-( 181 msg = "Plugin error: "; 182 if (sourceFileName) 183 msg += "source: "+sourceFileName; 184 if (sourceFileLine) 185 msg += ", line: "+sourceFileLine; 186 } 187 return msg; 188 }, 189 190 /** Get the value of a document element 191 * @param doc - the document that the element is contained in 192 * @param elementName - the name of the element to get the value from 193 * @return the value of the element identified by elementName 194 */ 195 _getElementValue: function(doc, elementName) { 196 var elementNameNodes = doc.getElementsByTagName(elementName); 197 var value = (elementNameNodes && elementNameNodes.length>0) ? elementNameNodes[0].childNodes[0].nodeValue : null; 198 return value; 199 } 200 }; 201 202 203 /** GPI XML generation utility. 204 * 205 * @class Garmin.PluginUtils 206 * @constructor 207 **/ 208 Garmin.GpiUtil = function(){}; 209 Garmin.GpiUtil = { 210 211 /** Build a single DeviceDownload XML for multiple file downloads. 212 * 213 * @param descriptionArray - Even sized array with matching source and destination pairs. 214 * @param regionId - Optional parameter designating RegionId attribute of File. For now, this single 215 * regionId will be applied to all files in the descriptionArray if provided at all. 216 * 217 */ 218 buildMultipleDeviceDownloadsXML: function(descriptionArray) { 219 if(descriptionArray.length % 2 != 0) { 220 throw new Error("buildMultipleDeviceDownloadsXML expects even sized array with matching source and destination pairs"); 221 } 222 var xml = 223 '<?xml version="1.0" encoding="UTF-8"?>\n' + 224 '<DeviceDownload xmlns="http://www.garmin.com/xmlschemas/PluginAPI/v1"\n' + 225 ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' + 226 ' xsi:schemaLocation="http://www.garmin.com/xmlschemas/PluginAPI/v1 http://www.garmin.com/xmlschemas/GarminPluginAPIV1.xsd">\n'; 227 228 for(var i=0;i<descriptionArray.length;i+=2) { 229 var source = descriptionArray[i]; 230 var destination = descriptionArray[i+1]; 231 232 // if(!Garmin.GpiUtil.isDestinationValid(destinationArray[i])) { 233 // throw new Error("Destination filename contains invalid characters: [" + destinationArray[i] + "]"); 234 // } 235 xml += ' <File Source="'+source+'" Destination="'+destination+'" RegionId="46" />\n'; 236 } 237 xml += '</DeviceDownload>'; 238 return xml; 239 }, 240 241 buildDeviceDownloadXML: function(source, destination) { 242 return Garmin.GpiUtil.buildMultipleDeviceDownloadsXML([source, destination]); 243 }, 244 245 isDestinationValid: function(destination) { 246 var splitPath = destination.split("/"); 247 var filename = splitPath[splitPath.length-1]; 248 249 var lengthBefore = filename.length; 250 251 var stringAfter = Garmin.GpiUtil.cleanUpFilename(filename); 252 253 return(lengthBefore == stringAfter.length); 254 }, 255 256 cleanUpFilename: function(filename) { 257 var result = filename; 258 259 var replacement = ""; // see http://www.asciitable.com/ 260 result = result.stripTags(); 261 result = result.replace(/&/, replacement); 262 result = result.replace(/[\x21-\x2F]/g, replacement); // using range "!" through "/" 263 result = result.replace(/[\x5B-\x60]/g, replacement); // using range "[" through "`" 264 result = result.replace(/[\x3A-\x40]/g, replacement); // using range ":" through "@" 265 result = result.strip(); 266 267 return result; 268 } 269 };