Source file: /~heha/hsn/hidparse.zip/hidparse/UsageDecode.cpp

/*****************************************************
 * Decode usages using HidGen's initialization files *
 *****************************************************
*110830	created
*/

#include "hidparse.h"

// Parsed DT.INI and *.UPG files.
// This structure tree is not intended to be freed recursively, it is allocated in one heap.
struct UE {	// Usage Entry
 USAGE u[2];	// range from-to, equal when one value only
 char *name;	// usage string (template), ASCII (7-bit english only)
};
struct UPE {	// Usage Page Entry
 USAGE up[2];	// range from-to, equal when one value only
 char* name;	// usage page string (template), ASCII (7-bit english only)
 UE*   ulist;	// array of Usage Entries
 int   ulen;	// length of array
 bool Build(const TCHAR *fname);
};
struct UP {
 UPE* uplist;	// array of Usage Page Entries
 int  uplen;	// length of array
 HANDLE heap;	// using Windows Heap functions
 bool Build(const TCHAR *directory);
}uplist;

static void HeapGrow(void*&p, int&len, int elemsize) {
 if (!(len&15)) {	// action every 16 elements
  if (p) p=HeapReAlloc(uplist.heap,HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,p,(len+16)*elemsize);
  else p=HeapAlloc(uplist.heap,HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,16*elemsize);
 }
 len++;
}

static char* mystrdup(char* s) {
 int l=lstrlenA(s)+1;
 char*p=(char*)HeapAlloc(uplist.heap,HEAP_GENERATE_EXCEPTIONS,l);
 CopyMemory(p,s,l);
 return p;
}

bool UPE::Build(const TCHAR *fname) {
 FILE *f=_tfopen(fname,T("r"));
 if (!f) return false;
 char line[128];
 fgets(line,sizeof(line),f);	// Name of usage page (unused)
 fgets(line,sizeof(line),f);	// Type of usage (either "NORMAL" or "REPEATING")
 while (fgets(line,sizeof(line),f)) {
  HeapGrow((void*&)ulist,ulen,sizeof(UE));
  UE&ue=ulist[ulen-1];		// Address the newly available element
  if (sscanf(line,"%hx-%hx",&ue.u[0],&ue.u[1])==1) ue.u[1]=ue.u[0];
  char *p=StrPBrkA(line,"\t ");
  if (p) {
   char *e=StrPBrkA(++p,"\r\n");
   if (e) *e=0;
   ue.name=mystrdup(p);
  }
 }
 fclose(f);
 return true;
}

bool UP::Build(const TCHAR *directory) {
 TCHAR fname[MAX_PATH];
 PathCombine(fname,directory,T("dt.ini"));
 int n=GetPrivateProfileInt(T("UsagePages"),T("Count"),0,fname);
 if (!n) return false;
 for (int i=0; i<n; i++) {
  TCHAR key[16];
  wnsprintf(key,elemof(key),T("UP%d"),i);
  TCHAR buf[128];
  GetPrivateProfileString(T("UsagePages"),key,NULL,buf,elemof(buf),fname);
  TCHAR *k1=StrChr(buf,',');
  if (k1) {
   *k1++=0;
   TCHAR *k2=StrChr(k1,',');
   if (k2) {
    *k2++=0;
    HeapGrow((void*&)uplist,uplen,sizeof(UPE));
    UPE&upe=uplist[uplen-1];
    upe.up[0]=upe.up[1]=StrToInt(buf);
#ifdef UNICODE
    int l=lstrlen(k1)+1;
    upe.name=(char*)HeapAlloc(heap,HEAP_GENERATE_EXCEPTIONS,l);
    WideCharToMultiByte(CP_ACP,0,k1,l,upe.name,l,NULL,NULL);
#else
    upe.name=mystrdup(k1);
#endif
    TCHAR fname[MAX_PATH];
    PathCombine(fname,directory,k2);
    upe.Build(fname);
   }
  }
 }
 return true;
}

bool UsageDecode::Init(const TCHAR*directory) {
 uplist.heap=HeapCreate(HEAP_GENERATE_EXCEPTIONS,0x10000,0x100000);
 return uplist.Build(directory);
}

void UsageDecode::Done() {
 HeapDestroy(uplist.heap);
 uplist.heap=0;
 uplist.uplen=0;
}

int UsageDecode::Decode(USAGE_AND_PAGE u, BYTE flags, TCHAR*buf, int buflen) {
 char sp[64];	// name of usage page
 char su[64];	// name of usage
 int i;
 UPE *upe;
// Scan for usage page (always)
 for (upe=uplist.uplist,i=0; i<uplist.uplen; i++,upe++)
 if (upe->up[0]<=u.UsagePage && u.UsagePage<=upe->up[1]) {
  wnsprintfA(sp,elemof(sp),upe->name,u.UsagePage-upe->up[0]);
  break;
 }
// When not found, make hexadecimal number
 if (i==uplist.uplen) {
  upe=NULL;		// no Usage Page entry
  wnsprintfA(sp,elemof(sp),"0x%02X",u.UsagePage);
 }

// Scan for usage (when needed)
 if (flags&1) {
  UE *ue;
  if (upe) {
   for (ue=upe->ulist,i=0; i<upe->ulen; i++,ue++)
   if (ue->u[0]<=u.Usage && u.Usage<=ue->u[1]) {
    wnsprintfA(su,elemof(su),ue->name,u.Usage-ue->u[0]);
    goto found_usage;
   }
   ue=NULL;		// no Usage entry
found_usage:;
  }else ue=NULL;
// When not found, make hexadecimal number
  if (!ue) wnsprintfA(su,elemof(su),"0x%02X",u.Usage);
 }

// Generate final strings
 switch (flags&3) {
  case 3:	// long usage
    return wnsprintf(buf,buflen,T("Usage (") ASTR T(":") ASTR T(")"),sp,su);
  case 1:	// short usage
    return wnsprintf(buf,buflen,T("Usage (") ASTR T(")"),su);
  case 2:	// usage page
    return wnsprintf(buf,buflen,T("UsagePage (") ASTR T(")"),sp);
 }
 return 0;
}
Detected encoding: ASCII (7 bit)2