bsnes/ananke/nall/zip.hpp
Tim Allen 84e98833ca Update to v091r11 release.
byuu says:

This release refines HSU1 support as a bidirectional protocol, nests SFC
manifests as "release/cartridge" and "release/information" (but release/
is not guaranteed to be finalized just yet), removes the database
integration, and adds support for ananke.

ananke represents inevitability. It's a library that, when installed,
higan can use to load files from the command-line, and also from a new
File -> Load Game menu option.

I need to change the build rules a bit for it to work on Windows (need
to make phoenix a DLL, basically), but it works now on Linux.

Right now, it only takes *.sfc file names, looks them up in the included
database, converts them to game folders, and returns the game folder
path for higan to load.

The idea is to continue expanding it to support everything we can that
I don't want in the higan core:
- load *.sfc, *.smc, *.swc, *.fig files
- remove SNES copier headers
- split apart merged firmware files
- pull in external firmware files (eg dsp1b.rom - these are staying
  merged, just as SPC7110 prg+dat are merged)
- load *.zip and *.7z archives
- prompt for selection on multi-file archives
- generate manifest files based on heuristics
- apply BPS patches

The "Load" menu option has been renamed to "Library", to represent games
in your library. I'm going to add some sort of suffix to indicate
unverified games, and use a different folder icon for those (eg
manifests built on heuristics rather than from the database.)

So basically, to future end users:
File -> Load Game will be how they play games.
Library -> (specific system) can be thought of as an infinitely-sized
    recent games list.

purify will likely become a simple stub that invokes ananke's functions.
No reason to duplicate all that code.
2012-12-26 17:46:57 +11:00

95 lines
3.5 KiB
C++

#ifndef NALL_ZIP_HPP
#define NALL_ZIP_HPP
//creates uncompressed ZIP archives
#include <nall/crc32.hpp>
#include <nall/string.hpp>
namespace nall {
struct zip {
zip(const string &filename) {
fp.open(filename, file::mode::write);
time_t currentTime = time(0);
tm *info = localtime(&currentTime);
dosTime = (info->tm_hour << 11) | (info->tm_min << 5) | (info->tm_sec >> 1);
dosDate = ((info->tm_year - 80) << 9) | ((1 + info->tm_mon) << 5) + (info->tm_mday);
}
//append path: append("path/");
//append file: append("path/file", data, size);
void append(string filename, const uint8_t *data = nullptr, unsigned size = 0u) {
filename.transform("\\", "/");
uint32_t checksum = crc32_calculate(data, size);
directory.append({filename, checksum, size, fp.offset()});
fp.writel(0x04034b50, 4); //signature
fp.writel(0x0014, 2); //minimum version (2.0)
fp.writel(0x0000, 2); //general purpose bit flags
fp.writel(0x0000, 2); //compression method (0 = uncompressed)
fp.writel(dosTime, 2);
fp.writel(dosDate, 2);
fp.writel(checksum, 4);
fp.writel(size, 4); //compressed size
fp.writel(size, 4); //uncompressed size
fp.writel(filename.length(), 2); //file name length
fp.writel(0x0000, 2); //extra field length
fp.print(filename); //file name
fp.write(data, size); //file data
}
~zip() {
//central directory
unsigned baseOffset = fp.offset();
for(auto &entry : directory) {
fp.writel(0x02014b50, 4); //signature
fp.writel(0x0014, 2); //version made by (2.0)
fp.writel(0x0014, 2); //version needed to extract (2.0)
fp.writel(0x0000, 2); //general purpose bit flags
fp.writel(0x0000, 2); //compression method (0 = uncompressed)
fp.writel(dosTime, 2);
fp.writel(dosDate, 2);
fp.writel(entry.checksum, 4);
fp.writel(entry.size, 4); //compressed size
fp.writel(entry.size, 4); //uncompressed size
fp.writel(entry.filename.length(), 2); //file name length
fp.writel(0x0000, 2); //extra field length
fp.writel(0x0000, 2); //file comment length
fp.writel(0x0000, 2); //disk number start
fp.writel(0x0000, 2); //internal file attributes
fp.writel(0x00000000, 4); //external file attributes
fp.writel(entry.offset, 4); //relative offset of file header
fp.print(entry.filename);
}
unsigned finishOffset = fp.offset();
//end of central directory
fp.writel(0x06054b50, 4); //signature
fp.writel(0x0000, 2); //number of this disk
fp.writel(0x0000, 2); //disk where central directory starts
fp.writel(directory.size(), 2); //number of central directory records on this disk
fp.writel(directory.size(), 2); //total number of central directory records
fp.writel(finishOffset - baseOffset, 4); //size of central directory
fp.writel(baseOffset, 4); //offset of central directory
fp.writel(0x0000, 2); //comment length
fp.close();
}
protected:
file fp;
uint16_t dosTime, dosDate;
struct entry_t {
string filename;
uint32_t checksum;
uint32_t size;
uint32_t offset;
};
vector<entry_t> directory;
};
}
#endif