home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2004 March
/
CMCD0304.ISO
/
Software
/
Freeware
/
Programare
/
nullsoft
/
nsis20.exe
/
Source
/
strlist.h
< prev
next >
Wrap
C/C++ Source or Header
|
2004-01-30
|
19KB
|
866 lines
#ifndef _STRLIST_H_
#define _STRLIST_H_
#include "Platform.h"
#include <stdio.h>
#include <stdlib.h> // for gcc
class IGrowBuf
{
public:
virtual int add(const void *data, int len)=0;
virtual void resize(int newlen)=0;
virtual int getlen()=0;
virtual void *get()=0;
};
class IMMap
{
public:
virtual void resize(int newlen)=0;
virtual int getsize()=0;
virtual void *get(int offset, int size)=0;
virtual void *getmore(int offset, int size)=0;
virtual void release()=0;
virtual void release(void *view)=0;
virtual void clear()=0;
virtual void setro(BOOL bRO)=0;
virtual void flush(int num)=0;
};
class GrowBuf : public IGrowBuf
{
public:
GrowBuf() { m_alloc=m_used=m_zero=0; m_s=NULL; m_bs=32768; }
~GrowBuf() { free(m_s); }
void set_zeroing(int zero) { m_zero=zero; }
int add(const void *data, int len)
{
if (len<=0) return 0;
resize(m_used+len);
memcpy((char*)m_s+m_used-len,data,len);
return m_used-len;
}
void resize(int newlen)
{
int os=m_alloc;
int ou=m_used;
m_used=newlen;
if (newlen > m_alloc)
{
void *n;
m_alloc = newlen*2 + m_bs;
n = realloc(m_s, m_alloc);
if (!n)
{
extern FILE *g_output;
extern int g_display_errors;
if (g_display_errors)
{
fprintf(g_output,"\nack! realloc(%d) failed, trying malloc(%d)!\n",m_alloc,newlen);
fflush(g_output);
}
m_alloc=newlen; // try to malloc the minimum needed
n=malloc(m_alloc);
if (!n)
{
extern void quit();
if (g_display_errors)
{
fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",m_alloc);
fflush(g_output);
}
quit();
}
memcpy(n,m_s,min(newlen,os));
free(m_s);
}
m_s=n;
}
if (m_zero && m_used > ou)
memset((char*)m_s + ou, 0, m_used - ou);
if (!m_used && m_alloc > 2*m_bs) // only free if you resize to 0 and we're > 64k
{
m_alloc=0;
free(m_s);
m_s=NULL;
}
}
int getlen() { return m_used; }
void *get() { return m_s; }
private:
void *m_s;
int m_alloc;
int m_used;
int m_zero;
protected:
int m_bs;
};
class TinyGrowBuf : public GrowBuf {
public:
TinyGrowBuf() : GrowBuf() { m_bs=1024; }
};
class StringList
{
public:
StringList() { }
~StringList() { }
int add(const char *str, int case_sensitive)
{
int a=find(str,case_sensitive);
if (a >= 0 && case_sensitive!=-1) return a;
return gr.add(str,strlen(str)+1);
}
// use 2 for case sensitive end-of-string matches too
int find(const char *str, int case_sensitive, int *idx=NULL) // returns -1 if not found
{
char *s=(char*)gr.get();
int ml=gr.getlen();
int offs=0;
if (idx) *idx=0;
while (offs < ml)
{
if ((case_sensitive && !strcmp(s+offs,str)) ||
(!case_sensitive && !stricmp(s+offs,str)))
{
return offs;
}
if (case_sensitive==2 &&
strlen(str) < strlen(s+offs) && // check for end of string
!strcmp(s+offs+strlen(s+offs)-strlen(str),str))
{
return offs+strlen(s+offs)-strlen(str);
}
offs+=strlen(s+offs)+1;
if (idx) (*idx)++;
}
return -1;
}
void delbypos(int pos)
{
char *s=(char*)gr.get();
int len=strlen(s+pos)+1;
if (pos+len < gr.getlen()) memcpy(s+pos,s+pos+len,gr.getlen()-(pos+len));
gr.resize(gr.getlen()-len);
}
int idx2pos(int idx)
{
char *s=(char*)gr.get();
int offs=0;
int cnt=0;
if (idx>=0) while (offs < gr.getlen())
{
if (cnt++ == idx) return offs;
offs+=strlen(s+offs)+1;
}
return -1;
}
int getnum() {
char *s=(char*)gr.get();
int ml=gr.getlen();
int offs=0;
int idx=0;
while (offs < ml)
{
offs+=strlen(s+offs)+1;
idx++;
}
return idx;
}
char *get() { return (char*)gr.get(); }
int getlen() { return gr.getlen(); }
private:
GrowBuf gr;
};
template <class T>
class SortedStringList
{
public:
SortedStringList() { }
~SortedStringList()
{
T *s=(T*)gr.get();
int num=gr.getlen()/sizeof(T);
for (int i=0; i<num; i++) {
if (s[i].name)
free(s[i].name);
}
}
// returns -1 when name already exists and pos if added
int add(const char *name, int case_sensitive=0)
{
T newstruct={0,};
int pos=find(name,case_sensitive,1);
if (pos==-1) return -1;
newstruct.name=(char*)malloc(strlen(name)+1);
if (!newstruct.name)
{
extern FILE *g_output;
extern int g_display_errors;
extern void quit();
if (g_display_errors)
{
fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",strlen(name)+1);
fflush(g_output);
}
quit();
}
strcpy(newstruct.name,name);
gr.add(&newstruct,sizeof(T));
T *s=(T*)gr.get();
memmove(s+pos+1,s+pos,gr.getlen()-((pos+1)*sizeof(T)));
memcpy(s+pos,&newstruct,sizeof(T));
return pos;
}
// returns -1 if not found, position if found
// if returnbestpos=1 returns -1 if found, best pos to insert if not found
int find(const char *str, int case_sensitive=0, int returnbestpos=0)
{
T *data=(T *)gr.get();
int ul=gr.getlen()/sizeof(T);
int ll=0;
int nextpos=(ul+ll)/2;
while (ul > ll)
{
int res;
if (case_sensitive)
res=strcmp(str, data[nextpos].name);
else
res=stricmp(str, data[nextpos].name);
if (res==0) return returnbestpos ? -1 : nextpos;
if (res<0) ul=nextpos;
else ll=nextpos+1;
nextpos=(ul+ll)/2;
}
return returnbestpos ? nextpos : -1;
}
// returns 0 on success, 1 otherwise
int del(const char *str, int case_sensitive=0)
{
int pos=find(str, case_sensitive);
if (pos==-1) return 1;
T *db=(T *)gr.get();
free(db[pos].name);
freestruct(pos);
memmove(db+pos,db+pos+1,gr.getlen()-(pos*sizeof(T))-sizeof(T));
gr.resize(gr.getlen()-sizeof(T));
return 0;
}
void delbypos(int pos)
{
T *db=(T *)gr.get();
free(db[pos].name);
memmove(db+pos,db+pos+1,gr.getlen()-(pos*sizeof(T))-sizeof(T));
gr.resize(gr.getlen()-sizeof(T));
}
protected:
TinyGrowBuf gr;
};
template <class T>
class SortedStringListND // no delete - can be placed in GrowBuf
{
public:
SortedStringListND() { }
~SortedStringListND() { }
// returns -1 when name already exists and pos if added
int add(const char *name, int case_sensitive=0, int alwaysreturnpos=0)
{
int where;
T newstruct={0,};
int pos=find(name,-1,case_sensitive,1,&where);
if (pos==-1) return alwaysreturnpos ? where : -1;
newstruct.name=strings.add(name,strlen(name)+1);
gr.add(&newstruct,sizeof(T));
T *s=(T*)gr.get();
memmove(s+pos+1,s+pos,gr.getlen()-((pos+1)*sizeof(T)));
memcpy(s+pos,&newstruct,sizeof(T));
return pos;
}
// returns -1 if not found, position if found
// if returnbestpos=1 returns -1 if found, best pos to insert if not found
// if n_chars equal to -1 all string is tested
int find(const char *str, size_t n_chars=-1, int case_sensitive=0, int returnbestpos=0, int *where=0)
{
T *data=(T *)gr.get();
int ul=gr.getlen()/sizeof(T);
int ll=0;
int nextpos=(ul+ll)/2;
while (ul > ll)
{
int res;
const char *pCurr = (char*)strings.get() + data[nextpos].name;
if (n_chars == -1 )
{
if (case_sensitive)
res=strcmp(str, pCurr);
else
res=stricmp(str, pCurr);
}
else
{
if (case_sensitive)
res=strncmp(str, pCurr, min(n_chars, strlen(pCurr)));
else
res=strnicmp(str, pCurr, min(n_chars, strlen(pCurr)));
if ( res == 0 && n_chars != -1 && n_chars != strlen(pCurr) )
res = n_chars - strlen(pCurr);
}
if (res==0)
{
if (where) *where = nextpos;
return returnbestpos ? (case_sensitive!=-1 ? -1 : nextpos) : nextpos;
}
if (res<0) ul=nextpos;
else ll=nextpos+1;
nextpos=(ul+ll)/2;
}
return returnbestpos ? nextpos : -1;
}
protected:
TinyGrowBuf gr;
GrowBuf strings;
};
struct define {
char *name;
char *value;
};
class DefineList : public SortedStringList<struct define>
{
public:
DefineList() { }
~DefineList()
{
struct define *s=(struct define*)gr.get();
int num=gr.getlen()/sizeof(struct define);
for (int i=0; i<num; i++) {
free(s[i].value);
}
}
int add(const char *name, const char *value="")
{
int pos=SortedStringList<struct define>::add(name);
if (pos == -1)
{
return 1;
}
char **newvalue=&(((struct define*)gr.get())[pos].value);
*newvalue=(char*)malloc(strlen(value)+1);
if (!(*newvalue))
{
extern FILE *g_output;
extern int g_display_errors;
extern void quit();
if (g_display_errors)
{
fprintf(g_output,"\nInternal compiler error #12345: GrowBuf realloc/malloc(%d) failed.\n",strlen(value)+1);
fflush(g_output);
}
quit();
}
strcpy(*newvalue,value);
return 0;
}
char *find(const char *name)
{
int v=SortedStringList<struct define>::find(name);
if (v==-1)
{
return NULL;
}
return ((struct define*)gr.get())[v].value;
}
// returns 0 on success, 1 otherwise
int del(const char *str)
{
int pos=SortedStringList<struct define>::find(str);
if (pos==-1) return 1;
struct define *db=(struct define *)gr.get();
free(db[pos].value);
delbypos(pos);
return 0;
}
int getnum()
{
return gr.getlen()/sizeof(define);
}
char *getname(int num)
{
if ((unsigned int)getnum() <= (unsigned int)num)
return 0;
return ((struct define*)gr.get())[num].name;
}
char *getvalue(int num)
{
if ((unsigned int)getnum() <= (unsigned int)num)
return 0;
return ((struct define*)gr.get())[num].value;
}
};
struct string_t {
int name;
};
class FastStringList : public SortedStringListND<struct string_t>
{
public:
FastStringList() { }
~FastStringList() { }
int add(const char *name, int case_sensitive=0)
{
int pos = SortedStringListND<struct string_t>::add(name, case_sensitive);
if (pos == -1) return -1;
return ((struct string_t*)gr.get())[pos].name;
}
char *get()
{
return (char*)strings.get();
}
int getlen()
{
return strings.getlen();
}
int getnum()
{
return gr.getlen()/sizeof(struct string_t);
}
};
class MMapFile : public IMMap
{
public:
MMapFile()
{
m_hFile = INVALID_HANDLE_VALUE;
m_hFileMap = NULL;
m_pView = NULL;
m_iSize = 0;
m_bReadOnly = FALSE;
m_bTempHandle = FALSE;
if (!m_iAllocationGranularity)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
m_iAllocationGranularity = (int) si.dwAllocationGranularity;
}
}
~MMapFile()
{
clear();
}
void clear()
{
release();
if (m_hFileMap)
CloseHandle(m_hFileMap);
if (m_bTempHandle && m_hFile)
CloseHandle(m_hFile);
m_hFileMap = 0;
}
void setro(BOOL bRO)
{
m_bReadOnly = bRO;
}
int setfile(HANDLE hFile, DWORD dwSize)
{
release();
if (m_hFileMap)
CloseHandle(m_hFileMap);
if (m_bTempHandle && m_hFile)
CloseHandle(m_hFile);
m_hFileMap = 0;
m_hFile = hFile;
m_bTempHandle = FALSE;
if (m_hFile == INVALID_HANDLE_VALUE)
return 0;
m_iSize = (int) dwSize;
if (m_iSize <= 0)
return 0;
m_hFileMap = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, m_iSize, NULL);
if (!m_hFileMap)
return 0;
m_bReadOnly = TRUE;
return 1;
}
void resize(int newsize)
{
release();
if (newsize > m_iSize)
{
if (m_hFileMap)
CloseHandle(m_hFileMap);
m_hFileMap = 0;
m_iSize = newsize;
if (m_hFile == INVALID_HANDLE_VALUE)
{
char buf[MAX_PATH], buf2[MAX_PATH];
GetTempPath(MAX_PATH, buf);
GetTempFileName(buf, "nsd", 0, buf2);
m_hFile = CreateFile(
buf2,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
m_bTempHandle = TRUE;
}
if (m_hFile != INVALID_HANDLE_VALUE)
{
m_hFileMap = CreateFileMapping(
m_hFile,
NULL,
m_bReadOnly ? PAGE_READONLY : PAGE_READWRITE,
0,
m_iSize,
NULL
);
}
if (!m_hFileMap)
{
extern FILE *g_output;
extern void quit(); extern int g_display_errors;
if (g_display_errors)
{
fprintf(g_output,"\nInternal compiler error #12345: error creating mmap the size of %d.\n", m_iSize);
fflush(g_output);
}
quit();
}
}
}
int getsize()
{
return m_iSize;
}
void *get(int offset, int size)
{
if (m_pView)
release();
if (!m_iSize || offset + size > m_iSize)
{
extern FILE *g_output;
extern void quit(); extern int g_display_errors;
if (g_display_errors)
{
fprintf(g_output,"\nInternal compiler error #12345: error mmapping file (%d, %d) is out of range.\n", offset, size);
fflush(g_output);
}
quit();
}
// fix offset
int alignedoffset = offset - (offset % m_iAllocationGranularity);
size += offset - alignedoffset;
m_pView = MapViewOfFile(m_hFileMap, m_bReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE, 0, alignedoffset, size);
if (!m_pView)
{
extern FILE *g_output;
extern void quit(); extern int g_display_errors;
if (g_display_errors)
{
fprintf(g_output,"\nInternal compiler error #12345: error mmapping datablock to %d.\n", size);
fflush(g_output);
}
quit();
}
return (void *)((char *)m_pView + offset - alignedoffset);
}
void *getmore(int offset, int size)
{
void *pView;
void *pViewBackup = m_pView;
m_pView = 0;
pView = get(offset, size);
m_pView = pViewBackup;
return pView;
}
void release()
{
if (!m_pView)
return;
UnmapViewOfFile(m_pView);
m_pView = NULL;
}
void release(void *pView)
{
if (!pView)
return;
UnmapViewOfFile(pView);
}
void flush(int num)
{
if (m_pView)
FlushViewOfFile(m_pView, num);
}
private:
HANDLE m_hFile, m_hFileMap;
void *m_pView;
int m_iSize;
BOOL m_bReadOnly;
BOOL m_bTempHandle;
static int m_iAllocationGranularity;
};
class MMapFake : public IMMap
{
public:
MMapFake()
{
m_pMem = NULL;
m_iSize = 0;
}
void set(const char *pMem, int iSize)
{
m_pMem = pMem;
m_iSize = iSize;
}
int getsize()
{
return m_iSize;
}
void *get(int offset, int size)
{
if (offset + size > m_iSize)
return NULL;
return (void *)(m_pMem + offset);
}
void *getmore(int offset, int size)
{
return get(offset, size);
}
void resize(int n) {}
void release() {}
void release(void *p) {}
void clear() {}
void setro(BOOL b) {}
void flush(BOOL b) {}
private:
const char *m_pMem;
int m_iSize;
};
class MMapBuf : public IGrowBuf, public IMMap
{
public:
MMapBuf()
{
m_gb_u=0;
m_alloc=m_used=0;
}
~MMapBuf()
{
m_fm.release();
}
int add(const void *data, int len)
{
if (len <= 0) return 0;
resize(getlen() + len);
memcpy((char*)get(getlen() - len, len), data, len);
return getlen() - len;
}
void setro(BOOL bRO)
{
m_fm.setro(bRO);
}
void resize(int newlen)
{
if (!m_gb_u && newlen < (16 << 20)) // still in db mode
{
m_gb.resize(newlen);
return;
}
// not in db mode
m_gb_u = 1;
m_used = newlen;
if (newlen > m_alloc)
{
m_alloc = newlen + (16 << 20); // add 16mb to top of mapping
m_fm.resize(m_alloc);
if (m_gb.getlen())
{
memcpy(m_fm.get(0, m_gb.getlen()), m_gb.get(), m_gb.getlen());
m_fm.flush(m_gb.getlen());
m_fm.release();
m_gb.resize(0);
}
}
}
int getsize()
{
if (m_gb_u)
return m_fm.getsize();
return m_gb.getlen();
}
int getlen()
{
if (m_gb_u)
return m_used;
return m_gb.getlen();
}
void *get()
{
return get(0, m_alloc);
}
void *get(int offset, int size)
{
if (m_gb_u)
return m_fm.get(offset, size);
return (void *) ((char *) m_gb.get() + offset);
}
void *getmore(int offset, int size)
{
if (m_gb_u)
return m_fm.getmore(offset, size);
return (void *) ((char *) m_gb.get() + offset);
}
void release()
{
if (m_gb_u)
m_fm.release();
}
void release(void *pView)
{
if (m_gb_u)
m_fm.release(pView);
}
void clear()
{
if (m_gb_u)
m_fm.clear();
}
void flush(int num)
{
if (m_gb_u)
m_fm.flush(num);
}
private:
GrowBuf m_gb;
MMapFile m_fm;
int m_gb_u;
int m_alloc, m_used;
};
#endif//_STRLIST_H_