Vehicle Spy VSB file Spec
File Specification
Version Specification
Version 0x101
This format is no longer created. Click to see Network ID's
Version 0x102
This format is created by the extractor. Click to see Network ID's
Version 0x103
This format is created using VSpy. Click to see Network ID’s
EDP section
Used by version 0x102 and 0x103. The ExtraDataPtr -1 of each message is a index to the EDP in EDP section. Click to see Network ID's
Version 0x104
This format is created by the Loggers and VSpy Stream to Disk.
NetWork ID
Version 0x101
Version 0x102, 0x103, 0x104
Example
Below is a C++ example of how to open a .vsb file (v102 & v103 & 104) and display the network messages (Ethernet, CANFD, and CAN) with some other useful information You can view the full C++
code or Download the full project from the links provided.
Reading File Specification
bool Messages::Read(char * sFileName){ unsigned long numEDP = 0;
m_pFile = fopen(sFileName, "rb"); if (m_pFile) {
fSead( 0, SEEK_END);
int length = ftell(m_pFile); //identify length of File
fSead( 0, SEEK_SET); char id[6];
if (!fRead((char * )&id, 6) || memcmp(id, "icsbin", 6) != 0) //check for icsbin in the first 6 bytes to identify if it a VSB file
{ printf("Invalid VSB file\n"); return false;
} unsigned int fileversion;
if (!fRead((char *)&fileversion, 4)){ //VSB has 4 versions 101 is no longer used
printf("Read Error\n"); return false; }
else if (fileversion == 0x102)//this is created by the extractor
{
int EDPSize = ReadEDPSelction(); //the extra data section contains extra data which is different for each message type
if (EDPSize == 0) fSead( VSB_HEADERSIZE, SEEK_SET);
unsigned long numofmessages = ((length - (EDPSize + SIZEOFEDPSIZE)) - VSB_HEADERSIZE) / sizeof(icsSpyMessage); //calculate number of messages in file; the plus 4
m_nMessages = numofmessages; // set number of messages in file
if (numofmessages){
if(!ReadMessage(numofmessages, fileversion)){ //read messages
printf("file was not read correctly \n");
return false; } }
else if (fileversion == 0x103)//this is created by VSPY {
ReadEDPSelction(); //read EDP
unsigned long numofmessages = Read103Header(); //read 103 header
m_nMessages = numofmessages; //set number of messages in file
if (numofmessages){
if(!ReadMessage(numofmessages, fileversion)){ //read messages
printf("file was not read correctly \n");
return false; } } }
else if (fileversion == 0x104){//this is created by various hardware and VSPY for logging
if(!Read104()){ // 104 has a very different structure compared to the other file types
printf("file was not read correctly \n");
return false; } } else{
printf("%s is an unsupported VSB version!\n", sFileName);
return false; } fclose(m_pFile); } else {
printf("Could not open %s to read!\n", sFileName); return false;
} return true;}
Reading EDP Section
int Messages::ReadEDPSelction()
{
unsigned long edpsize;
bool bFixTimeStamp = false;
if (fRead((char *)&edpsize, SIZEOFEDPSIZE) && edpsize > 0)//read size of edp section
{
unsigned long tempEDPSize = edpsize;
static const char* EDP_SECTION = "EDP_SECTION";
char obItem [EDPSECTIONSTRINGSIZE];
// check if there's an EDP_SECTION in here
if (fRead(obItem, EDPSECTIONSTRINGSIZE) && tempEDPSize >= EDPSECTIONSTRINGSIZE && strcmp(obItem, EDP_SECTION) == 0)//verify edp section
{
// the following lines of code is a bad idea for large files. but since it is an simple example I wanted to simplify the code normality you would want to use some sort of file stream.
tempEDPSize -= EDPSECTIONSTRINGSIZE;
m_pEDPSection = new char[tempEDPSize];
if (!fRead(m_pEDPSection, tempEDPSize)){ //load edp section into memory
printf("invalid file read\n");
return 0;
}
char * edpPtr = m_pEDPSection;
while (tempEDPSize > 0)//parse edp section
{
int edpLen = *(int*)edpPtr;
m_edps.push_back(std::pair<char*, int>(edpPtr + sizeof(int), edpLen));//each node in this vector pertains to a different message (this will make more sense when you look at Read Message )
tempEDPSize -= sizeof(int);
edpPtr += edpLen +sizeof(edpLen);
tempEDPSize -= edpLen;
}
return edpsize;
}
}
return 0;
}
Reading 0x103 File Info
unsigned long Messages::Read103Header(){ unsigned long theNumOfMsgs;
size_t msgslength, currbuffptr, numalltime, commentlength, origbuffsize;
fRead((char *)&commentlength, 4); //check if there is a comment
if (commentlength > 0)
fSead( (long)commentlength * 2, SEEK_CUR); // skip comment (comment written in wchar_t)
fRead((char *)&msgslength, 4);//size of message section
fRead((char *)&origbuffsize, 4); //original size of buffer
fRead((char *)&currbuffptr, 4); // current buffer postion
fRead((char *)&numalltime, 4); // number of message all time
theNumOfMsgs = msgslength / sizeof(VSBSpyMessage); // number of messages
return theNumOfMsgs;}
Reading 0x102 and 0x103 Messages
bool Messages::ReadMessage(unsigned long theNumOfMsgs, unsigned int fileversion)
{ VSBSpyMessage * pMessageRead = new VSBSpyMessage();
m_pMessages = new icsSpyMessage[theNumOfMsgs]; bool firstMsg = true;
SpyMsgTime timeStampRead; SpyMsgTime FirstMsgTime;
for(unsigned int i = 0; i < theNumOfMsgs; i++){//read one message at a time
if(!fRead((char *)pMessageRead, sizeof(VSBSpyMessage))){//read message
delete pMessageRead; delete m_pMessages; m_pMessages = NULL;
theNumOfMsgs = 0; return false; }
if (firstMsg) {//record the start time of the first message
FirstMsgTime.HardwareTimeStampID = m_pMessages[0].TimeStampHardwareID;
FirstMsgTime.HardwareTime1 = m_pMessages[0].TimeHardware;
FirstMsgTime.HardwareTime2 = m_pMessages[0].TimeHardware2;
FirstMsgTime.SystemTimeStampID = m_pMessages[0].TimeStampSystemID;
FirstMsgTime.SystemTime1 = m_pMessages[0].TimeSystem;
FirstMsgTime.SystemTime2 = m_pMessages[0].TimeSystem2; firstMsg = false; }
VSBMessageToNormal(&m_pMessages[i], pMessageRead);// convert structure
bool clear = true;
if (pMessageRead->ExtraDataPtrEnabled && pMessageRead->iExtraDataPtr) // check for edp section
{
if (pMessageRead->iExtraDataPtr >= 1 && pMessageRead->iExtraDataPtr <= m_edps.size())
{
int iEDPIndex = pMessageRead->iExtraDataPtr - 1;// identify index in the m_edps vector we made in the ReadEDPSelction function
int payloadLength = m_edps[iEDPIndex].second;
m_pMessages[i].pExtraDataPtr = new pExtraDataPtrHandler(); //using pExtraDataPtrHandler to simply make to identify length of edp section
((pExtraDataPtrHandler *)(m_pMessages[i].pExtraDataPtr))->pExtraDataPtr = m_edps[iEDPIndex].first;
((pExtraDataPtrHandler *)(m_pMessages[i].pExtraDataPtr))->length = payloadLength;
clear = false; } } if (clear) {
m_pMessages[i].ColorID = 0; //reset values
m_pMessages[i].pExtraDataPtr = 0; //reset values }
if (fileversion == 0x102)//all 102s implicitly have bit 7 high. since we're converting to 103 we need to force it
m_pMessages[i].TimeStampHardwareID |= 0x80; }
if (!fRead((char *)&timeStampRead, sizeof(timeStampRead))) //check if start logging time was recorded
timeStampRead = FirstMsgTime; // if start logging time was not record simply set it to first message time
m_startTimeStamp = timeStampRead; delete pMessageRead; return true;}
Reading 0x104
bool Messages::Read104() // 104 don't have a edp section they instead put the extra data after that message
{
unsigned long EDPLength = 0, Edpsize = 0, numOfMessages = 0;
bool firstMsg = true;
SpyMsgTime timeStampRead;
SpyMsgTime FirstMsgTime;
VSBSpyMessage *pMessage = new VSBSpyMessage();
while (fRead((char *)pMessage, sizeof(VSBSpyMessage))) // read messages to identify number of message and edp size
{
numOfMessages++;
if (pMessage->ExtraDataPtrEnabled && pMessage->iExtraDataPtr > 0)// as you can see we are using extraDataptr to identify the size of the edp section for that message
{
Edpsize += pMessage->iExtraDataPtr;
// The EDP is the length of the extra data following the message, skip it
fSead((unsigned int)pMessage->iExtraDataPtr, SEEK_CUR);
}
}
fSead( VSB_HEADERSIZE, SEEK_SET); //go back to the start
//from here on out it is very similar to 103 and 102 but the location of the edp section is different
m_pMessages = new icsSpyMessage[numOfMessages];
for (unsigned int i = 0; i < numOfMessages; i++)
{
if (!fRead((char *)pMessage, sizeof(VSBSpyMessage)))
break; //error
if (firstMsg) {
FirstMsgTime.HardwareTimeStampID = pMessage[0].TimeStampHardwareID;
FirstMsgTime.HardwareTime1 = pMessage[0].TimeHardware;
FirstMsgTime.HardwareTime2 = pMessage[0].TimeHardware2;
FirstMsgTime.SystemTimeStampID = pMessage[0].TimeStampSystemID;
FirstMsgTime.SystemTime1 = pMessage[0].TimeSystem;
FirstMsgTime.SystemTime2 = pMessage[0].TimeSystem2;
firstMsg = false;
}
bool clear = true;
VSBMessageToNormal(&m_pMessages[i], pMessage);
if (pMessage->ExtraDataPtrEnabled && pMessage->iExtraDataPtr >= 1 ) {
EDPLength = pMessage->iExtraDataPtr;
char * pEDP = new char[EDPLength];
if(!fRead(pEDP, EDPLength))
return false; //error
m_pMessages[i].pExtraDataPtr = new pExtraDataPtrHandler();
((pExtraDataPtrHandler *)(m_pMessages[i].pExtraDataPtr))->pExtraDataPtr = (void *)pEDP;
((pExtraDataPtrHandler *)(m_pMessages[i].pExtraDataPtr))->length = EDPLength;
clear = false;
}
if (clear) {
EDPLength = 0;
m_pMessages[i].ColorID = 0;
m_pMessages[i].pExtraDataPtr = 0;
}
}
if (!fRead((char *)&timeStampRead, sizeof(timeStampRead)))
timeStampRead = FirstMsgTime;
m_startTimeStamp = timeStampRead;
m_nMessages = numOfMessages;
return true;
}
Last updated