Пример #1
0
int main(int argc, char *argv[])
{
    // this should be checked, especially in larger projects
    if(!ttvfs::checkCompat())
    {
        std::cout << "HUH? ttvfs was compiled with different options than this file!" << std::endl;
        return 1;
    }

    // Note: Here, it is really important that all files & subdirs are loaded recursively.
    // In the merge step below, only those files that already exist in the tree will be
    // accessible in their new location.
    vfs.LoadFileSysRoot(true);
    vfs.Prepare();
    
    PrintFile("myfile.txt"); // this is the default file
    PrintFile("patches/myfile.txt"); // this is the patch file

    std::cout << "-- Mounting 'patches' -> ''" << std::endl;

    // merge "patches" into root dir
    //vfs.MountExternalPath("patches"); // this works, but recreates parts of the tree
                                        // that are already existing - possibly error prone!

    vfs.Mount("patches", ""); // <-- this is the better way.
    // all files and subdirs that were in "patches" are now mirrored in "" as well.

    PrintFile("myfile.txt"); // Access the file as before -> it got replaced.

    std::cout << "-- Before mounting 'more/even_more/deep' -> 'far' (should error)" << std::endl;

    PrintFile("far/file.txt"); // not found!

    // remount a directory under a different name
    vfs.Mount("more/even_more/deep", "far");

    std::cout << "-- After mounting 'more/even_more/deep' -> 'far'" << std::endl;

    PrintFile("far/file.txt"); // ... and access this file normally

    // mount an external directory (this could be ~/.MyApp or anything)
    vfs.MountExternalPath("../ttvfs", "ext");

    ttvfs::VFSDir *ext = vfs.GetDir("ext");
    if(ext)
    {
        //VFS_GUARD(ext); // in case this would be called from multiple threads, lock this directory.

        std::cout << "Listing files in 'ext' subdir ..." << std::endl;

        unsigned int c = 0;
        ext->forEachFile(FileCallback, &c);

        std::cout << c << " files in total!" << std::endl;
    }
    
    return 0;
}
Пример #2
0
VFILE *vfopen(const char *fn, const char *mode)
{
    if (strchr(mode, 'w'))
    {
        fprintf(stderr, "FileAPI.h: File writing via VFS not yet supported!");
        return NULL;
    }

    VFILE *vf = vfs.GetFile(fn);
    if (!vf || !vf->open(mode))
        return NULL;
    ++(vf->ref); // keep the file alive until closed.
    return vf;
}
Пример #3
0
bool InStream::open(const char *fn)
{
    ttvfs::VFSFile *vf = vfs.GetFile(fn);
    if(vf)
    {
        vf->open("r");
        str((char*)vf->getBuf()); // stringstream will always make a copy
        vf->close();
        vf->dropBuf(true);
        return true;
    }
    setstate(std::ios_base::failbit);
    return false;
}
Пример #4
0
static void PrintFile(const char *fn)
{
    ttvfs::VFSFile *vf = vfs.GetFile(fn);
    std::cout << "Open file " << fn << ": ";
    if(vf)
    {
        vf->open("r"); // force text mode
        std::cout << (const char*)vf->getBuf() << std::endl;
        vf->dropBuf(true); // no longer needed
        vf->close();
    }
    else
    {
        std::cout << "FILE OPEN ERROR!" << std::endl;
    }
}
Пример #5
0
//Main program entry point
int main(int argc, char** argv)
{
    g_bProgressOverwrite = false;
    g_iNumThreads = 0;
    DWORD iTicks = GetTickCount();	//Store the starting number of milliseconds

    vfs.Prepare();

    //read in the resource names to unpack
    initResMap();
    initSoundManifest();
    parseCmdLine(argc,argv);

    if(argc < 2)
    {
        cout << "Usage: liDecompress [filename1] [filename2] ... [filenameN]" << endl;
        return 0;
    }

    for(int iArg = 1; iArg < argc; iArg++)
    {
        if(argv[iArg][0] == '-')	//Skip over commandline switches
            continue;
        cout << endl << "Unpacking resource blob file " << argv[iArg] << endl;

        FILE* f = fopen(argv[iArg], "rb");
        if(f == NULL)
        {
            cout << "Unable to open file " << argv[iArg] << endl;
            continue;
        }

        blobHeader bH;
        if(fread((void*)&bH, 1, sizeof(blobHeader), f) != sizeof(blobHeader))
        {
            cout << "Error reading number of resources in file " << argv[iArg] << endl;
            fclose(f);
            continue;
        }

        list<resourceHeader> lResourceHeaders;

        for(int i = 0; i < bH.numItems; i++)
        {
            resourceHeader rH;
            size_t sizeRead = fread((void*)&rH, 1, sizeof(resourceHeader), f);
            if(sizeRead != sizeof(resourceHeader))
            {
                cout << "Read " << sizeRead << " bytes, which differs from resource header size " << sizeof(resourceHeader) << endl;
                fclose(f);
                continue;
            }
            lResourceHeaders.push_back(rH);
        }

        //Create list file with all the files that were in this .pak
        string sPakListFilename = "";
        for(int i = strlen(argv[iArg])-1; i >= 0; i--)
        {
            if(argv[iArg][i] == '\\' ||
                    argv[iArg][i] == '/')
                break;
            sPakListFilename.insert(sPakListFilename.begin(), argv[iArg][i]);
        }
        sPakListFilename += ".filelist.txt";
        ofstream oPakList(sPakListFilename.c_str());

        //Iterate through these items, splitting them out of the file and creating new files out of each
        cout << "Extracting files..." << endl;
        for(list<resourceHeader>::iterator i = lResourceHeaders.begin(); i != lResourceHeaders.end(); i++)
        {
            ThreadConvertHelper dh;
            makeFolder(i->id);
            const wchar_t* cName = getName(i->id);
            oPakList << ws2s(cName) << endl;
            fseek(f, i->offset, SEEK_SET);
            dh.sFilename = cName;
            if(i->flags == FLAG_ZLIBCOMPRESSED)
            {
                compressedHeader cH;
                if(fread((void*)&cH, 1, sizeof(compressedHeader), f) != sizeof(compressedHeader))
                {
                    cout << "Error reading compressed header." << endl;
                    fclose(f);
                    continue;
                }

                uint32_t size = cH.compressedSizeBytes;

                uint8_t* buf = (uint8_t*)malloc(size);
                size_t sizeRead = fread((void*)buf, 1, size, f);
                if(sizeRead != size)
                {
                    cout << "Error reading compressed data. Size: " << size << " read: " << sizeRead << endl;
                    fclose(f);
                    free(buf);
                    continue;
                }
                dh.data.data = buf;
                dh.data.compressedSize = cH.compressedSizeBytes;
                dh.data.decompressedSize = cH.uncompressedSizeBytes;
                dh.bCompressed = true;
            }
            else if(i->flags == FLAG_NOCOMPRESSION)
            {
                uint8_t* buf = (uint8_t*)malloc(i->size);

                if(fread((void*)buf, 1, i->size, f) != i->size)
                {
                    cout << "Error reading non-compressed data." << endl;
                    fclose(f);
                    free(buf);
                    continue;
                }
                dh.data.data = buf;
                dh.data.compressedSize = dh.data.decompressedSize = i->size;
                dh.bCompressed = false;
            }
            else
                cout << "Invalid resource flag " << i->flags << endl;

            g_lThreadedResources.push_back(dh);

        }

        threadedDecompress();

        fclose(f);
        oPakList.close();
    }
    cout << "\rDone.                                " << endl;

    iTicks = GetTickCount() - iTicks;
    float iSeconds = (float)iTicks / 1000.0;	//Get seconds elapsed
    int iMinutes = iSeconds / 60;
    iSeconds -= iMinutes * 60;

    cout << "Time elapsed: " << iMinutes << " min, " << iSeconds << " sec" << endl;
    //system("PAUSE");

    return 0;
}
Пример #6
0
//Main program entry point
int main(int argc, char** argv)
{
	g_bProgressOverwrite = false;
	g_iNumThreads = 0;
	g_iCompressAmount = Z_DEFAULT_COMPRESSION;
	DWORD iTicks = GetTickCount();

	vfs.Prepare();
		
	//read in the resource names to pack
	initResMap();
	initSoundManifest();
	parseCmdLine(argc, argv);
	
	if(argc < 2)
	{
		cout << "Usage: liCompress [pakfile1] [pakfile2] ... [pakfileN]" << endl;
		return 0;
	}
	
	for(int iArg = 1; iArg < argc; iArg++)
	{
		if(argv[iArg][0] == '-')	//Skip over commandline switches
			continue;
		
		list<wstring> lFilenames;	//Files in this pakfile that we're going to compress
		wstring sArg = s2ws(argv[iArg]);
		size_t pos = sArg.find(TEXT(".filelist.txt"));
		if(pos != wstring::npos)
			sArg.erase(pos, wstring::npos);	//Erase a .filelist.pak extension if there is one
		cout << endl << "Packing resource blob file " << ws2s(sArg) << endl;
		
		//Determine what files to pack into this .pak file
		wstring sInfilename = sArg;
		sInfilename += TEXT(".filelist.txt");
		ifstream infile(ws2s(sInfilename).c_str());
		if(infile.fail())
		{
			cout << "Cannot open " << ws2s(sInfilename) << " to pack " << ws2s(sArg) << " Skipping..." << endl;
			continue;
		}
		
		while(!infile.fail() && !infile.eof())	//Pull in all the lines out of this file
		{
			string ss;
			getline(infile, ss);
			wstring s = s2ws(ttvfs::FixSlashes(ss));
			if(!s.length() || s == TEXT(""))
				continue;	//Ignore blank lines
			lFilenames.push_back(s);	//Add this to our list of files to package
		}
		
		threadedCompress(lFilenames);	//Compress everything
		
		//Ok, now we have all the compressed files in RAM. Stick them in the .pak file and call it a day
		if(g_pakHelping.size() != lFilenames.size())	//These should be the same
		{
			cout << "Error: size of file list: " << g_pakHelping.size() << " differs from size of files to pak: " << lFilenames.size() << endl;
			continue;
		}
		
		//Create a mini residmap.dat file and stick it into g_pakHelping to compress if we need to
		//See what IDs are known and unknown
		map<wstring, u32> mResIDs;
		map<u32, wstring> mUnknownIDs;
		for(list<wstring>::iterator i = lFilenames.begin(); i != lFilenames.end(); i++)
		{
			u32 id = getKnownResID(*i);
			if(!id)	//The ID mapping is unknown
			{
				id = hash(*i);
				mUnknownIDs[id] = toBackslashes(*i);	//Make sure we use backslashes inside a residmap.dat
			}
			mResIDs[*i] = id;
		}
		
		//If there are any unknown mappings, make our residmap.dat
		if(mUnknownIDs.size())
		{
			lFilenames.push_front(TEXT(RESIDMAP_NAME));	//Add this to the front, so it'll decompress first so we'll have all the filenames
			mResIDs[TEXT(RESIDMAP_NAME)] = RESIDMAP_ID;	//Add this to the IDs we'll compress
			createMiniResidMap(&mUnknownIDs);	//And create the file in memory
		}
		
		//Open our output pakfile for writing
		FILE* f = _wfopen(sArg.c_str(), TEXT("wb"));
		if(f == NULL)
		{
			cout << "Unable to open file " << ws2s(sArg) << " for writing. Skipping..." << endl;
			continue;
		}
		
		//Add the header
		blobHeader bh;
		bh.pakVersion = 0x01;
		bh.numItems = lFilenames.size();
		
		fwrite(&bh, 1, sizeof(blobHeader), f);
		
		//Get the starting file pos for where we (should) be writing objects to
		size_t offsetPos = sizeof(blobHeader) + (lFilenames.size() * sizeof(resourceHeader));	
		
		//Add the table of contents
		cout << "\rAdding table of contents...                " << endl;
		for(list<wstring>::iterator i = lFilenames.begin(); i != lFilenames.end(); i++)
		{
			resourceHeader rH;
			rH.id = mResIDs[*i];
			rH.flags = 0x01;
			
			rH.offset = offsetPos;	//Offset
			rH.size = g_pakHelping[*i].dataSz;
			if(g_pakHelping[*i].bCompressed)
				rH.size += sizeof(compressedHeader);	//Compressed files have a compression header also
			else
				rH.flags = 0x00;	//Set the flags to uncompressed
			
			fwrite(&rH, 1, sizeof(resourceHeader), f);	//Write this to the file
			
			offsetPos += rH.size;	//Add this size to our running tally of where we are
		}
		
		//Add actual resource data
		cout << "Adding compressed files..." << endl;
		for(list<wstring>::iterator i = lFilenames.begin(); i != lFilenames.end(); i++)
		{
			pakHelper pH = g_pakHelping[*i];
			
			//Write the compressed header only if compressed
			if(pH.bCompressed)
				fwrite(&(pH.cH), 1, sizeof(compressedHeader), f);
			
			fwrite(pH.data, 1, pH.dataSz, f);	//One pass to write this file. Simple enough.
			//Don't free the memory here, in case there's more than one .pak file with this data in it.
		}
		fclose(f);	//Done packing this .pak file
		
		//Clear memory
		for(map<wstring, pakHelper>::iterator i = g_pakHelping.begin(); i != g_pakHelping.end(); i++)
			free(i->second.data);
		g_pakHelping.clear();
	}
	
	cout << "Done." << endl;
	
	iTicks = GetTickCount() - iTicks;
	float iSeconds = (float)iTicks / 1000.0;	//Get seconds elapsed
	int iMinutes = iSeconds / 60;
	iSeconds -= iMinutes * 60;
	
	cout << "Time elapsed: " << iMinutes << " min, " << iSeconds << " sec" << endl;
	
	return 0;
}