From 1e77b2ef58103b36220517d751a5324dddf95d41 Mon Sep 17 00:00:00 2001 From: Shawwwn Date: Fri, 16 May 2014 01:33:14 -0700 Subject: [PATCH] output correct filename --- H2OExtractor.dsp | 82 ++- Source/Archive.cpp | 150 ++++- Source/Archive.h | 34 +- Source/ArchiveCompressedStringChunk.h | 12 + Source/ArchiveCompressedStringDesc.h | 13 + Source/ArchiveDirectoryNameChunk.h | 11 + Source/ArchiveDirectoryNameDesc.h | 8 +- Source/ArchiveFileName.cpp | 2 - Source/ArchiveFileName.h | 12 - Source/ArchiveFileNameChunk.h | 7 +- Source/ArchiveFileNameDesc.h | 8 +- Source/ArchiveHeader.h | 2 +- Source/H2OExtractor.cpp | 3 +- Source/H2OExtractor.h | 4 + Source/StringUtils.cpp | 20 - Source/StringUtils.h | 9 - Source/{ => Utils}/DebugUtils.cpp | 0 Source/{ => Utils}/DebugUtils.h | 2 +- Source/{ => Utils}/FileUtils.cpp | 2 +- Source/{ => Utils}/FileUtils.h | 7 +- Source/Utils/StringUtils.cpp | 41 ++ Source/Utils/StringUtils.h | 11 + Source/Utils/blast/README.md | 4 + Source/Utils/blast/blast.c | 444 ++++++++++++++ Source/Utils/blast/blast.h | 71 +++ Source/Utils/blast/blastHandler.c | 86 +++ Source/Utils/blast/blastHandler.h | 53 ++ Source/Utils/blast/crc32.c | 83 +++ Source/Utils/blast/crc32.h | 8 + Source/Utils/blast/types.h | 9 + Source/Utils/dirent/ChangeLog | 108 ++++ Source/Utils/dirent/README.md | 4 + Source/Utils/dirent/dirent.h | 838 ++++++++++++++++++++++++++ 33 files changed, 2038 insertions(+), 110 deletions(-) create mode 100644 Source/ArchiveCompressedStringChunk.h create mode 100644 Source/ArchiveCompressedStringDesc.h create mode 100644 Source/ArchiveDirectoryNameChunk.h delete mode 100644 Source/ArchiveFileName.cpp delete mode 100644 Source/ArchiveFileName.h delete mode 100644 Source/StringUtils.cpp delete mode 100644 Source/StringUtils.h rename Source/{ => Utils}/DebugUtils.cpp (100%) rename Source/{ => Utils}/DebugUtils.h (95%) rename Source/{ => Utils}/FileUtils.cpp (99%) rename Source/{ => Utils}/FileUtils.h (62%) create mode 100644 Source/Utils/StringUtils.cpp create mode 100644 Source/Utils/StringUtils.h create mode 100644 Source/Utils/blast/README.md create mode 100644 Source/Utils/blast/blast.c create mode 100644 Source/Utils/blast/blast.h create mode 100644 Source/Utils/blast/blastHandler.c create mode 100644 Source/Utils/blast/blastHandler.h create mode 100644 Source/Utils/blast/crc32.c create mode 100644 Source/Utils/blast/crc32.h create mode 100644 Source/Utils/blast/types.h create mode 100644 Source/Utils/dirent/ChangeLog create mode 100644 Source/Utils/dirent/README.md create mode 100644 Source/Utils/dirent/dirent.h diff --git a/H2OExtractor.dsp b/H2OExtractor.dsp index 3cd8b80..700e5ac 100644 --- a/H2OExtractor.dsp +++ b/H2OExtractor.dsp @@ -104,15 +104,23 @@ SOURCE=.\Source\ArchiveComment.h # End Source File # Begin Source File -SOURCE=.\Source\ArchiveDirectoryNameDesc.h +SOURCE=.\Source\ArchiveCompressedStringChunk.h # End Source File # Begin Source File -SOURCE=.\Source\ArchiveFile.h +SOURCE=.\Source\ArchiveCompressedStringDesc.h # End Source File # Begin Source File -SOURCE=.\Source\ArchiveFileName.h +SOURCE=.\Source\ArchiveDirectoryNameChunk.h +# End Source File +# Begin Source File + +SOURCE=.\Source\ArchiveDirectoryNameDesc.h +# End Source File +# Begin Source File + +SOURCE=.\Source\ArchiveFile.h # End Source File # Begin Source File @@ -144,10 +152,6 @@ SOURCE=.\Source\ArchiveFile.cpp # End Source File # Begin Source File -SOURCE=.\Source\ArchiveFileName.cpp -# End Source File -# Begin Source File - SOURCE=.\Source\ArchiveFileNameChunk.cpp # End Source File # Begin Source File @@ -175,29 +179,81 @@ SOURCE=.\Source\H2OExtractor.h # Begin Group "Utils" # PROP Default_Filter "" +# Begin Group "Blast" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Source\Utils\Blast\blast.c +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\Blast\blast.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\Blast\blastHandler.c +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\Blast\blastHandler.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\Blast\crc32.c +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\Blast\crc32.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\Blast\README.md +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\Blast\types.h +# End Source File +# End Group +# Begin Group "dirent" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Source\Utils\dirent\ChangeLog +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\dirent\dirent.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Utils\dirent\README.md +# End Source File +# End Group # Begin Source File -SOURCE=.\Source\DebugUtils.cpp +SOURCE=.\Source\Utils\DebugUtils.cpp # End Source File # Begin Source File -SOURCE=.\Source\DebugUtils.h +SOURCE=.\Source\Utils\DebugUtils.h # End Source File # Begin Source File -SOURCE=.\Source\FileUtils.cpp +SOURCE=.\Source\Utils\FileUtils.cpp # End Source File # Begin Source File -SOURCE=.\Source\FileUtils.h +SOURCE=.\Source\Utils\FileUtils.h # End Source File # Begin Source File -SOURCE=.\Source\StringUtils.cpp +SOURCE=.\Source\Utils\StringUtils.cpp # End Source File # Begin Source File -SOURCE=.\Source\StringUtils.h +SOURCE=.\Source\Utils\StringUtils.h # End Source File # Begin Source File diff --git a/Source/Archive.cpp b/Source/Archive.cpp index 8fee942..247bf51 100644 --- a/Source/Archive.cpp +++ b/Source/Archive.cpp @@ -15,9 +15,9 @@ Archive::Archive(char* szFilePath) Archive::~Archive() { close(); - delete[] m_aDirectoryParents; - delete[] m_pFileNameChunk; - delete[] m_pDirectoryNameChunk; + delete[] m_arrDirectoryParents; + delete[] m_pCompressedFileNameChunk; + delete[] m_pCompressedDirectoryNameChunk; delete[] m_Comment.szComments; } @@ -72,9 +72,10 @@ uint64_t Archive::readFileList(uint64_t streamPos) for (int i=0; i ", *(m_aDirectoryParents), ""); - } + #ifdef H2O_PRINT_DIR_INHEIRTANCY + for (int i=0; i ", *(m_arrDirectoryParents), ""); + } #endif +#endif return m_hH2O.tellg(); } +bool Archive::parseStringChunk(ArchiveCompressedStringDesc& desc, ArchiveCompressedStringChunk& chunk, + char*& pCompressedBuffer, std::vector& outputVector) +{ + // Decompress + char* pDecompressedBuffer = new char[desc.RawSize]; + bool result = (bool)runblast_mem2mem(pCompressedBuffer, desc.RawSize, pDecompressedBuffer, *(uint32_t*)(desc.CRC32)); + + // Serialize the header of the chunk + memcpy(&chunk, pDecompressedBuffer, sizeof(chunk)); + + // Serialize the file names + outputVector.clear(); + uint32_t length = 0; + uint32_t offest = sizeof(chunk); + while (offest < desc.RawSize) + { + wchar_t* wszStartingPos = (wchar_t*)&pDecompressedBuffer[offest]; + length = wcslen(wszStartingPos); + if (length==0) + break; + wchar_t* wszString = new wchar_t[length]; + wcscpy(wszString, wszStartingPos); + outputVector.push_back(wszString); + offest += length*sizeof(wchar_t) + 2; // plus the length of null teminator + } + delete[] pDecompressedBuffer; + return result; +} + void Archive::open(char* szFilePath) { m_hH2O.open(szFilePath, std::ifstream::binary); @@ -162,19 +194,60 @@ void Archive::open(char* szFilePath) curPos = readHeader(curPos); DB::debugLog("\nFile Section: ", "", NULL); curPos = readFileList(curPos); - - DB::debugLog("\nFileNameDesc Section: ", "", NULL); - curPos = readFileNameDesc(curPos); - curPos = readFileNameChunk(curPos); DB::debugLog("\nDirectoryNameDesc Section: ", "", NULL); curPos = readDirectoryNameDesc(curPos); curPos = readDirectoryNameChunk(curPos); + DB::debugLog("\nFileNameDesc Section: ", "", NULL); + curPos = readFileNameDesc(curPos); + curPos = readFileNameChunk(curPos); + DB::debugLog("\nDirectoryParents Section: ", "", NULL); curPos = readDirectoryParents(curPos); + + bool success; + // Parse compressed file names + success = parseStringChunk(m_FileNameDesc, m_FileNameChunk, m_pCompressedFileNameChunk, m_FileNameList); +#ifdef _DEBUG + if (success) + DB::debugLog("\nFileNameChunk - decompress: ", "Success!", ""); + else + DB::debugLog("\nFileNameChunk - decompress: ", "Fail!", ""); + DB::debugLog("FileNameCount: ", m_FileNameChunk.StringsCount, ""); + DB::debugLog("ChunkSize: ", m_FileNameChunk.ChunkSize, ""); + DB::debugLog("FileNames: ", "", ""); + #ifdef H2O_PRINT_FILE_LIST + for (int i=0; i #include "Types.h" -#include "FileUtils.h" -#include "StringUtils.h" -#include "DebugUtils.h" +#include "./Utils/FileUtils.h" +#include "./Utils/StringUtils.h" +#include "./Utils/DebugUtils.h" #include "ArchiveComment.h" #include "ArchiveHeader.h" #include "ArchiveFile.h" #include "ArchiveFileNameDesc.h" #include "ArchiveFileNameChunk.h" -#include "ArchiveFileName.h" #include "ArchiveDirectoryNameDesc.h" +#include "ArchiveDirectoryNameChunk.h" + +#include "./Utils/Blast/blastHandler.h" class Archive { @@ -34,21 +36,35 @@ class Archive uint64_t readDirectoryNameDesc(uint64_t streamPos); uint64_t readDirectoryNameChunk(uint64_t streamPos); uint64_t readDirectoryParents(uint64_t streamPos); + bool parseStringChunk(ArchiveCompressedStringDesc& desc, ArchiveCompressedStringChunk& chunk, + char*& pCompressedBuffer, std::vector& outputVector); void open(char* szFilePath); void extractByIndex(uint32_t index); void extractAll(); void close(); + // Header ArchiveComment m_Comment; ArchiveHeader m_Header; - ArchiveFileNameDesc m_FileNameDesc; + + // Directory Name ArchiveDirectoryNameDesc m_DirectoryNameDesc; - uint32_t m_DirectoryCount; - int32_t* m_aDirectoryParents; + char* m_pCompressedDirectoryNameChunk; // pointer to the raw(compressed) data from the h2o package + ArchiveDirectoryNameChunk m_DirectoryNameChunk; + std::vector m_DirectoryNameList; - char* m_pFileNameChunk; // pointer the raw(compressed) data from the h2o package - char* m_pDirectoryNameChunk; // pointer the raw(compressed) data from the h2o package + // File Name + ArchiveFileNameDesc m_FileNameDesc; + char* m_pCompressedFileNameChunk; // pointer to the raw(compressed) data from the h2o package + ArchiveFileNameChunk m_FileNameChunk; + std::vector m_FileNameList; + + // Directory Structure + uint32_t m_DirectoryCount; + int32_t* m_arrDirectoryParents; + + // File std::vector m_FileList; diff --git a/Source/ArchiveCompressedStringChunk.h b/Source/ArchiveCompressedStringChunk.h new file mode 100644 index 0000000..39c70a8 --- /dev/null +++ b/Source/ArchiveCompressedStringChunk.h @@ -0,0 +1,12 @@ +/* ArchiveCompressedStringChunk.h */ +#pragma once + +#include "Types.h" + +#pragma pack(push, 1) +struct ArchiveCompressedStringChunk +{ + uint32_t StringsCount; + uint32_t ChunkSize; +}; +#pragma pack(pop) \ No newline at end of file diff --git a/Source/ArchiveCompressedStringDesc.h b/Source/ArchiveCompressedStringDesc.h new file mode 100644 index 0000000..cae33ae --- /dev/null +++ b/Source/ArchiveCompressedStringDesc.h @@ -0,0 +1,13 @@ +/* ArchiveCompressedStringDesc.h */ +#pragma once + +#include "Types.h" + +#pragma pack(push, 1) +struct ArchiveCompressedStringDesc +{ + uint32_t CompressedSize; + uint32_t RawSize; + char CRC32[4]; +}; +#pragma pack(pop) \ No newline at end of file diff --git a/Source/ArchiveDirectoryNameChunk.h b/Source/ArchiveDirectoryNameChunk.h new file mode 100644 index 0000000..81e67d4 --- /dev/null +++ b/Source/ArchiveDirectoryNameChunk.h @@ -0,0 +1,11 @@ +/* ArchiveDirectoryNameChunk.h */ +#pragma once + +#include "ArchiveCompressedStringChunk.h" + +#pragma pack(push, 1) +struct ArchiveDirectoryNameChunk: public ArchiveCompressedStringChunk +{ + // derived struct +}; +#pragma pack(pop) \ No newline at end of file diff --git a/Source/ArchiveDirectoryNameDesc.h b/Source/ArchiveDirectoryNameDesc.h index aaf3ea7..087a64e 100644 --- a/Source/ArchiveDirectoryNameDesc.h +++ b/Source/ArchiveDirectoryNameDesc.h @@ -1,13 +1,11 @@ /* ArchiveDirectoryNameDesc.h */ #pragma once -#include "Types.h" +#include "ArchiveCompressedStringDesc.h" #pragma pack(push, 1) -struct ArchiveDirectoryNameDesc +struct ArchiveDirectoryNameDesc: public ArchiveCompressedStringDesc { - uint32_t CompressedSize; - uint32_t RawSize; - char CRC32[4]; + // derived struct }; #pragma pack(pop) \ No newline at end of file diff --git a/Source/ArchiveFileName.cpp b/Source/ArchiveFileName.cpp deleted file mode 100644 index ab5e27f..0000000 --- a/Source/ArchiveFileName.cpp +++ /dev/null @@ -1,2 +0,0 @@ -/* ArchiveFileName.cpp */ -#include "ArchiveFileName.h" diff --git a/Source/ArchiveFileName.h b/Source/ArchiveFileName.h deleted file mode 100644 index 158fb76..0000000 --- a/Source/ArchiveFileName.h +++ /dev/null @@ -1,12 +0,0 @@ -/* ArchiveFileName.h */ -#pragma once - -#include "Types.h" - -#pragma pack(push, 1) -struct ArchiveFileName -{ - char* FileName; - uint16_t NullTerminator; -}; -#pragma pack(pop) diff --git a/Source/ArchiveFileNameChunk.h b/Source/ArchiveFileNameChunk.h index ec31c12..8a9c0da 100644 --- a/Source/ArchiveFileNameChunk.h +++ b/Source/ArchiveFileNameChunk.h @@ -1,12 +1,11 @@ /* ArchiveFileNameChunk.h */ #pragma once -#include "Types.h" +#include "ArchiveCompressedStringChunk.h" #pragma pack(push, 1) -struct ArchiveFileNameChunk +struct ArchiveFileNameChunk: public ArchiveCompressedStringChunk { - uint32_t FileNameCount; - uint32_t FileNameSize; + // derived struct }; #pragma pack(pop) \ No newline at end of file diff --git a/Source/ArchiveFileNameDesc.h b/Source/ArchiveFileNameDesc.h index c6b4cbf..49eaeec 100644 --- a/Source/ArchiveFileNameDesc.h +++ b/Source/ArchiveFileNameDesc.h @@ -1,13 +1,11 @@ /* ArchiveFileNameDesc.h */ #pragma once -#include "Types.h" +#include "ArchiveCompressedStringDesc.h" #pragma pack(push, 1) -struct ArchiveFileNameDesc +struct ArchiveFileNameDesc: public ArchiveCompressedStringDesc { - uint32_t CompressedSize; - uint32_t RawSize; - char CRC32[4]; + // derived struct }; #pragma pack(pop) \ No newline at end of file diff --git a/Source/ArchiveHeader.h b/Source/ArchiveHeader.h index fedf43d..400d9b9 100644 --- a/Source/ArchiveHeader.h +++ b/Source/ArchiveHeader.h @@ -7,7 +7,7 @@ struct ArchiveHeader { uint32_t Version; - uint32_t FileCount; + uint32_t FileCount; // may not be accurate due to empty entries uint64_t CompressedSize; uint64_t RawSize; }; diff --git a/Source/H2OExtractor.cpp b/Source/H2OExtractor.cpp index 3ca2b33..69ba9f9 100644 --- a/Source/H2OExtractor.cpp +++ b/Source/H2OExtractor.cpp @@ -6,7 +6,8 @@ int main(int argc, char* argv[]) printf("H2OExtractor\n============================\n"); Archive h2o("Input.H2O"); + getchar(); DB::debugLog("\nExtracting files...", "\n", NULL); - //h2o.extractAll(); + h2o.extractAll(); return 0; } \ No newline at end of file diff --git a/Source/H2OExtractor.h b/Source/H2OExtractor.h index 5d71571..b1dfa01 100644 --- a/Source/H2OExtractor.h +++ b/Source/H2OExtractor.h @@ -6,4 +6,8 @@ #include +//#define H2O_PRINT_FILE_LIST +//#define H2O_PRINT_FILE_DESC +//#define H2O_PRINT_DIR_INHEIRTANCY + #include "Archive.h" \ No newline at end of file diff --git a/Source/StringUtils.cpp b/Source/StringUtils.cpp deleted file mode 100644 index 97a3438..0000000 --- a/Source/StringUtils.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* StringUtils.cpp */ -#include "StringUtils.h" - -// TODO: Use native char array - -void getFileName(uint32_t index, const char* postfix, char* outputBuffer) -{ - memset(outputBuffer, 0, 16); - char szIndex[8]; - itoa (index, szIndex, 10); - strcpy(outputBuffer, szIndex); - strcat(outputBuffer, postfix); -} - -void getFullPath(const char* directoryPath, char* fileName, char* outputBuffer) -{ - memset(outputBuffer, 0, 64); - strcpy(outputBuffer, directoryPath); - strcat(outputBuffer, fileName); -} \ No newline at end of file diff --git a/Source/StringUtils.h b/Source/StringUtils.h deleted file mode 100644 index 6318f6d..0000000 --- a/Source/StringUtils.h +++ /dev/null @@ -1,9 +0,0 @@ -/* StringUtils.h */ -#pragma once - -#include -#include -#include "Types.h" - -void getFileName(uint32_t index, const char* postfix, char* outputBuffer); -void getFullPath(const char* directoryPath, char* fileName, char* outputBuffer); diff --git a/Source/DebugUtils.cpp b/Source/Utils/DebugUtils.cpp similarity index 100% rename from Source/DebugUtils.cpp rename to Source/Utils/DebugUtils.cpp diff --git a/Source/DebugUtils.h b/Source/Utils/DebugUtils.h similarity index 95% rename from Source/DebugUtils.h rename to Source/Utils/DebugUtils.h index 0826c8e..c873b23 100644 --- a/Source/DebugUtils.h +++ b/Source/Utils/DebugUtils.h @@ -3,7 +3,7 @@ #include #include -#include "Types.h" +#include "../Types.h" namespace DB { void printint64(uint64_t i); diff --git a/Source/FileUtils.cpp b/Source/Utils/FileUtils.cpp similarity index 99% rename from Source/FileUtils.cpp rename to Source/Utils/FileUtils.cpp index aca3f72..e74d592 100644 --- a/Source/FileUtils.cpp +++ b/Source/Utils/FileUtils.cpp @@ -13,4 +13,4 @@ PathType checkPathType(const char* dirPath) return TYPE_FILE; } return TYPE_NOT_EXIST; -} \ No newline at end of file +} diff --git a/Source/FileUtils.h b/Source/Utils/FileUtils.h similarity index 62% rename from Source/FileUtils.h rename to Source/Utils/FileUtils.h index a37cfb8..0099fb2 100644 --- a/Source/FileUtils.h +++ b/Source/Utils/FileUtils.h @@ -4,7 +4,10 @@ #include // For access() #include // For stat() #include // For stat() -#include "Types.h" +#include + +#include "./dirent/dirent.h" +#include "../Types.h" enum PathType { TYPE_DIR, TYPE_FILE, TYPE_NOT_EXIST }; -PathType checkPathType(const char* dirPath); \ No newline at end of file +PathType checkPathType(const char* dirPath); diff --git a/Source/Utils/StringUtils.cpp b/Source/Utils/StringUtils.cpp new file mode 100644 index 0000000..ca620bc --- /dev/null +++ b/Source/Utils/StringUtils.cpp @@ -0,0 +1,41 @@ +/* StringUtils.cpp */ +#include "StringUtils.h" + +void wtoc(wchar_t *toConvert, char *str) +{ + int count = 0; + int len = wcslen(toConvert); + + for(; count < len; count++) + { + str[count] = (char) toConvert[count]; + } +} + +void ctow(char *toConvert, wchar_t *wstr) +{ + int count = 0; + int len = strlen(toConvert); + + for(; count < len; count++) + { + wstr[count] = (wchar_t) toConvert[count]; + } +} + +void getFileName(uint32_t index, char* postfix, char* outputBuffer) +{ + memset(outputBuffer, 0, 128); + char szIndex[8]; + itoa(index, szIndex, 10); + strcpy(outputBuffer, szIndex); + strcat(outputBuffer, postfix); +} + +void getFullPath(const char* directoryPath, char* fileName, char* outputBuffer) +{ + memset(outputBuffer, 0, 256); + if (strlen(directoryPath)!=0) + strcpy(outputBuffer, directoryPath); + strcat(outputBuffer, fileName); +} \ No newline at end of file diff --git a/Source/Utils/StringUtils.h b/Source/Utils/StringUtils.h new file mode 100644 index 0000000..4dcc70a --- /dev/null +++ b/Source/Utils/StringUtils.h @@ -0,0 +1,11 @@ +/* StringUtils.h */ +#pragma once + +#include +#include +#include "../Types.h" + +void wtoc(wchar_t *toConvert, char *str); +void ctow(char *toConvert, wchar_t *wstr); +void getFileName(uint32_t index, char* postfix, char* outputBuffer); +void getFullPath(const char* directoryPath, char* fileName, char* outputBuffer); diff --git a/Source/Utils/blast/README.md b/Source/Utils/blast/README.md new file mode 100644 index 0000000..ad9abfa --- /dev/null +++ b/Source/Utils/blast/README.md @@ -0,0 +1,4 @@ +Blast - A PKWare Data Compression Library (aka Implode/Explode Compression) +======= + +Copyright (C) 2003 Mark Adler diff --git a/Source/Utils/blast/blast.c b/Source/Utils/blast/blast.c new file mode 100644 index 0000000..4ce697a --- /dev/null +++ b/Source/Utils/blast/blast.c @@ -0,0 +1,444 @@ +/* blast.c + * Copyright (C) 2003 Mark Adler + * For conditions of distribution and use, see copyright notice in blast.h + * version 1.1, 16 Feb 2003 + * + * blast.c decompresses data compressed by the PKWare Compression Library. + * This function provides functionality similar to the explode() function of + * the PKWare library, hence the name "blast". + * + * This decompressor is based on the excellent format description provided by + * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the + * example Ben provided in the post is incorrect. The distance 110001 should + * instead be 111000. When corrected, the example byte stream becomes: + * + * 00 04 82 24 25 8f 80 7f + * + * which decompresses to "AIAIAIAIAIAIA" (without the quotes). + */ + +/* + * Change history: + * + * 1.0 12 Feb 2003 - First version + * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "blast.h" /* prototype for blast() */ + +#define local static /* for local function definitions */ +#define MAXBITS 13 /* maximum code length */ +#define MAXWIN 4096 /* maximum window size */ + +/* input and output state */ +struct state { + /* input state */ + blast_in infun; /* input function provided by user */ + void *inhow; /* opaque information passed to infun() */ + unsigned char *in; /* next input location */ + unsigned left; /* available input at in */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; + + /* output state */ + blast_out outfun; /* output function provided by user */ + void *outhow; /* opaque information passed to outfun() */ + unsigned next; /* index of next write location in out[] */ + int first; /* true to check distances (for first 4K) */ + unsigned char out[MAXWIN]; /* output buffer and sliding window */ +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + int val; /* bit accumulator */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */ + s->left--; + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = val >> need; + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return val & ((1 << need) - 1); +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -9 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. + * + * - The first code for the shortest length is all ones. Subsequent codes of + * the same length are simply integer decrements of the previous code. When + * moving up a length, a one bit is appended to the code. For a complete + * code, the last code of the longest length will be all zeros. To support + * this ordering, the bits pulled during decoding are inverted to apply the + * more "natural" ordering starting with all zeros and incrementing. + */ +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= (bitbuf & 1) ^ 1; /* invert code */ + bitbuf >>= 1; + count = *next++; + if (code < first + count) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) break; + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + bitbuf = *(s->in)++; + s->left--; + if (left > 8) left = 8; + } + return -9; /* ran out of codes */ +} + +/* + * Given a list of repeated code lengths rep[0..n-1], where each byte is a + * count (high four bits + 1) and a code length (low four bits), generate the + * list of code lengths. This compaction reduces the size of the object code. + * Then given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + */ +local int construct(struct huffman *h, const unsigned char *rep, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + short length[256]; /* code lengths */ + + /* convert compact repeat counts into symbol bit length list */ + symbol = 0; + do { + len = *rep++; + left = (len >> 4) + 1; + len &= 15; + do { + length[symbol++] = len; + } while (--left); + } while (--n); + n = symbol; + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode PKWare Compression Library stream. + * + * Format notes: + * + * - First byte is 0 if literals are uncoded or 1 if they are coded. Second + * byte is 4, 5, or 6 for the number of extra bits in the distance code. + * This is the base-2 logarithm of the dictionary size minus six. + * + * - Compressed data is a combination of literals and length/distance pairs + * terminated by an end code. Literals are either Huffman coded or + * uncoded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - A bit preceding a literal or length/distance pair indicates which comes + * next, 0 for literals, 1 for length/distance. + * + * - If literals are uncoded, then the next eight bits are the literal, in the + * normal bit order in th stream, i.e. no bit-reversal is needed. Similarly, + * no bit reversal is needed for either the length extra bits or the distance + * extra bits. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 518 + * simply copies the last byte 518 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. + */ +local int decomp(struct state *s) +{ + int lit; /* true if literals are coded */ + int dict; /* log2(dictionary size) - 6 */ + int symbol; /* decoded symbol, extra bits for distance */ + int len; /* length for copy */ + int dist; /* distance for copy */ + int copy; /* copy counter */ + unsigned char *from, *to; /* copy pointers */ + static int virgin = 1; /* build tables once */ + static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */ + static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */ + static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */ + static struct huffman litcode = {litcnt, litsym}; /* length code */ + static struct huffman lencode = {lencnt, lensym}; /* length code */ + static struct huffman distcode = {distcnt, distsym};/* distance code */ + /* bit lengths of literal codes */ + static const unsigned char litlen[] = { + 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8, + 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, + 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, + 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, + 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45, + 44, 173}; + /* bit lengths of length codes 0..15 */ + static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23}; + /* bit lengths of distance codes 0..63 */ + static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248}; + static const short base[16] = { /* base for length codes */ + 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264}; + static const char extra[16] = { /* extra bits for length codes */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}; + + /* set up decoding tables (once--might not be thread-safe) */ + if (virgin) { + construct(&litcode, litlen, sizeof(litlen)); + construct(&lencode, lenlen, sizeof(lenlen)); + construct(&distcode, distlen, sizeof(distlen)); + virgin = 0; + } + + /* read header */ + lit = bits(s, 8); + if (lit > 1) return -1; + dict = bits(s, 8); + if (dict < 4 || dict > 6) return -2; + + /* decode literals and length/distance pairs */ + do { + if (bits(s, 1)) { + /* get length */ + symbol = decode(s, &lencode); + len = base[symbol] + bits(s, extra[symbol]); + if (len == 519) break; /* end code */ + + /* get distance */ + symbol = len == 2 ? 2 : dict; + dist = decode(s, &distcode) << symbol; + dist += bits(s, symbol); + dist++; + if (s->first && dist > s->next) + return -3; /* distance too far back */ + + /* copy length bytes from distance bytes back */ + do { + to = s->out + s->next; + from = to - dist; + copy = MAXWIN; + if (s->next < dist) { + from += copy; + copy = dist; + } + copy -= s->next; + if (copy > len) copy = len; + len -= copy; + s->next += copy; + do { + *to++ = *from++; + } while (--copy); + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } while (len != 0); + } + else { + /* get literal and write it */ + symbol = lit ? decode(s, &litcode) : bits(s, 8); + s->out[s->next++] = symbol; + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } + } while (1); + return 0; +} + +/* See comments in blast.h */ +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow) +{ + struct state s; /* input/output state */ + int err; /* return value */ + + /* initialize input state */ + s.infun = infun; + s.inhow = inhow; + s.left = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* initialize output state */ + s.outfun = outfun; + s.outhow = outhow; + s.next = 0; + s.first = 1; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ + err = 2; /* then skip decomp(), return error */ + else + err = decomp(&s); /* decompress */ + + /* write any leftover output and update the error code if needed */ + if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0) + err = 1; + return err; +} + +#ifdef TEST +/* Example of how to use blast() */ +#include +#include + +#define CHUNK 16384 + +local unsigned inf(void *how, unsigned char **buf) +{ + static unsigned char hold[CHUNK]; + + *buf = hold; + return fread(hold, 1, CHUNK, (FILE *)how); +} + +local int outf(void *how, unsigned char *buf, unsigned len) +{ + return fwrite(buf, 1, len, (FILE *)how) != len; +} + +/* Decompress a PKWare Compression Library stream from stdin to stdout */ +int main(void) +{ + int ret, n; + + /* decompress to stdout */ + ret = blast(inf, stdin, outf, stdout); + if (ret != 0) fprintf(stderr, "blast error: %d\n", ret); + + /* see if there are any leftover bytes */ + n = 0; + while (getchar() != EOF) n++; + if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n); + + /* return blast() error code */ + return ret; +} +#endif diff --git a/Source/Utils/blast/blast.h b/Source/Utils/blast/blast.h new file mode 100644 index 0000000..ce9e541 --- /dev/null +++ b/Source/Utils/blast/blast.h @@ -0,0 +1,71 @@ +/* blast.h -- interface for blast.c + Copyright (C) 2003 Mark Adler + version 1.1, 16 Feb 2003 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * blast() decompresses the PKWare Data Compression Library (DCL) compressed + * format. It provides the same functionality as the explode() function in + * that library. (Note: PKWare overused the "implode" verb, and the format + * used by their library implode() function is completely different and + * incompatible with the implode compression method supported by PKZIP.) + */ + + +typedef unsigned (*blast_in)(void *how, unsigned char **buf); +typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len); +/* Definitions for input/output functions passed to blast(). See below for + * what the provided functions need to do. + */ + + +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow); +/* Decompress input to output using the provided infun() and outfun() calls. + * On success, the return value of blast() is zero. If there is an error in + * the source data, i.e. it is not in the proper format, then a negative value + * is returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. + * + * The input function is invoked: len = infun(how, &buf), where buf is set by + * infun() to point to the input buffer, and infun() returns the number of + * available bytes there. If infun() returns zero, then blast() returns with + * an input error. (blast() only asks for input if it needs it.) inhow is for + * use by the application to pass an input descriptor to infun(), if desired. + * + * The output function is invoked: err = outfun(how, buf, len), where the bytes + * to be written are buf[0..len-1]. If err is not zero, then blast() returns + * with an output error. outfun() is always called with len <= 4096. outhow + * is for use by the application to pass an output descriptor to outfun(), if + * desired. + * + * The return codes are: + * + * 2: ran out of input before completing decompression + * 1: output error before completing decompression + * 0: successful decompression + * -1: literal flag not zero or one + * -2: dictionary size not in 4..6 + * -3: distance is too far back + * + * At the bottom of blast.c is an example program that uses blast() that can be + * compiled to produce a command-line decompression filter by defining TEST. + */ diff --git a/Source/Utils/blast/blastHandler.c b/Source/Utils/blast/blastHandler.c new file mode 100644 index 0000000..d8bc57d --- /dev/null +++ b/Source/Utils/blast/blastHandler.c @@ -0,0 +1,86 @@ +/* blastHandler.c */ +#include "blastHandler.h" + +unsigned fileblastin(void *how, unsigned char **buf) { + struct blastprogress_t *p = (struct blastprogress_t*)how; + uint32 n = p->inbytesavail - p->inbytesread; + if (n > p->bufsize) + n = p->bufsize; + n = fread(p->buffer, 1, n, p->infile); + p->inbytesread += n; + *buf = p->buffer; + return n; +} + +int fileblastout(void *how, unsigned char *buf, unsigned len) { + struct blastprogress_t *p = (struct blastprogress_t*)how; + int n = fwrite(buf, 1, len, p->outfile); + p->outbyteswritten += n; + p->checksum = crc32(buf, len, p->checksum); + return 0; +} + +unsigned memblastin(void* how, unsigned char** buf) { + struct blastprogress_t *p = (struct blastprogress_t*)how; + *buf = p->inbuffer; + p->inbytesread += p->inbytesavail; + return p->inbytesavail; +} + +int memblastout(void* how, unsigned char* buf, unsigned len) { + struct blastprogress_t *p = (struct blastprogress_t*)how; + memcpy(p->outbuffer + p->outbyteswritten, buf, (size_t)len); + p->outbyteswritten += len; + p->checksum = crc32(buf, len, p->checksum); + return 0; +} + +int runblast(struct blastprogress_t *p, blast_in infun, blast_out outfun, uint32 expected_checksum) { + blast(infun, (void*)p, outfun, (void*)p); + p->checksum = ~p->checksum; + return (p->checksum == expected_checksum); +} + +int runblast_mem2mem(void* in, uint32 insize, void* out, uint32 expected_checksum) { + struct blastprogress_t p; + p.inbytesavail = insize; + p.inbytesread = 0; + p.inbuffer = in; + p.checksum = CRC32_INITIAL_VALUE; + p.outbyteswritten = 0; + p.outbuffer = out; + return runblast(&p, memblastin, memblastout, expected_checksum); +} + +int runblast_file2mem(FILE* infile, uint32 insize, void* out, uint32 expected_checksum) { + struct blastprogress_t p; + int val; + p.inbytesavail = insize; + p.inbytesread = 0; + p.infile = infile; + p.bufsize = BATCH_SIZE; + p.buffer = (uint8*)malloc(p.bufsize); + p.checksum = CRC32_INITIAL_VALUE; + p.outbyteswritten = 0; + p.outbuffer = out; + + val = runblast(&p, fileblastin, memblastout, expected_checksum); + free(p.buffer); + return val; +} + +int runblast_file2file(FILE* infile, uint32 insize, FILE* outfile, uint32 expected_checksum) { + struct blastprogress_t p; + int val; + p.inbytesavail = insize; + p.inbytesread = 0; + p.infile = infile; + p.bufsize = BATCH_SIZE; + p.buffer = (uint8*)malloc(p.bufsize); + p.checksum = CRC32_INITIAL_VALUE; + p.outbyteswritten = 0; + p.outfile = outfile; + val = runblast(&p, fileblastin, fileblastout, expected_checksum); + free(p.buffer); + return val; +} diff --git a/Source/Utils/blast/blastHandler.h b/Source/Utils/blast/blastHandler.h new file mode 100644 index 0000000..d0eec6a --- /dev/null +++ b/Source/Utils/blast/blastHandler.h @@ -0,0 +1,53 @@ +/* blastHandler.h -- A wrapper for the blast library */ +#ifndef BLAST_HANDLER_H_ +#define BLAST_HANDLER_H_ + +#include +#include +#include +#include "types.h" +#include "crc32.h" +#include "blast.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BATCH_SIZE 65536 + +struct blastprogress_t { + uint32 inbytesavail; + uint32 inbytesread; + uint8 *inbuffer; + FILE *infile; + + uint8 *buffer; + uint32 bufsize; + uint32 checksum; + + uint32 outbyteswritten; + uint8 *outbuffer; + FILE *outfile; +}; + +extern unsigned fileblastin(void *how, unsigned char **buf); + +extern int fileblastout(void *how, unsigned char *buf, unsigned len); + +extern unsigned memblastin(void* how, unsigned char** buf); + +extern int memblastout(void* how, unsigned char* buf, unsigned len); + +extern int runblast(struct blastprogress_t *p, blast_in infun, blast_out outfun, uint32 expected_checksum); + +extern int runblast_mem2mem(void* in, uint32 insize, void* out, uint32 expected_checksum); + +extern int runblast_file2mem(FILE* infile, uint32 insize, void* out, uint32 expected_checksum); + +extern int runblast_file2file(FILE* infile, uint32 insize, FILE* outfile, uint32 expected_checksum); + +#ifdef __cplusplus +} +#endif + +#endif /*BLAST_HANDLER_H_*/ \ No newline at end of file diff --git a/Source/Utils/blast/crc32.c b/Source/Utils/blast/crc32.c new file mode 100644 index 0000000..4ba14b5 --- /dev/null +++ b/Source/Utils/blast/crc32.c @@ -0,0 +1,83 @@ +#include "types.h" + +static uint32 table[256] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; + +static __inline uint32 calc(uint8 byte, uint32 checksum) { + return ((checksum) >> 8) ^ table[(byte) ^ ((checksum) & 0x000000FF)]; +} + +uint32 crc32(uint8 *buffer, uint32 len, uint32 checksum) { + + while (len--) + checksum = calc(*buffer++, checksum); + return checksum; +} diff --git a/Source/Utils/blast/crc32.h b/Source/Utils/blast/crc32.h new file mode 100644 index 0000000..acb53fb --- /dev/null +++ b/Source/Utils/blast/crc32.h @@ -0,0 +1,8 @@ +#ifndef CRC32_H_ +#define CRC32_H_ + +#define CRC32_INITIAL_VALUE 0xFFFFFFFF + +uint32 crc32(uint8 *buffer, uint32 len, uint32 checksum); + +#endif /*CRC32_H_*/ diff --git a/Source/Utils/blast/types.h b/Source/Utils/blast/types.h new file mode 100644 index 0000000..80ed5ec --- /dev/null +++ b/Source/Utils/blast/types.h @@ -0,0 +1,9 @@ +#ifndef TYPES_H_ +#define TYPES_H_ + +typedef unsigned int uint32; +typedef signed int int32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +#endif /*TYPES_H_*/ diff --git a/Source/Utils/dirent/ChangeLog b/Source/Utils/dirent/ChangeLog new file mode 100644 index 0000000..bb63728 --- /dev/null +++ b/Source/Utils/dirent/ChangeLog @@ -0,0 +1,108 @@ +2014-04-07 Toni Rönkkö + + * Version 1.20.1: the zip file from the previous version did not open + correctly with Microsoft's compressed folders. Thanks to Alexandre + for info! + +2014-03-17 Toni Ronkko + + * Version 1.20: dirent.h compiles correctly in 64-bit architecture. + Thanks to Aaron Simmons! + +2014-03-03 Toni Ronkko + + * Version 1.13.2: define DT_LNK for compatibility with Unix + programs. Thanks to Joel Bruick for suggestion! + +2013-01-27 Toni Ronkko + + * Version 1.13.1: patch from Edward Berner fixes set_errno() on + Windows NT 4.0. + + * Revised wcstombs() and mbstowcs() wrappers to make sure that they do + not write past their target string. + + * PATH_MAX from windows.h includes zero terminator so there is no + need to add one extra byte to variables and structures. + +2012-12-12 Toni Ronkko + + * Version 1.13: use the traditional 8+3 file naming scheme if a file + name cannot be represented in the default ANSI code page. Now + compiles again with MSVC 6.0. Thanks to Konstantin Khomoutov for + testing. + +2012-10-01 Toni Ronkko + + * Version 1.12.1: renamed wide-character DIR structure _wDIR to + _WDIR (with capital W) in order to maintain compatibility with MingW. + +2012-09-30 Toni Ronkko + + * Version 1.12: define PATH_MAX and NAME_MAX. Added wide-character + variants _wDIR, _wdirent, _wopendir(), _wreaddir(), _wclosedir() and + _wrewinddir(). Thanks to Edgar Buerkle and Jan Nijtmans for ideas + and code. + + * Do not include windows.h. This allows dirent.h to be integrated + more easily into programs using winsock. Thanks to Fernando + Azaldegui. + +2011-03-15 Toni Ronkko + + * Version 1.11: defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0. + +2010-08-11 Toni Ronkko + + * Version 1.10: added d_type and d_namlen fields to dirent structure. + The former is especially useful for determining whether directory + entry represents a file or a directory. For more information, see + http://www.delorie.com/gnu/docs/glibc/libc_270.html + + * Improved conformance to the standards. For example, errno is now + set properly on failure and assert() is never used. Thanks to Peter + Brockam for suggestions. + + * Fixed a bug in rewinddir(): when using relative directory names, + change of working directory no longer causes rewinddir() to fail. + +2009-12-15 John Cunningham + + * Version 1.9: added rewinddir member function + +2008-01-18 Toni Ronkko + + * Version 1.8: Using FindFirstFileA and WIN32_FIND_DATAA to avoid + converting string between multi-byte and unicode representations. + This makes the code simpler and also allows the code to be compiled + under MingW. Thanks to Azriel Fasten for the suggestion. + +2007-03-04 Toni Ronkko + + * Bug fix: due to the strncpy_s() function this file only compiled in + Visual Studio 2005. Using the new string functions only when the + compiler version allows. + +2006-11-02 Toni Ronkko + + * Major update: removed support for Watcom C, MS-DOS and Turbo C to + simplify the file, updated the code to compile cleanly on Visual + Studio 2005 with both unicode and multi-byte character strings, + removed rewinddir() as it had a bug. + +2006-08-20 Toni Ronkko + + * Removed all remarks about MSVC 1.0, which is antiqued now. + Simplified comments by removing SGML tags. + +2002-05-14 Toni Ronkko + + * Embedded the function definitions directly to the header so that no + source modules need to be included in the Visual Studio project. + Removed all the dependencies to other projects so that this header + file can be used independently. + +1998-05-28 Toni Ronkko + + * First version. + diff --git a/Source/Utils/dirent/README.md b/Source/Utils/dirent/README.md new file mode 100644 index 0000000..7f560b3 --- /dev/null +++ b/Source/Utils/dirent/README.md @@ -0,0 +1,4 @@ +Dirent API for Microsoft Visual Studio +======= + +http://softagalleria.net/dirent.php \ No newline at end of file diff --git a/Source/Utils/dirent/dirent.h b/Source/Utils/dirent/dirent.h new file mode 100644 index 0000000..6f959a5 --- /dev/null +++ b/Source/Utils/dirent/dirent.h @@ -0,0 +1,838 @@ +/* + * dirent.h - dirent API for Microsoft Visual Studio + * + * Copyright (C) 2006-2012 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $ + */ +#ifndef DIRENT_H +#define DIRENT_H + +/* + * Define architecture flags so we don't need to include windows.h. + * Avoiding windows.h makes it simpler to use windows sockets in conjunction + * with dirent.h. + */ +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) +# define _X86_ +#endif +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64) +#define _AMD64_ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Indicates that d_type field is available in dirent structure */ +#define _DIRENT_HAVE_D_TYPE + +/* Indicates that d_namlen field is available in dirent structure */ +#define _DIRENT_HAVE_D_NAMLEN + +/* Entries missing from MSVC 6.0 */ +#if !defined(FILE_ATTRIBUTE_DEVICE) +# define FILE_ATTRIBUTE_DEVICE 0x40 +#endif + +/* File type and permission flags for stat() */ +#if !defined(S_IFMT) +# define S_IFMT _S_IFMT /* File type mask */ +#endif +#if !defined(S_IFDIR) +# define S_IFDIR _S_IFDIR /* Directory */ +#endif +#if !defined(S_IFCHR) +# define S_IFCHR _S_IFCHR /* Character device */ +#endif +#if !defined(S_IFFIFO) +# define S_IFFIFO _S_IFFIFO /* Pipe */ +#endif +#if !defined(S_IFREG) +# define S_IFREG _S_IFREG /* Regular file */ +#endif +#if !defined(S_IREAD) +# define S_IREAD _S_IREAD /* Read permission */ +#endif +#if !defined(S_IWRITE) +# define S_IWRITE _S_IWRITE /* Write permission */ +#endif +#if !defined(S_IEXEC) +# define S_IEXEC _S_IEXEC /* Execute permission */ +#endif +#if !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO /* Pipe */ +#endif +#if !defined(S_IFBLK) +# define S_IFBLK 0 /* Block device */ +#endif +#if !defined(S_IFLNK) +# define S_IFLNK 0 /* Link */ +#endif +#if !defined(S_IFSOCK) +# define S_IFSOCK 0 /* Socket */ +#endif + +#if defined(_MSC_VER) +# define S_IRUSR S_IREAD /* Read user */ +# define S_IWUSR S_IWRITE /* Write user */ +# define S_IXUSR 0 /* Execute user */ +# define S_IRGRP 0 /* Read group */ +# define S_IWGRP 0 /* Write group */ +# define S_IXGRP 0 /* Execute group */ +# define S_IROTH 0 /* Read others */ +# define S_IWOTH 0 /* Write others */ +# define S_IXOTH 0 /* Execute others */ +#endif + +/* Maximum length of file name */ +#if !defined(PATH_MAX) +# define PATH_MAX MAX_PATH +#endif +#if !defined(FILENAME_MAX) +# define FILENAME_MAX MAX_PATH +#endif +#if !defined(NAME_MAX) +# define NAME_MAX FILENAME_MAX +#endif + +/* File type flags for d_type */ +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK + +/* Macros for converting between st_mode and d_type */ +#define IFTODT(mode) ((mode) & S_IFMT) +#define DTTOIF(type) (type) + +/* + * File type macros. Note that block devices, sockets and links cannot be + * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are + * only defined for compatibility. These macros should always return false + * on Windows. + */ +#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) + +/* Return the exact length of d_namlen without zero terminator */ +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) + +/* Return number of bytes needed to store d_namlen */ +#define _D_ALLOC_NAMLEN(p) (PATH_MAX) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Wide-character version */ +struct _wdirent { + long d_ino; /* Always zero */ + unsigned short d_reclen; /* Structure size */ + size_t d_namlen; /* Length of name without \0 */ + int d_type; /* File type */ + wchar_t d_name[PATH_MAX]; /* File name */ +}; +typedef struct _wdirent _wdirent; + +struct _WDIR { + struct _wdirent ent; /* Current directory entry */ + WIN32_FIND_DATAW data; /* Private file data */ + int cached; /* True if data is valid */ + HANDLE handle; /* Win32 search handle */ + wchar_t *patt; /* Initial directory name */ +}; +typedef struct _WDIR _WDIR; + +static _WDIR *_wopendir (const wchar_t *dirname); +static struct _wdirent *_wreaddir (_WDIR *dirp); +static int _wclosedir (_WDIR *dirp); +static void _wrewinddir (_WDIR* dirp); + + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir + + +/* Multi-byte character versions */ +struct dirent { + long d_ino; /* Always zero */ + unsigned short d_reclen; /* Structure size */ + size_t d_namlen; /* Length of name without \0 */ + int d_type; /* File type */ + char d_name[PATH_MAX]; /* File name */ +}; +typedef struct dirent dirent; + +struct DIR { + struct dirent ent; + struct _WDIR *wdirp; +}; +typedef struct DIR DIR; + +static DIR *opendir (const char *dirname); +static struct dirent *readdir (DIR *dirp); +static int closedir (DIR *dirp); +static void rewinddir (DIR* dirp); + + +/* Internal utility functions */ +static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); +static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); + +static int dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count); + +static int dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, + const wchar_t *wcstr, + size_t count); + +static void dirent_set_errno (int error); + +/* + * Open directory stream DIRNAME for read and return a pointer to the + * internal working area that is used to retrieve individual directory + * entries. + */ +static _WDIR* +_wopendir( + const wchar_t *dirname) +{ + _WDIR *dirp = NULL; + int error; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate new _WDIR structure */ + dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); + if (dirp != NULL) { + DWORD n; + + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + + /* Compute the length of full path plus zero terminator */ + n = GetFullPathNameW (dirname, 0, NULL, NULL); + + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); + if (dirp->patt) { + + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + */ + n = GetFullPathNameW (dirname, n, dirp->patt, NULL); + if (n > 0) { + wchar_t *p; + + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + if (dirp->patt < p) { + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } + } + *p++ = '*'; + *p = '\0'; + + /* Open directory stream and retrieve the first entry */ + if (dirent_first (dirp)) { + /* Directory stream opened successfully */ + error = 0; + } else { + /* Cannot retrieve first entry */ + error = 1; + dirent_set_errno (ENOENT); + } + + } else { + /* Cannot retrieve full path name */ + dirent_set_errno (ENOENT); + error = 1; + } + + } else { + /* Cannot allocate memory for search pattern */ + error = 1; + } + + } else { + /* Cannot allocate _WDIR structure */ + error = 1; + } + + /* Clean up in case of error */ + if (error && dirp) { + _wclosedir (dirp); + dirp = NULL; + } + + return dirp; +} + +/* + * Read next directory entry. The directory entry is returned in dirent + * structure in the d_name field. Individual directory entries returned by + * this function include regular files, sub-directories, pseudo-directories + * "." and ".." as well as volume labels, hidden files and system files. + */ +static struct _wdirent* +_wreaddir( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *datap; + struct _wdirent *entp; + + /* Read next directory entry */ + datap = dirent_next (dirp); + if (datap) { + size_t n; + DWORD attr; + + /* Pointer to directory entry to return */ + entp = &dirp->ent; + + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + n = 0; + while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) { + entp->d_name[n] = datap->cFileName[n]; + n++; + } + dirp->ent.d_name[n] = 0; + + /* Length of file name excluding zero terminator */ + entp->d_namlen = n; + + /* File type */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entp->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entp->d_type = DT_DIR; + } else { + entp->d_type = DT_REG; + } + + /* Reset dummy fields */ + entp->d_ino = 0; + entp->d_reclen = sizeof (struct _wdirent); + + } else { + + /* Last directory entry read */ + entp = NULL; + + } + + return entp; +} + +/* + * Close directory stream opened by opendir() function. This invalidates the + * DIR structure as well as any directory entry read previously by + * _wreaddir(). + */ +static int +_wclosedir( + _WDIR *dirp) +{ + int ok; + if (dirp) { + + /* Release search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + } + + /* Release search pattern */ + if (dirp->patt) { + free (dirp->patt); + dirp->patt = NULL; + } + + /* Release directory structure */ + free (dirp); + ok = /*success*/0; + + } else { + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + } + return ok; +} + +/* + * Rewind directory stream such that _wreaddir() returns the very first + * file name again. + */ +static void +_wrewinddir( + _WDIR* dirp) +{ + if (dirp) { + /* Release existing search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + } + + /* Open new search handle */ + dirent_first (dirp); + } +} + +/* Get first directory entry (internal) */ +static WIN32_FIND_DATAW* +dirent_first( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *datap; + + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileW (dirp->patt, &dirp->data); + if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* a directory entry is now waiting in memory */ + datap = &dirp->data; + dirp->cached = 1; + + } else { + + /* Failed to re-open directory: no directory entry in memory */ + dirp->cached = 0; + datap = NULL; + + } + return datap; +} + +/* Get next directory entry (internal) */ +static WIN32_FIND_DATAW* +dirent_next( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *p; + + /* Get next directory entry */ + if (dirp->cached != 0) { + + /* A valid directory entry already in memory */ + p = &dirp->data; + dirp->cached = 0; + + } else if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* Get the next directory entry from stream */ + if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { + /* Got a file */ + p = &dirp->data; + } else { + /* The very last entry has been processed or an error occured */ + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + p = NULL; + } + + } else { + + /* End of directory stream reached */ + p = NULL; + + } + + return p; +} + +/* + * Open directory stream using plain old C-string. + */ +static DIR* +opendir( + const char *dirname) +{ + struct DIR *dirp; + int error; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate memory for DIR structure */ + dirp = (DIR*) malloc (sizeof (struct DIR)); + if (dirp) { + wchar_t wname[PATH_MAX]; + size_t n; + + /* Convert directory name to wide-character string */ + error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX); + if (!error) { + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir (wname); + if (dirp->wdirp) { + /* Directory stream opened */ + error = 0; + } else { + /* Failed to open directory stream */ + error = 1; + } + + } else { + /* + * Cannot convert file name to wide-character string. This + * occurs if the string contains invalid multi-byte sequences or + * the output buffer is too small to contain the resulting + * string. + */ + error = 1; + } + + } else { + /* Cannot allocate DIR structure */ + error = 1; + } + + /* Clean up in case of error */ + if (error && dirp) { + free (dirp); + dirp = NULL; + } + + return dirp; +} + +/* + * Read next directory entry. + * + * When working with text consoles, please note that file names returned by + * readdir() are represented in the default ANSI code page while any output to + * console is typically formatted on another code page. Thus, non-ASCII + * characters in file names will not usually display correctly on console. The + * problem can be fixed in two ways: (1) change the character set of console + * to 1252 using chcp utility and use Lucida Console font, or (2) use + * _cprintf function when writing to console. The _cprinf() will re-encode + * ANSI strings to the console code page so many non-ASCII characters will + * display correcly. + */ +static struct dirent* +readdir( + DIR *dirp) +{ + WIN32_FIND_DATAW *datap; + struct dirent *entp; + + /* Read next directory entry */ + datap = dirent_next (dirp->wdirp); + if (datap) { + size_t n; + int error; + + /* Attempt to convert file name to multi-byte string */ + error = dirent_wcstombs_s( + &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX); + + /* + * If the file name cannot be represented by a multi-byte string, + * then attempt to use old 8+3 file name. This allows traditional + * Unix-code to access some file names despite of unicode + * characters, although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file + * name unless the file system provides one. At least + * VirtualBox shared folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') { + error = dirent_wcstombs_s( + &n, dirp->ent.d_name, PATH_MAX, + datap->cAlternateFileName, PATH_MAX); + } + + if (!error) { + DWORD attr; + + /* Initialize directory entry for return */ + entp = &dirp->ent; + + /* Length of file name excluding zero terminator */ + entp->d_namlen = n - 1; + + /* File attributes */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entp->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entp->d_type = DT_DIR; + } else { + entp->d_type = DT_REG; + } + + /* Reset dummy fields */ + entp->d_ino = 0; + entp->d_reclen = sizeof (struct dirent); + + } else { + /* + * Cannot convert file name to multi-byte string so construct + * an errornous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entp = &dirp->ent; + entp->d_name[0] = '?'; + entp->d_name[1] = '\0'; + entp->d_namlen = 1; + entp->d_type = DT_UNKNOWN; + entp->d_ino = 0; + entp->d_reclen = 0; + } + + } else { + /* No more directory entries */ + entp = NULL; + } + + return entp; +} + +/* + * Close directory stream. + */ +static int +closedir( + DIR *dirp) +{ + int ok; + if (dirp) { + + /* Close wide-character directory stream */ + ok = _wclosedir (dirp->wdirp); + dirp->wdirp = NULL; + + /* Release multi-byte character version */ + free (dirp); + + } else { + + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + + } + return ok; +} + +/* + * Rewind directory stream to beginning. + */ +static void +rewinddir( + DIR* dirp) +{ + /* Rewind wide-character string directory stream */ + _wrewinddir (dirp->wdirp); +} + +/* Convert multi-byte string to wide character string */ +static int +dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to wide-character string (or count characters) */ + n = mbstowcs (wcstr, mbstr, sizeInWords); + if (!wcstr || n < count) { + + /* Zero-terminate output buffer */ + if (wcstr && sizeInWords) { + if (n >= sizeInWords) { + n = sizeInWords - 1; + } + wcstr[n] = 0; + } + + /* Length of resuting multi-byte string WITH zero terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + + } else { + + /* Could not convert string */ + error = 1; + + } + +#endif + + return error; +} + +/* Convert wide-character string to multi-byte string */ +static int +dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, /* max size of mbstr */ + const wchar_t *wcstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to multi-byte string (or count the number of bytes needed) */ + n = wcstombs (mbstr, wcstr, sizeInBytes); + if (!mbstr || n < count) { + + /* Zero-terminate output buffer */ + if (mbstr && sizeInBytes) { + if (n >= sizeInBytes) { + n = sizeInBytes - 1; + } + mbstr[n] = '\0'; + } + + /* Lenght of resulting multi-bytes string WITH zero-terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + + } else { + + /* Cannot convert string */ + error = 1; + + } + +#endif + + return error; +} + +/* Set errno variable */ +static void +dirent_set_errno( + int error) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 and later */ + _set_errno (error); + +#else + + /* Non-Microsoft compiler or older Microsoft compiler */ + errno = error; + +#endif +} + + +#ifdef __cplusplus +} +#endif +#endif /*DIRENT_H*/ +