/*
	Utility to scan a directory, and creates C header/source files
	for all the files it contains.
*/

#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <vector>
#include <ctype.h>
#include <time.h>

using namespace std;

typedef vector<string> StringList;

StringList sl;
char b[512];
char c[512];
float TotalKb = 0;
float TotalBytes = 0;
int TotalFiles = 0;
int cf_size;
FILE *head, *src, *dat;
	
static int WildMatch(const char* pat, const char* str)
{
   char *s, *p;
   int star = 0;

loopStart:
   for (s = (char*)str, p = (char*)pat; *s; ++s, ++p) {
      switch (*p) {
         case '?':
            if (*s == '.') goto starCheck;
            break;
         case '*':
            star = 1;
            str = s, pat = p;
            if (!*++pat) return 1;
            goto loopStart;
         default:
            if (tolower(*s) != tolower(*p))
               goto starCheck;
            break;
      } /* endswitch */
   } /* endfor */
   if (*p == '*') ++p;
   return (!*p);

starCheck:
   if (!star) return 0;
   str++;
   goto loopStart;
}

static int ReadDirectory(StringList &target, const char *ignore)
{
	DIR *d;
	struct dirent *e;
	string n;
	int ret = 0;
	
	d = opendir("./");
	if (!d) return -1;
	
	while ((e = readdir(d)) != NULL)
	{
		n = e->d_name;
		if ((n == ".") || (n == "..")) continue;
		if (ignore)
		{
			if (!WildMatch(ignore,e->d_name)) // ignore the masked types
			{
				target.push_back(n);
				ret++;
			}
		} else
		{
			target.push_back(n);
			ret++;
		}
	}
	closedir(d);
	
	return ret;
}

static void PrintStdHeaderH()
{
	fprintf(head,"/* Data Header created by dir2c utility */\n\n");
}

static void PrintStdSourceH()
{
	fprintf(src,"/* Data Source created by dir2c utility */\n\n");
}

static void PrintStdHeaderF()
{
	time_t rawtime;
 	struct tm * timeinfo;

  	time ( &rawtime );
  	timeinfo = localtime ( &rawtime );
  
	fprintf(head,"\n/* Data Header created by dir2c utility */\n");
	fprintf(head,"/* Total Files: %d, Total KB: %.0f */\n",TotalFiles, TotalKb+0.999f);
	fprintf(head,"/*\n\tGenerated on: %s */\n\n",asctime(timeinfo));
}

static void PrintStdSourceF()
{
	fprintf(src,"\n/* Data Source created by dir2c utility */\n\n");
}

	
int main(int argc, const char **argv)
{
	if (argc != 2)
	{
		printf ("Usage: dir2c <directory>\nOutputs dir_<directory>.h and dir_<directory>.c to current directory.\n");
		return 0;
	}
	
	// read all but .exe files in the target directory
	getcwd(c,512);
	chdir(argv[1]);
		ReadDirectory(sl,NULL);
	chdir(c);
	
	if (sl.size() == 0)
	{
		printf ("ERROR: Found no files to incorporate!\n");
		return 0;
	}
	
	TotalFiles = sl.size();
	
	// now dump them all into a header
	strcpy(c,argv[1]);
	char *p = c;
	while (*p)
	{
		if (*p == '.') *p = '_';
		if (*p == '/') *p = '_';
		if (*p == '\\') *p = '_';
		p++;
	}
	
	sprintf(b,"dir_%s.h",c);
	head = fopen(b,"wt");
	if (!head) { printf("Could not open output header!"); return -1; }
	sprintf(b,"dir_%s.c",c);
	src = fopen(b,"wt");
	if (!head) { printf("Could not open output source file!"); return -1; }
	
	PrintStdHeaderH();
	PrintStdSourceH();

	fprintf(head,"\nextern const unsigned int dir_%s_files;\n",c);
	fprintf(src,"\nconst unsigned int dir_%s_files = %d;\n",c, sl.size());
		
	// ok, lets start handling these files
	chdir(argv[1]);

	// first build the size index
	fprintf(head,"\nextern const unsigned int dir_%s_size[];\n",c);
	fprintf(src,"\nconst unsigned int dir_%s_size[] = {\n",c, sl.size());	
	for (int i = 0; i < sl.size(); i++)
	{
		FILE *dat = fopen(sl[i].c_str(),"rb");
		if (!dat) continue;
		
		fseek(dat,0,SEEK_END);
		cf_size = ftell(dat);
		fseek(dat,0,SEEK_SET);

		fprintf(src,"\t%d , ",cf_size);
		TotalKb += (float)cf_size / 1024.0f;
		fclose(dat);
	}
	fprintf(src,"0 };\n\n");

	// second the name index
	fprintf(head,"\nextern const char * dir_%s_name[];\n",c);
	fprintf(src,"\nconst  char * dir_%s_name[] = {\n",c, sl.size());	
	for (int i = 0; i < sl.size(); i++)
	{
		FILE *dat = fopen(sl[i].c_str(),"rb");
		if (!dat) continue;
		fclose(dat);
		
		fprintf(src,"\t\"%s\" , ",sl[i].c_str());
		fclose(dat);
	}
	fprintf(src,"0 };\n\n");

	// third the data itself
	fprintf(head,"\nextern const unsigned char * dir_%s_data[];\n",c);
	for (int i = 0; i < sl.size(); i++)
	{
		FILE *dat = fopen(sl[i].c_str(),"rb");
		if (!dat) continue;
		
		fprintf(src,"const unsigned char dir_%s_%d_data[] = {\n",c,i);

		int cv, rows = 0;
		while (1)
		{
			cv = fgetc(dat);
			if (cv == EOF) break;
			fprintf(src,"\t0x%02X, ",cv);
			rows++;
			if (rows > 15)
			{
				fprintf(src,"\n");
				rows = 0;
			}
		}		
		
		fprintf(src,"0 };\n\n");
		fclose(dat);
	}
	
	// finally, the index for the data...
	fprintf(src,"const unsigned char * dir_%s_data[] = {\n",c);
	for (int i = 0; i < sl.size(); i++)
	{
		FILE *dat = fopen(sl[i].c_str(),"rb");
		if (!dat) continue;
		fclose(dat);
		
		fprintf(src,"\tdir_%s_%d_data,\n",c,i);
	}
	fprintf(src,"\t0 };\n\n");	
		
	PrintStdHeaderF();
	PrintStdSourceF();
			
	fclose(head);
	fclose(src);
	
	return 0;
}


