static hs_output_plugin* create_output_plugin(const hs_config* cfg, hs_sandbox_config* sbc) { hs_output_plugin* p = calloc(1, sizeof(hs_output_plugin)); if (!p) return NULL; p->list_index = -1; if (pthread_mutex_init(&p->cp_lock, NULL)) { perror("cp_lock pthread_mutex_init failed"); exit(EXIT_FAILURE); } p->sb = hs_create_output_sandbox(p, cfg, sbc); if (!p->sb) { free(p); hs_log(g_module, 3, "lsb_create_custom failed: %s/%s", sbc->dir, sbc->filename); return NULL; } if (sbc->async_buffer_size > 0) { p->async_len = sbc->async_buffer_size; p->async_cp = calloc(p->async_len, sizeof(hs_checkpoint_pair)); if (!p->async_cp) { hs_free_sandbox(p->sb); free(p); hs_log(g_module, 3, "failed allocating the async buffer"); return NULL; } lsb_add_function(p->sb->lsb, &async_checkpoint_update, "async_checkpoint_update"); } return p; }
void hs_init_checkpoint_reader(hs_checkpoint_reader *cpr, const char *path) { char fqfn[HS_MAX_PATH]; if (!hs_get_fqfn(path, "hindsight.cp", fqfn, sizeof(fqfn))) { hs_log(g_module, 0, "checkpoint name exceeds the max length: %d", sizeof(fqfn)); exit(EXIT_FAILURE); } cpr->values = luaL_newstate(); if (!cpr->values) { hs_log(g_module, 0, "checkpoint_reader luaL_newstate failed"); exit(EXIT_FAILURE); } else { lua_pushvalue(cpr->values, LUA_GLOBALSINDEX); lua_setglobal(cpr->values, "_G"); } if (hs_file_exists(fqfn)) { if (luaL_dofile(cpr->values, fqfn)) { hs_log(g_module, 0, "loading %s failed: %s", fqfn, lua_tostring(cpr->values, -1)); exit(EXIT_FAILURE); } } if (pthread_mutex_init(&cpr->lock, NULL)) { perror("checkpoint reader pthread_mutex_init failed"); exit(EXIT_FAILURE); } }
void hs_init_checkpoint_writer(hs_checkpoint_writer* cpw, hs_input_plugins* ip, hs_analysis_plugins* ap, hs_output_plugins* op, const char* path) { cpw->input_plugins = ip; cpw->analysis_plugins = ap; cpw->output_plugins = op; char fqfn[HS_MAX_PATH]; if (!hs_get_fqfn(path, "hindsight.cp", fqfn, sizeof(fqfn))) { hs_log(g_module, 0, "checkpoint name exceeds the max length: %d", sizeof(fqfn)); exit(EXIT_FAILURE); } cpw->fh = fopen(fqfn, "wb"); if (!cpw->fh) { hs_log(g_module, 0, "%s: %s", fqfn, strerror(errno)); exit(EXIT_FAILURE); } if (!hs_get_fqfn(path, "hindsight.tsv", fqfn, sizeof(fqfn))) { hs_log(g_module, 0, "tsv name exceeds the max length: %d", sizeof(fqfn)); exit(EXIT_FAILURE); } cpw->tsv_path = malloc(strlen(fqfn) + 1); if (!cpw->tsv_path) { hs_log(g_module, 0, "tsv_path malloc failed"); exit(EXIT_FAILURE); } strcpy(cpw->tsv_path, fqfn); }
void hs_load_output_plugins(hs_output_plugins *plugins, const hs_config *cfg, bool dynamic) { char lpath[HS_MAX_PATH]; char rpath[HS_MAX_PATH]; if (!hs_get_fqfn(cfg->load_path, hs_output_dir, lpath, sizeof(lpath))) { hs_log(NULL, g_module, 0, "load path too long"); exit(EXIT_FAILURE); } if (!hs_get_fqfn(cfg->run_path, hs_output_dir, rpath, sizeof(rpath))) { hs_log(NULL, g_module, 0, "run path too long"); exit(EXIT_FAILURE); } const char *dir = dynamic ? lpath : rpath; DIR *dp = opendir(dir); if (dp == NULL) { hs_log(NULL, g_module, 0, "%s: %s", dir, strerror(errno)); exit(EXIT_FAILURE); } if (dynamic) process_lua(plugins, lpath, rpath, dp); struct dirent *entry; while ((entry = readdir(dp))) { if (dynamic) { int ret = hs_process_load_cfg(lpath, rpath, entry->d_name); switch (ret) { case 0: remove_from_output_plugins(plugins, entry->d_name); break; case 1: // proceed to load break; default: // ignore continue; } } hs_sandbox_config sbc; if (hs_load_sandbox_config(rpath, entry->d_name, &sbc, &cfg->opd, 'o')) { hs_output_plugin *p = create_output_plugin(plugins->mmb, cfg, &sbc); if (p) { p->plugins = plugins; hs_init_input(&p->input, cfg->max_message_size, cfg->output_path, p->name); hs_init_input(&p->analysis, cfg->max_message_size, cfg->output_path, p->name); add_to_output_plugins(plugins, p); } else { hs_log(NULL, g_module, 3, "%s create_output_plugin failed", sbc.cfg_name); } hs_free_sandbox_config(&sbc); } } closedir(dp); }
// Runs through the list of universes, telling them to // save to the specified file. void CHSUniverseDBDef::SaveToFile(const char *lpstrPath) { FILE *fp; char tbuf[256]; // Is the file path good? if (!lpstrPath || strlen(lpstrPath) == 0) { hs_log ("Attempt to save the universe database, but no path specified. Could be a config file problem."); return; } // Any universes to save? if (m_mapUniverses.size() == 0) { return; } // Open the database fopen_s(&fp, lpstrPath, "w"); if (!fp) { sprintf_s(tbuf, "ERROR: Unable to write universes to %s.", lpstrPath); hs_log(tbuf); return; } // Print dbversion fprintf(fp, "DBVERSION=4.0\n"); // Save all of the universes. CSTLUniverseMap::iterator iter; for (iter = m_mapUniverses.begin(); iter != m_mapUniverses.end(); iter++) { CHSUniverse *pUniverse; pUniverse = (*iter).second; if (pUniverse) { pUniverse->SaveToFile(fp); } } fprintf(fp, "*END*\n"); fclose(fp); }
void CHSWeaponDBArray::SaveToFile(char *lpstrPath) { UINT idx; FILE *fp; char tbuf[512]; if (m_num_weapons <= 0) return; fp = fopen(lpstrPath, "w"); if (!fp) { sprintf(tbuf, "ERROR: Unable to write weapons to %s.", lpstrPath); hs_log(tbuf); return; } for (idx = 0; idx < m_num_weapons; idx++) { if (m_weapons[idx]->m_type == HSW_LASER) { WriteLaser((CHSDBLaser *) m_weapons[idx], fp); } else if (m_weapons[idx]->m_type == HSW_MISSILE) { WriteMissile((CHSDBMissile *) m_weapons[idx], fp); } } fprintf(fp, "*END*\n"); fclose(fp); }
void hs_lookup_input_checkpoint(hs_checkpoint_reader *cpr, const char *subdir, const char *key, const char *path, hs_checkpoint *cp) { const char *pos = NULL; pthread_mutex_lock(&cpr->lock); lua_pushfstring(cpr->values, "%s->%s", subdir, key); lua_gettable(cpr->values, LUA_GLOBALSINDEX); if (lua_type(cpr->values, -1) == LUA_TSTRING) { const char *tmp = lua_tostring(cpr->values, -1); if (tmp) { pos = strchr(tmp, ':'); if (pos) { cp->id = strtoull(tmp, NULL, 10); cp->offset = (size_t)strtoull(pos + 1, NULL, 10); } } } lua_pop(cpr->values, 1); pthread_mutex_unlock(&cpr->lock); if (!pos) { char fqfn[HS_MAX_PATH]; if (!hs_get_fqfn(path, subdir, fqfn, sizeof(fqfn))) { hs_log(g_module, 0, "checkpoint name exceeds the max length: %d", sizeof(fqfn)); exit(EXIT_FAILURE); } cp->id = find_first_id(fqfn); } }
static void init_analysis_thread(hs_analysis_plugins* plugins, int tid) { hs_analysis_thread* at = &plugins->list[tid]; at->plugins = plugins; at->list = NULL; at->msg = NULL; if (pthread_mutex_init(&at->list_lock, NULL)) { perror("list_lock pthread_mutex_init failed"); exit(EXIT_FAILURE); } if (pthread_mutex_init(&at->cp_lock, NULL)) { perror("cp_lock pthread_mutex_init failed"); exit(EXIT_FAILURE); } at->cp.id = 0; at->cp.offset = 0; at->current_t = 0; at->list_cap = 0; at->list_cnt = 0; at->tid = tid; at->matched = false; char name[255]; int n = snprintf(name, sizeof name, "%s%d", hs_analysis_dir, tid); if (n < 0 || n >= (int)sizeof name) { hs_log(g_module, 0, "name exceeded the buffer length: %s%d", hs_analysis_dir, tid); exit(EXIT_FAILURE); } hs_init_input(&at->input, plugins->cfg->max_message_size, plugins->cfg->output_path, name); }
static void add_to_analysis_plugins(const hs_sandbox_config* cfg, hs_analysis_plugins* plugins, hs_analysis_plugin* p) { int thread = cfg->thread % plugins->cfg->analysis_threads; hs_analysis_thread* at = &plugins->list[thread]; p->at = at; pthread_mutex_lock(&at->list_lock); // todo shrink it down if there are a lot of empty slots if (at->list_cnt < at->list_cap) { // add to an empty slot for (int i = 0; i < at->list_cap; ++i) { if (!at->list[i]) { at->list[i] = p; ++at->list_cnt; } } } else { // expand the list ++at->list_cap; // todo probably don't want to grow it by 1 hs_analysis_plugin** tmp = realloc(at->list, sizeof(hs_analysis_plugin) * at->list_cap); if (tmp) { at->list = tmp; at->list[at->list_cap - 1] = p; ++at->list_cnt; } else { hs_log(g_module, 0, "plugins realloc failed"); exit(EXIT_FAILURE); } } pthread_mutex_unlock(&at->list_lock); }
void CHSHandlerUniverse::HandleGetUniverseList(CHSPacket * pPacket) { hs_log("ADMIN SERVER: Handle packet GetUniverseList"); CHSPGetUniverseList *cmdGetList = static_cast < CHSPGetUniverseList * >(pPacket); // Create a class list packet as a response. CHSPUniverseList cmdList; cmdList.SetPacketAddress(cmdGetList->GetPacketAddress()); THSUniverseIterator tIter; HS_BOOL8 bContinue; for (bContinue = CHSUniverseDB::GetInstance().GetFirstUniverse(tIter); bContinue; bContinue = CHSUniverseDB::GetInstance().GetNextUniverse(tIter)) { if (tIter.pValue != NULL) { CHSUniverse *pUniverse = (CHSUniverse *) tIter.pValue; CHSPUniverseList::THSUniverse tEntry; tEntry.uiID = pUniverse->GetID(); tEntry.strName = pUniverse->GetName(); tEntry.uiNumObjects = pUniverse->GetNumObjects(); tEntry.uiNumActiveObjects = pUniverse->GetNumActiveObjects(); cmdList.AddUniverse(tEntry); } } HSNetwork.SendPacket(cmdList); }
// Attempts to allocate a new territory in the array of the // specified type. CHSTerritory *CHSTerritoryArray::NewTerritory(int objnum, TERRTYPE type) { CHSTerritory* territory; // Determine type of territory switch (type) { case T_RADIAL: territory = new CHSRadialTerritory; break; case T_CUBIC: territory = new CHSCubicTerritory; break; default: // What is this territory type? return NULL; } // Set object num territory->SetDbref(objnum); // Set the territory flag if (objnum != HSNOTHING) { hsInterface.SetToggle(territory->GetDbref(), THING_HSPACE_TERRITORY); hs_log(hsInterface.HSPrintf("%s Territory %s (#%d) added.", type == 0 ? "Radial" : "Cubic", hsInterface.GetName(objnum), objnum)); } m_territories.push_back(territory); return territory; }
void CHSHandlerClass::HandleGetClassList(CHSPacket * pPacket) { hs_log("ADMIN SERVER: Handle packet GetClassList"); CHSPGetClassList *cmdGetList = static_cast < CHSPGetClassList * >(pPacket); // Create a class list packet as a response. CHSPClassList cmdList; cmdList.SetPacketAddress(cmdGetList->GetPacketAddress()); THSShipClassIterator tIter; HS_BOOL8 bContinue; for (bContinue = CHSClassDB::GetInstance().GetFirstClass(tIter); bContinue; bContinue = CHSClassDB::GetInstance().GetNextClass(tIter)) { if (tIter.pValue != NULL) { CHSShipClass *pClass = (CHSShipClass *) tIter.pValue; CHSPClassList::THSClass tClass; tClass.uiClassID = pClass->Id(); tClass.strClassName = pClass->ClassName(); cmdList.AddClass(tClass); } } HSNetwork.SendPacket(cmdList); }
// Creates a new weapon, based on the specified type. If the // type is invalid, or the weapon couldn't be created, NULL is // returned. CHSDBWeapon *CHSWeaponDBArray::NewWeapon(UINT type) { // Do we have any space left in the array? int idx; for (idx = 0; idx < HS_MAX_WEAPONS; idx++) { if (!m_weapons[idx]) break; } if (idx == HS_MAX_WEAPONS) { hs_log("WARNING: Maximum number of weapons reached."); return NULL; } // Determine type, allocate the new weapon. switch(type) { case HSW_LASER: m_weapons[idx] = new CHSDBLaser; break; case HSW_MISSILE: m_weapons[idx] = new CHSDBMissile; break; return NULL; } dbHSDB.m_nWeapons++; m_num_weapons++; m_weapons[idx]->m_type = type; return m_weapons[idx]; }
void hs_load_analysis_plugins(hs_analysis_plugins* plugins, const hs_config* cfg, const char* path) { char dir[HS_MAX_PATH]; if (!hs_get_fqfn(path, hs_analysis_dir, dir, sizeof(dir))) { hs_log(g_module, 0, "load path too long"); exit(EXIT_FAILURE); } struct dirent* entry; DIR* dp = opendir(dir); if (dp == NULL) { exit(EXIT_FAILURE); } while ((entry = readdir(dp))) { hs_sandbox_config sbc; if (hs_load_sandbox_config(dir, entry->d_name, &sbc, &cfg->apd, HS_SB_TYPE_ANALYSIS)) { hs_analysis_plugin* p = create_analysis_plugin(cfg, &sbc); if (p) { p->sb->mm = hs_create_message_matcher(plugins->mmb, sbc.message_matcher); int ret = hs_init_analysis_sandbox(p->sb, &inject_message); if (!p->sb->mm || ret) { if (!p->sb->mm) { hs_log(g_module, 3, "%s invalid message_matcher: %s", p->sb->name, sbc.message_matcher); } else { hs_log(g_module, 3, "lsb_init: %s received: %d %s", p->sb->name, ret, lsb_get_error(p->sb->lsb)); } free_analysis_plugin(p); free(p); p = NULL; hs_free_sandbox_config(&sbc); continue; } add_to_analysis_plugins(&sbc, plugins, p); } } hs_free_sandbox_config(&sbc); } closedir(dp); }
static void shutdown_timer_event(hs_output_plugin *p) { if (lsb_heka_is_running(p->hsb)) { if (lsb_heka_timer_event(p->hsb, time(NULL), true)) { hs_log(NULL, p->name, 3, "terminated: %s", lsb_heka_get_error(p->hsb)); } } }
static void terminate_sandbox(hs_analysis_thread* at, int i) { hs_log(g_module, 3, "terminated: %s msg: %s", at->list[i]->sb->name, lsb_get_error(at->list[i]->sb->lsb)); free_analysis_plugin(at->list[i]); free(at->list[i]); at->list[i] = NULL; --at->list_cnt; }
static void shutdown_timer_event(hs_output_plugin* p) { if (lsb_get_state(p->sb->lsb) != LSB_TERMINATED) { if (hs_timer_event(p->sb->lsb, time(NULL))) { hs_log(g_module, 3, "terminated: %s msg: %s", p->sb->name, lsb_get_error(p->sb->lsb)); } } }
// Loads missile bay information from the specified file stream. void CHSMissileBay::LoadFromFile(FILE * fp) { if (NULL == fp) { hs_log("NULL filepointer passed to CHSMissileBay::LoadFromFile()"); return; } char tbuf[HS_BUF_256]; char strKey[HS_BUF_128]; char strValue[HS_BUF_128]; char *ptr; HS_INT32 type; // Load from the file stream until end of file or, more // like, MISSILEBAYEND indicator. type = -1; while (fgets(tbuf, HS_BUF_256_CPY, fp)) { // Strip newline chars if ((ptr = strchr(tbuf, '\n')) != NULL) *ptr = '\0'; if ((ptr = strchr(tbuf, '\r')) != NULL) *ptr = '\0'; // Extract key/value pairs extract(tbuf, strKey, 0, 1, '='); extract(tbuf, strValue, 1, 1, '='); // Check for key match if (!strncmp(strKey, "MISSILEBAYEND", 13)) { // This is the end. return; } else if (!strncmp(strKey, "MISSILETYPE", 11)) { type = atoi(strValue); } else if (!strncmp(strKey, "MISSILEMAX", 10)) { // Set the maximum value for the type. // No need to error check. SetRemaining(type, atoi(strValue)); } else if (!strncmp(strKey, "MISSILEREMAINING", 16)) { // Set missiles remaining for the type. SetRemaining(type, atoi(strValue)); } } }
bool hs_load_checkpoint(lua_State *L, int idx, hs_ip_checkpoint *cp) { size_t len; switch (lua_type(L, idx)) { case LUA_TSTRING: pthread_mutex_lock(&cp->lock); if (cp->type == HS_CP_NUMERIC) cp->value.s = NULL; cp->type = HS_CP_STRING; const char *tmp = lua_tolstring(L, idx, &len); cp->len = (unsigned)len; ++len; if (tmp && len <= HS_MAX_IP_CHECKPOINT) { if (len > cp->cap) { free(cp->value.s); cp->value.s = malloc(len); if (!cp->value.s) { cp->len = 0; cp->cap = 0; hs_log(g_module, 0, "malloc failed"); pthread_mutex_unlock(&cp->lock); return false; } cp->cap = len; } memcpy(cp->value.s, tmp, len); } else { pthread_mutex_unlock(&cp->lock); return false; } pthread_mutex_unlock(&cp->lock); break; case LUA_TNUMBER: pthread_mutex_lock(&cp->lock); if (cp->type == HS_CP_STRING) { free(cp->value.s); cp->value.s = NULL; cp->len = 0; cp->cap = 0; } cp->type = HS_CP_NUMERIC; cp->value.d = lua_tonumber(L, idx); pthread_mutex_unlock(&cp->lock); break; case LUA_TNONE: case LUA_TNIL: break; default: return false; } return true; }
void hs_wait_output_plugins(hs_output_plugins *plugins) { pthread_mutex_lock(&plugins->list_lock); for (int i = 0; i < plugins->list_cap; ++i) { if (!plugins->list[i]) continue; hs_output_plugin *p = plugins->list[i]; plugins->list[i] = NULL; if (pthread_join(p->thread, NULL)) { hs_log(NULL, p->name, 3, "thread could not be joined"); } destroy_output_plugin(p); --plugins->list_cnt; } pthread_mutex_unlock(&plugins->list_lock); }
void CHSHandlerUniverse::HandleDeleteUniverse(CHSPacket * pPacket) { hs_log("ADMIN SERVER: Handle packet DeleteUniverse"); CHSPDeleteUniverse *cmdDelete = static_cast < CHSPDeleteUniverse * >(pPacket); // Create a class list packet as a response. CHSPDeleteUniverseResp cmdResponse; cmdResponse.SetPacketAddress(cmdDelete->GetPacketAddress()); cmdResponse.m_bDeleted = CHSUniverseDB::GetInstance().DeleteUniverse(cmdDelete-> m_uiUniverseID); HSNetwork.SendPacket(cmdResponse); }
static hs_analysis_plugin* create_analysis_plugin(const hs_config* cfg, hs_sandbox_config* sbc) { hs_analysis_plugin* p = calloc(1, sizeof(hs_analysis_plugin)); if (!p) return NULL; p->sb = hs_create_analysis_sandbox(p, cfg, sbc); if (!p->sb) { free(p); hs_log(g_module, 3, "lsb_create_custom failed: %s/%s", sbc->dir, sbc->filename); return NULL; } return p; }
static void destroy_output_plugin(hs_output_plugin *p) { if (!p) return; hs_free_input(&p->analysis); hs_free_input(&p->input); char *msg = lsb_heka_destroy_sandbox(p->hsb); if (msg) { hs_log(NULL, p->name, 3, "lsb_heka_destroy_sandbox failed: %s", msg); free(msg); } lsb_destroy_message_matcher(p->mm); free(p->name); free(p->async_cp); pthread_mutex_destroy(&p->cp_lock); free(p); }
void CHSInterface::AtrDel(int obj, const char *atrname, int owner) { if (false == ValidObject(obj)) { hs_log(HSPrintf("AtrDel() invalid object: %d, atr: %s", obj, atrname)); return; } #ifdef PENNMUSH // No change in code between versions atr_clr(obj, atrname, owner); #endif #if defined(TM3) || defined(MUX) my_atr_clear(obj, atrname); #endif }
// Adds an attribute with a value to an object. void CHSInterface::AtrAdd(int obj, const char *atrname, char *val, int owner, int flags) { if (false == ValidObject(obj)) { hs_log(HSPrintf("AtrAdd() invalid object: %d, atr: %s, val: %s", obj, atrname, val)); return; } #ifdef PENNMUSH // No change in code between versions atr_add(obj, atrname, val, owner, flags); #endif #if defined(TM3) || defined(MUX) my_atr_put(obj, atrname, val); #endif }
int hs_error(hs_error_code err, const char *fmt, ...) { va_list ap; for (unsigned int i = 0; i < mask_count; i++) { if (mask[i] == err) return err; } if (fmt) { va_start(ap, fmt); logv(HS_LOG_ERROR, fmt, ap); va_end(ap); } else { hs_log(HS_LOG_ERROR, "%s", generic_message(err)); } return err; }
static size_t find_first_id(const char *path) { struct dirent *entry; DIR *dp = opendir(path); if (dp == NULL) { hs_log(g_module, 0, "path does not exist: %s", path); exit(EXIT_FAILURE); } unsigned long long file_id = ULLONG_MAX, current_id = 0; while ((entry = readdir(dp))) { if (extract_id(entry->d_name, ¤t_id)) { if (current_id < file_id) { file_id = current_id; } } } closedir(dp); return file_id == ULLONG_MAX ? 0 : file_id; }
// Saves missile bay information to the specified file stream. void CHSMissileBay::SaveToFile(FILE * fp) { if (NULL == fp) { hs_log("Invalid file pointer passed to CHSMissileBay::SaveToFile()"); return; } // Write out our missile storage infos CSTLMissileStorageMap::iterator iter; for (iter = m_mapMissiles.begin(); iter != m_mapMissiles.end(); iter++) { THSMissileStorage & rtStorage = iter->second; fprintf(fp, "MISSILETYPE=%d\n", rtStorage.uiWeaponTypeID); fprintf(fp, "MISSILEMAX=%d\n", rtStorage.uiMaximum); fprintf(fp, "MISSILEREMAINING=%d\n", rtStorage.uiNumRemaining); } fprintf(fp, "MISSILEBAYEND\n"); }
void CHSMissile::DoCycle() { // Do we need to delete ourselves? if (m_delete_me) { // Remove us from space CHSUniverse *cSource; cSource = GetUniverse(); if (cSource) { cSource->RemoveObject(this); } // Purge the object representing the missile prior to deallocating // memory if (hsInterface.ValidObject(GetDbref())) { hsInterface.DestroyObject(GetDbref()); } return; } // If we have no target or no parent, remove us from space. if (!m_target || !m_pData || !m_target->IsActive()) { hs_log("CHSMissile::DoCycle() Missile Data Invalid - Removing Object."); m_delete_me = true; return; } // Do we know how much time is left until we die? if (m_timeleft < 0) { CalculateTimeLeft(); } else { m_timeleft--; } // Missile depleted? if (0 == m_timeleft) { m_delete_me = true; return; } // Change the missile heading toward the target ChangeHeading(); // Move us closer to the target. MoveTowardTarget(); // The MoveTowardTarget() checks to see if the missile hits // so we just have to check our flag. if (m_target_hit) { // If we aren't designated to miss, apply damage if (m_specified_miss != true) { // BOOM! HitTarget(); } m_delete_me = true; // Delete next time around } }
static void parse_descriptor(hs_handle *h, struct hidraw_report_descriptor *report) { unsigned int collection_depth = 0; unsigned int size = 0; for (size_t i = 0; i < report->size; i += size + 1) { unsigned int type; uint32_t data; type = report->value[i]; if (type == 0xFE) { // not interested in long items if (i + 1 < report->size) size = (unsigned int)report->value[i + 1] + 2; continue; } size = type & 3; if (size == 3) size = 4; type &= 0xFC; if (i + size >= report->size) { hs_log(HS_LOG_WARNING, "Invalid HID descriptor for device '%s'", h->dev->path); return; } // little endian switch (size) { case 0: data = 0; break; case 1: data = report->value[i + 1]; break; case 2: data = (uint32_t)(report->value[i + 2] << 8) | report->value[i + 1]; break; case 4: data = (uint32_t)((report->value[i + 4] << 24) | (report->value[i + 3] << 16) | (report->value[i + 2] << 8) | report->value[i + 1]); break; // silence unitialized warning default: data = 0; break; } switch (type) { // main items case 0xA0: collection_depth++; break; case 0xC0: collection_depth--; break; // global items case 0x84: h->numbered_reports = true; break; case 0x04: if (!collection_depth) h->usage_page = (uint16_t)data; break; // local items case 0x08: if (!collection_depth) h->usage = (uint16_t)data; break; } } }