diff --git a/examples/others/resources/main.go b/examples/others/resources/main.go index 733b82b..1a93480 100644 --- a/examples/others/resources/main.go +++ b/examples/others/resources/main.go @@ -4,6 +4,7 @@ import ( //"bytes" "github.com/gen2brain/raylib-go/raylib" + "github.com/gen2brain/raylib-go/rres" ) const numTextures = 4 @@ -28,15 +29,15 @@ func main() { //b := MustAsset("data.rres") //reader := bytes.NewReader(b) - res := raylib.LoadResource(reader, 0, nil) + res := rres.LoadResource(reader, 0, []byte("passwordpassword")) wav := raylib.LoadWaveEx(res.Data, int32(res.Param1), int32(res.Param2), int32(res.Param3), int32(res.Param4)) snd := raylib.LoadSoundFromWave(wav) raylib.UnloadWave(wav) textures := make([]raylib.Texture2D, numTextures) for i := 0; i < numTextures; i++ { - r := raylib.LoadResource(reader, i+1, nil) - image := raylib.LoadImagePro(r.Data, int32(r.Param1), int32(r.Param2), raylib.TextureFormat(r.Param3)) + r := rres.LoadResource(reader, i+1, []byte("passwordpassword")) + image := raylib.LoadImagePro(r.Data, int32(r.Param1), int32(r.Param2), raylib.PixelFormat(r.Param3)) textures[i] = raylib.LoadTextureFromImage(image) raylib.UnloadImage(image) } diff --git a/raylib/rres.go b/raylib/rres.go deleted file mode 100644 index 3043788..0000000 --- a/raylib/rres.go +++ /dev/null @@ -1,83 +0,0 @@ -package raylib - -import ( - "encoding/binary" - "io" - "os" - "unsafe" - - "github.com/gen2brain/raylib-go/rres" - "github.com/gen2brain/raylib-go/rres/rreslib" -) - -// LoadResource - Load resource from file by id -// NOTE: Returns uncompressed data with parameters, search resource by id -func LoadResource(reader io.ReadSeeker, rresID int, key []byte) (data rres.Data) { - var fileHeader rres.FileHeader - var infoHeader rres.InfoHeader - - reader.Seek(0, 0) - - // Read rres file header - err := binary.Read(reader, binary.LittleEndian, &fileHeader) - if err != nil { - TraceLog(LogWarning, err.Error()) - return - } - - // Verify "rRES" identifier - if string(fileHeader.ID[:]) != "rRES" { - TraceLog(LogWarning, "not a valid raylib resource file") - return - } - - reader.Seek(int64(unsafe.Sizeof(fileHeader)), os.SEEK_CUR) - - for i := 0; i < int(fileHeader.Count); i++ { - // Read resource info and parameters - err = binary.Read(reader, binary.LittleEndian, &infoHeader) - if err != nil { - TraceLog(LogWarning, err.Error()) - return - } - - reader.Seek(int64(unsafe.Sizeof(infoHeader)), os.SEEK_CUR) - - if int(infoHeader.ID) == rresID { - data.Type = uint32(infoHeader.DataType) - data.Param1 = infoHeader.Param1 - data.Param2 = infoHeader.Param2 - data.Param3 = infoHeader.Param3 - data.Param4 = infoHeader.Param4 - - // Read resource data block - b := make([]byte, infoHeader.DataSize) - reader.Read(b) - - // Decompress data - data.Data, err = rreslib.Decompress(b, int(infoHeader.CompType)) - if err != nil { - TraceLog(LogWarning, "[ID %d] %v", infoHeader.ID, err) - } - - // Decrypt data - data.Data, err = rreslib.Decrypt(key, data.Data, int(infoHeader.CryptoType)) - if err != nil { - TraceLog(LogWarning, "[ID %d] %v", infoHeader.ID, err) - } - - if data.Data != nil && len(data.Data) == int(infoHeader.UncompSize) { - TraceLog(LogInfo, "[ID %d] Resource data loaded successfully", infoHeader.ID) - } - } else { - // Skip required data to read next resource infoHeader - reader.Seek(int64(infoHeader.DataSize), os.SEEK_CUR) - } - } - - if data.Data == nil { - TraceLog(LogWarning, "[ID %d] Requested resource could not be found", rresID) - } - - return -} diff --git a/raylib/rres.h b/raylib/rres.h deleted file mode 100644 index 75faf64..0000000 --- a/raylib/rres.h +++ /dev/null @@ -1,483 +0,0 @@ -/********************************************************************************************** -* -* rres v1.0 - raylib resource (rRES) custom fileformat management functions -* -* CONFIGURATION: -* -* #define RREM_IMPLEMENTATION -* Generates the implementation of the library into the included file. -* If not defined, the library is in header only mode and can be included in other headers -* or source files without problems. But only ONE file should hold the implementation. -* -* DEPENDENCIES: -* tinfl - DEFLATE decompression functions -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2016-2017 Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors 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. -* -**********************************************************************************************/ - -/* -References: - RIFF file-format: http://www.johnloomis.org/cpe102/asgn/asgn1/riff.html - ZIP file-format: https://en.wikipedia.org/wiki/Zip_(file_format) - http://www.onicos.com/staff/iz/formats/zip.html - XNB file-format: http://xbox.create.msdn.com/en-US/sample/xnb_format -*/ - -#ifndef RRES_H -#define RRES_H - -#if !defined(RRES_STANDALONE) - #include "raylib.h" -#endif - -//#define RRES_STATIC -#ifdef RRES_STATIC - #define RRESDEF static // Functions just visible to module including this file -#else - #ifdef __cplusplus - #define RRESDEF extern "C" // Functions visible from other files (no name mangling of functions in C++) - #else - #define RRESDEF extern // Functions visible from other files - #endif -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define MAX_RESOURCES_SUPPORTED 256 - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Some types are required for RAYGUI_STANDALONE usage -//---------------------------------------------------------------------------------- -#if defined(RRES_STANDALONE) - // rRES data returned when reading a resource, it contains all required data for user (24 byte) - // NOTE: Using void *data pointer, so we can load to image.data, wave.data, mesh.*, (unsigned char *) - typedef struct RRESData { - unsigned int type; // Resource type (4 byte) - - unsigned int param1; // Resouce parameter 1 (4 byte) - unsigned int param2; // Resouce parameter 2 (4 byte) - unsigned int param3; // Resouce parameter 3 (4 byte) - unsigned int param4; // Resouce parameter 4 (4 byte) - - void *data; // Resource data pointer (4 byte) - } RRESData; - - // RRES type (pointer to RRESData array) - typedef struct RRESData *RRES; // Resource pointer - - // RRESData type - typedef enum { - RRES_TYPE_RAW = 0, - RRES_TYPE_IMAGE, - RRES_TYPE_WAVE, - RRES_TYPE_VERTEX, - RRES_TYPE_TEXT, - RRES_TYPE_FONT_IMAGE, - RRES_TYPE_FONT_CHARDATA, // CharInfo { int value, recX, recY, recWidth, recHeight, offsetX, offsetY, xAdvance } - RRES_TYPE_DIRECTORY - } RRESDataType; - -// Parameters information depending on resource type - -// RRES_TYPE_RAW params: -// RRES_TYPE_IMAGE params: width, height, mipmaps, format -// RRES_TYPE_WAVE params: sampleCount, sampleRate, sampleSize, channels -// RRES_TYPE_VERTEX params: vertexCount, vertexType, vertexFormat // Use masks instead? -// RRES_TYPE_TEXT params: charsCount, cultureCode -// RRES_TYPE_FONT_IMAGE params: width, height, format, mipmaps; -// RRES_TYPE_FONT_CHARDATA params: charsCount, baseSize -// RRES_TYPE_DIRECTORY params: fileCount, directoryCount - -// SpriteFont = RRES_TYPE_FONT_IMAGE chunk + RRES_TYPE_FONT_DATA chunk -// Mesh = multiple RRES_TYPE_VERTEX chunks - - -#endif - -//---------------------------------------------------------------------------------- -// Global variables -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -//RRESDEF RRESData LoadResourceData(const char *rresFileName, int rresId, int part); -RRESDEF RRES LoadResource(const char *fileName, int rresId); -RRESDEF void UnloadResource(RRES rres); - -/* -QUESTION: How to load each type of data from RRES ? - -rres->type == RRES_TYPE_RAW -unsigned char data = (unsigned char *)rres[0]->data; - -rres->type == RRES_TYPE_IMAGE -Image image; -image.data = rres[0]->data; // Be careful, duplicate pointer -image.width = rres[0]->param1; -image.height = rres[0]->param2; -image.mipmaps = rres[0]->param3; -image.format = rres[0]->format; - -rres->type == RRES_TYPE_WAVE -Wave wave; -wave.data = rres[0]->data; -wave.sampleCount = rres[0]->param1; -wave.sampleRate = rres[0]->param2; -wave.sampleSize = rres[0]->param3; -wave.channels = rres[0]->param4; - -rres->type == RRES_TYPE_VERTEX (multiple parts) -Mesh mesh; -mesh.vertexCount = rres[0]->param1; -mesh.vertices = (float *)rres[0]->data; -mesh.texcoords = (float *)rres[1]->data; -mesh.normals = (float *)rres[2]->data; -mesh.tangents = (float *)rres[3]->data; -mesh.tangents = (unsigned char *)rres[4]->data; - -rres->type == RRES_TYPE_TEXT -unsigned char *text = (unsigned char *)rres->data; -Shader shader = LoadShaderText(text, rres->param1); Shader LoadShaderText(const char *shdrText, int length); - -rres->type == RRES_TYPE_FONT_IMAGE (multiple parts) -rres->type == RRES_TYPE_FONT_CHARDATA -SpriteFont font; -font.texture = LoadTextureFromImage(image); // rres[0] -font.chars = (CharInfo *)rres[1]->data; -font.charsCount = rres[1]->param1; -font.baseSize = rres[1]->param2; - -rres->type == RRES_TYPE_DIRECTORY -unsigned char *fileNames = (unsigned char *)rres[0]->data; // fileNames separed by \n -int filesCount = rres[0]->param1; -*/ - -#endif // RRES_H - - -/*********************************************************************************** -* -* RRES IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RRES_IMPLEMENTATION) - -#include // Required for: FILE, fopen(), fclose() - -// Check if custom malloc/free functions defined, if not, using standard ones -#if !defined(RRES_MALLOC) - #include // Required for: malloc(), free() - - #define RRES_MALLOC(size) malloc(size) - #define RRES_FREE(ptr) free(ptr) -#endif - -#include "external/tinfl.c" // Required for: tinfl_decompress_mem_to_mem() - // NOTE: DEFLATE algorythm data decompression - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- - -// rRES file header (8 byte) -typedef struct { - char id[4]; // File identifier: rRES (4 byte) - unsigned short version; // File version and subversion (2 byte) - unsigned short count; // Number of resources in this file (2 byte) -} RRESFileHeader; - -// rRES info header, every resource includes this header (16 byte + 16 byte) -typedef struct { - unsigned int id; // Resource unique identifier (4 byte) - unsigned char dataType; // Resource data type (1 byte) - unsigned char compType; // Resource data compression type (1 byte) - unsigned char cryptoType; // Resource data encryption type (1 byte) - unsigned char partsCount; // Resource data parts count, used for splitted data (1 byte) - unsigned int dataSize; // Resource data size (compressed or not, only DATA) (4 byte) - unsigned int uncompSize; // Resource data size (uncompressed, only DATA) (4 byte) - - unsigned int param1; // Resouce parameter 1 (4 byte) - unsigned int param2; // Resouce parameter 2 (4 byte) - unsigned int param3; // Resouce parameter 3 (4 byte) - unsigned int param4; // Resouce parameter 4 (4 byte) -} RRESInfoHeader; - -// Compression types -typedef enum { - RRES_COMP_NONE = 0, // No data compression - RRES_COMP_DEFLATE, // DEFLATE compression - RRES_COMP_LZ4, // LZ4 compression - RRES_COMP_LZMA, // LZMA compression - RRES_COMP_BROTLI, // BROTLI compression - // gzip, zopfli, lzo, zstd // Other compression algorythms... -} RRESCompressionType; - -// Encryption types -typedef enum { - RRES_CRYPTO_NONE = 0, // No data encryption - RRES_CRYPTO_XOR, // XOR (128 bit) encryption - RRES_CRYPTO_AES, // RIJNDAEL (128 bit) encryption (AES) - RRES_CRYPTO_TDES, // Triple DES encryption - RRES_CRYPTO_BLOWFISH, // BLOWFISH encryption - RRES_CRYPTO_XTEA, // XTEA encryption - // twofish, RC5, RC6 // Other encryption algorythm... -} RRESEncryptionType; - -// Image/Texture data type -typedef enum { - RRES_IM_UNCOMP_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - RRES_IM_UNCOMP_GRAY_ALPHA, // 16 bpp (2 channels) - RRES_IM_UNCOMP_R5G6B5, // 16 bpp - RRES_IM_UNCOMP_R8G8B8, // 24 bpp - RRES_IM_UNCOMP_R5G5B5A1, // 16 bpp (1 bit alpha) - RRES_IM_UNCOMP_R4G4B4A4, // 16 bpp (4 bit alpha) - RRES_IM_UNCOMP_R8G8B8A8, // 32 bpp - RRES_IM_COMP_DXT1_RGB, // 4 bpp (no alpha) - RRES_IM_COMP_DXT1_RGBA, // 4 bpp (1 bit alpha) - RRES_IM_COMP_DXT3_RGBA, // 8 bpp - RRES_IM_COMP_DXT5_RGBA, // 8 bpp - RRES_IM_COMP_ETC1_RGB, // 4 bpp - RRES_IM_COMP_ETC2_RGB, // 4 bpp - RRES_IM_COMP_ETC2_EAC_RGBA, // 8 bpp - RRES_IM_COMP_PVRT_RGB, // 4 bpp - RRES_IM_COMP_PVRT_RGBA, // 4 bpp - RRES_IM_COMP_ASTC_4x4_RGBA, // 8 bpp - RRES_IM_COMP_ASTC_8x8_RGBA // 2 bpp - //... -} RRESImageFormat; - -// Vertex data type -typedef enum { - RRES_VERT_POSITION, - RRES_VERT_TEXCOORD1, - RRES_VERT_TEXCOORD2, - RRES_VERT_TEXCOORD3, - RRES_VERT_TEXCOORD4, - RRES_VERT_NORMAL, - RRES_VERT_TANGENT, - RRES_VERT_COLOR, - RRES_VERT_INDEX, - //... -} RRESVertexType; - -// Vertex data format type -typedef enum { - RRES_VERT_BYTE, - RRES_VERT_SHORT, - RRES_VERT_INT, - RRES_VERT_HFLOAT, - RRES_VERT_FLOAT, - //... -} RRESVertexFormat; - -#if defined(RRES_STANDALONE) -typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType; -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize); - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Load resource from file by id (could be multiple parts) -// NOTE: Returns uncompressed data with parameters, search resource by id -RRESDEF RRES LoadResource(const char *fileName, int rresId) -{ - RRES rres = { 0 }; - - RRESFileHeader fileHeader; - RRESInfoHeader infoHeader; - - FILE *rresFile = fopen(fileName, "rb"); - - if (rresFile == NULL) TraceLog(LOG_WARNING, "[%s] rRES raylib resource file could not be opened", fileName); - else - { - // Read rres file info header - fread(&fileHeader.id[0], sizeof(char), 1, rresFile); - fread(&fileHeader.id[1], sizeof(char), 1, rresFile); - fread(&fileHeader.id[2], sizeof(char), 1, rresFile); - fread(&fileHeader.id[3], sizeof(char), 1, rresFile); - fread(&fileHeader.version, sizeof(short), 1, rresFile); - fread(&fileHeader.count, sizeof(short), 1, rresFile); - - // Verify "rRES" identifier - if ((fileHeader.id[0] != 'r') && (fileHeader.id[1] != 'R') && (fileHeader.id[2] != 'E') && (fileHeader.id[3] != 'S')) - { - TraceLog(LOG_WARNING, "[%s] This is not a valid raylib resource file", fileName); - } - else - { - for (int i = 0; i < fileHeader.count; i++) - { - // Read resource info and parameters - fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile); - - if (infoHeader.id == rresId) - { - rres = (RRES)malloc(sizeof(RRESData)*infoHeader.partsCount); - - // Load all required resources parts - for (int k = 0; k < infoHeader.partsCount; k++) - { - // TODO: Verify again that rresId is the same in every part - - // Register data type and parameters - rres[k].type = infoHeader.dataType; - rres[k].param1 = infoHeader.param1; - rres[k].param2 = infoHeader.param2; - rres[k].param3 = infoHeader.param3; - rres[k].param4 = infoHeader.param4; - - // Read resource data block - void *data = RRES_MALLOC(infoHeader.dataSize); - fread(data, infoHeader.dataSize, 1, rresFile); - - if (infoHeader.compType == RRES_COMP_DEFLATE) - { - void *uncompData = DecompressData(data, infoHeader.dataSize, infoHeader.uncompSize); - - rres[k].data = uncompData; - - RRES_FREE(data); - } - else rres[k].data = data; - - if (rres[k].data != NULL) TraceLog(LOG_INFO, "[%s][ID %i] Resource data loaded successfully", fileName, (int)infoHeader.id); - - // Read next part - fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile); - } - } - else - { - // Skip required data to read next resource infoHeader - fseek(rresFile, infoHeader.dataSize, SEEK_CUR); - } - } - - if (rres[0].data == NULL) TraceLog(LOG_WARNING, "[%s][ID %i] Requested resource could not be found", fileName, (int)rresId); - } - - fclose(rresFile); - } - - return rres; -} - -// Unload resource data -RRESDEF void UnloadResource(RRES rres) -{ - // TODO: When you load resource... how many parts conform it? depends on type? --> Not clear... - - if (rres[0].data != NULL) free(rres[0].data); -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -// Data decompression function -// NOTE: Allocated data MUST be freed by user -static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize) -{ - int tempUncompSize; - void *uncompData; - - // Allocate buffer to hold decompressed data - uncompData = (mz_uint8 *)RRES_MALLOC((size_t)uncompSize); - - // Check correct memory allocation - if (uncompData == NULL) - { - TraceLog(LOG_WARNING, "Out of memory while decompressing data"); - } - else - { - // Decompress data - tempUncompSize = tinfl_decompress_mem_to_mem(uncompData, (size_t)uncompSize, data, compSize, 1); - - if (tempUncompSize == -1) - { - TraceLog(LOG_WARNING, "Data decompression failed"); - RRES_FREE(uncompData); - } - - if (uncompSize != (int)tempUncompSize) - { - TraceLog(LOG_WARNING, "Expected uncompressed size do not match, data may be corrupted"); - TraceLog(LOG_WARNING, " -- Expected uncompressed size: %i", uncompSize); - TraceLog(LOG_WARNING, " -- Returned uncompressed size: %i", tempUncompSize); - } - - TraceLog(LOG_INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize); - } - - return uncompData; -} - -// Some required functions for rres standalone module version -#if defined(RRES_STANDALONE) -// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) -void TraceLog(int logType, const char *text, ...) -{ - va_list args; - va_start(args, text); - - switch (msgType) - { - case LOG_INFO: fprintf(stdout, "INFO: "); break; - case LOG_ERROR: fprintf(stdout, "ERROR: "); break; - case LOG_WARNING: fprintf(stdout, "WARNING: "); break; - case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break; - default: break; - } - - vfprintf(stdout, text, args); - fprintf(stdout, "\n"); - - va_end(args); - - if (msgType == LOG_ERROR) exit(1); -} -#endif - -#endif // RRES_IMPLEMENTATION diff --git a/rres/cmd/rrem/main.go b/rres/cmd/rrem/main.go index 8d69d16..5938f27 100644 --- a/rres/cmd/rrem/main.go +++ b/rres/cmd/rrem/main.go @@ -30,7 +30,6 @@ import ( "github.com/moutend/go-wav" "github.com/gen2brain/raylib-go/rres" - "github.com/gen2brain/raylib-go/rres/rreslib" ) func init() { @@ -156,7 +155,7 @@ func main() { } // Encryption - data, err = rreslib.Encrypt([]byte(*key), data, int(infoHeader.CryptoType)) + data, err = rres.Encrypt([]byte(*key), data, int(infoHeader.CryptoType)) if err != nil { fmt.Printf("%v\n", err) } @@ -164,7 +163,7 @@ func main() { infoHeader.UncompSize = uint32(len(data)) // Compression - data, err = rreslib.Compress(data, int(infoHeader.CompType)) + data, err = rres.Compress(data, int(infoHeader.CompType)) if err != nil { fmt.Printf("%v\n", err) } diff --git a/rres/rres.go b/rres/rres.go index f3dee7b..3b5f258 100644 --- a/rres/rres.go +++ b/rres/rres.go @@ -1,5 +1,30 @@ package rres +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/rand" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "os" + "unsafe" + + "github.com/dsnet/compress/bzip2" + "github.com/golang/snappy" + "github.com/klauspost/compress/flate" + "github.com/pierrec/lz4" + xor "github.com/rootlch/encrypt" + "github.com/ulikunitz/xz" + "golang.org/x/crypto/blowfish" + "golang.org/x/crypto/xtea" + + "github.com/gen2brain/raylib-go/raylib" +) + type Data struct { // Resource type (4 byte) Type uint32 @@ -163,3 +188,504 @@ const ( VertHfloat VertFloat ) + +// LoadResource - Load resource from file by id +// NOTE: Returns uncompressed data with parameters, search resource by id +func LoadResource(reader io.ReadSeeker, rresID int, key []byte) (data Data) { + var fileHeader FileHeader + var infoHeader InfoHeader + + reader.Seek(0, 0) + + // Read rres file header + err := binary.Read(reader, binary.LittleEndian, &fileHeader) + if err != nil { + raylib.TraceLog(raylib.LogWarning, err.Error()) + return + } + + // Verify "rRES" identifier + if string(fileHeader.ID[:]) != "rRES" { + raylib.TraceLog(raylib.LogWarning, "not a valid raylib resource file") + return + } + + reader.Seek(int64(unsafe.Sizeof(fileHeader)), os.SEEK_CUR) + + for i := 0; i < int(fileHeader.Count); i++ { + // Read resource info and parameters + err = binary.Read(reader, binary.LittleEndian, &infoHeader) + if err != nil { + raylib.TraceLog(raylib.LogWarning, err.Error()) + return + } + + reader.Seek(int64(unsafe.Sizeof(infoHeader)), os.SEEK_CUR) + + if int(infoHeader.ID) == rresID { + data.Type = uint32(infoHeader.DataType) + data.Param1 = infoHeader.Param1 + data.Param2 = infoHeader.Param2 + data.Param3 = infoHeader.Param3 + data.Param4 = infoHeader.Param4 + + // Read resource data block + b := make([]byte, infoHeader.DataSize) + reader.Read(b) + + // Decompress data + data.Data, err = Decompress(b, int(infoHeader.CompType)) + if err != nil { + raylib.TraceLog(raylib.LogWarning, "[ID %d] %v", infoHeader.ID, err) + } + + // Decrypt data + data.Data, err = Decrypt(key, data.Data, int(infoHeader.CryptoType)) + if err != nil { + raylib.TraceLog(raylib.LogWarning, "[ID %d] %v", infoHeader.ID, err) + } + + if data.Data != nil && len(data.Data) == int(infoHeader.UncompSize) { + raylib.TraceLog(raylib.LogInfo, "[ID %d] Resource data loaded successfully", infoHeader.ID) + } + } else { + // Skip required data to read next resource infoHeader + reader.Seek(int64(infoHeader.DataSize), os.SEEK_CUR) + } + } + + if data.Data == nil { + raylib.TraceLog(raylib.LogWarning, "[ID %d] Requested resource could not be found", rresID) + } + + return +} + +// Encrypt data +func Encrypt(key, data []byte, cryptoType int) ([]byte, error) { + switch cryptoType { + case CryptoXOR: + c, err := xor.NewXor(string(key)) + if err != nil { + return nil, err + } + + return c.Encode(data), nil + case CryptoAES: + b, err := encryptAES(key, data) + if err != nil { + return nil, err + } + + return b, nil + case Crypto3DES: + b, err := encrypt3DES(key, data) + if err != nil { + return nil, err + } + + return b, nil + case CryptoBlowfish: + b, err := encryptBlowfish(key, data) + if err != nil { + return nil, err + } + + return b, nil + case CryptoXTEA: + b, err := encryptXTEA(key, data) + if err != nil { + fmt.Printf("%v\n", err) + } + + return b, nil + default: + return data, nil + } +} + +// Decrypt data +func Decrypt(key, data []byte, cryptoType int) ([]byte, error) { + switch cryptoType { + case CryptoXOR: + c, err := xor.NewXor(string(key)) + if err != nil { + return nil, err + } + + b := c.Encode(data) + return b, nil + case CryptoAES: + b, err := decryptAES(key, data) + if err != nil { + return nil, err + } + return b, nil + case Crypto3DES: + b, err := decrypt3DES(key, data) + if err != nil { + return nil, err + } + return b, nil + case CryptoBlowfish: + b, err := decryptBlowfish(key, data) + if err != nil { + return nil, err + } + return b, nil + case CryptoXTEA: + b, err := decryptXTEA(key, data) + if err != nil { + return nil, err + } + return b, nil + default: + return data, nil + } +} + +// Compress data +func Compress(data []byte, compType int) ([]byte, error) { + switch compType { + case CompNone: + return data, nil + case CompDeflate: + buf := new(bytes.Buffer) + + w, err := flate.NewWriter(buf, flate.DefaultCompression) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case CompLZ4: + buf := new(bytes.Buffer) + + w := lz4.NewWriter(buf) + + _, err := w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case CompLZMA2: + buf := new(bytes.Buffer) + + w, err := xz.NewWriter(buf) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case CompBZIP2: + buf := new(bytes.Buffer) + + w, err := bzip2.NewWriter(buf, &bzip2.WriterConfig{Level: bzip2.BestCompression}) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + case CompSnappy: + buf := new(bytes.Buffer) + + w := snappy.NewWriter(buf) + + _, err := w.Write(data) + if err != nil { + return nil, err + } + + w.Close() + + return buf.Bytes(), nil + default: + return data, nil + } +} + +// Decompress data +func Decompress(data []byte, compType int) ([]byte, error) { + switch compType { + case CompNone: + return data, nil + case CompDeflate: + r := flate.NewReader(bytes.NewReader(data)) + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + r.Close() + + return u, nil + case CompLZ4: + r := lz4.NewReader(bytes.NewReader(data)) + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + case CompLZMA2: + r, err := xz.NewReader(bytes.NewReader(data)) + if err != nil { + return nil, err + } + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + case CompBZIP2: + r, err := bzip2.NewReader(bytes.NewReader(data), &bzip2.ReaderConfig{}) + if err != nil { + return nil, err + } + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + case CompSnappy: + r := snappy.NewReader(bytes.NewReader(data)) + + u, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return u, nil + default: + return data, nil + } +} + +// pad to block size +func pad(src []byte, blockSize int) []byte { + padding := blockSize - len(src)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(src, padtext...) +} + +// unpad +func unpad(src []byte) ([]byte, error) { + length := len(src) + unpadding := int(src[length-1]) + + if unpadding > length { + return nil, fmt.Errorf("unpad error. This can happen when incorrect encryption key is used.") + } + + return src[:(length - unpadding)], nil +} + +// encryptAES +func encryptAES(key, text []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, aes.BlockSize) + ciphertext := make([]byte, aes.BlockSize+len(msg)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cfb := cipher.NewCFBEncrypter(block, iv) + cfb.XORKeyStream(ciphertext[aes.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptAES +func decryptAES(key, text []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % aes.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:aes.BlockSize] + msg := text[aes.BlockSize:] + + cfb := cipher.NewCFBDecrypter(block, iv) + cfb.XORKeyStream(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encrypt3DES +func encrypt3DES(key, text []byte) ([]byte, error) { + block, err := des.NewTripleDESCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, des.BlockSize) + ciphertext := make([]byte, des.BlockSize+len(msg)) + iv := ciphertext[:des.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[des.BlockSize:], msg) + + return ciphertext, nil +} + +// decrypt3DES +func decrypt3DES(key, text []byte) ([]byte, error) { + block, err := des.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % des.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:des.BlockSize] + msg := text[des.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encryptBlowfish +func encryptBlowfish(key, text []byte) ([]byte, error) { + block, err := blowfish.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, blowfish.BlockSize) + ciphertext := make([]byte, blowfish.BlockSize+len(msg)) + iv := ciphertext[:blowfish.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[blowfish.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptBlowfish +func decryptBlowfish(key, text []byte) ([]byte, error) { + block, err := blowfish.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % blowfish.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:blowfish.BlockSize] + msg := text[blowfish.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} + +// encryptXTEA +func encryptXTEA(key, text []byte) ([]byte, error) { + block, err := xtea.NewCipher(key) + if err != nil { + return nil, err + } + + msg := pad(text, xtea.BlockSize) + ciphertext := make([]byte, xtea.BlockSize+len(msg)) + iv := ciphertext[:xtea.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + cbc := cipher.NewCBCEncrypter(block, iv) + cbc.CryptBlocks(ciphertext[xtea.BlockSize:], msg) + + return ciphertext, nil +} + +// decryptXTEA +func decryptXTEA(key, text []byte) ([]byte, error) { + block, err := xtea.NewCipher(key) + if err != nil { + return nil, err + } + + if (len(text) % xtea.BlockSize) != 0 { + return nil, fmt.Errorf("blocksize must be multiple of decoded message length") + } + + iv := text[:xtea.BlockSize] + msg := text[xtea.BlockSize:] + + cbc := cipher.NewCBCDecrypter(block, iv) + cbc.CryptBlocks(msg, msg) + + unpadMsg, err := unpad(msg) + if err != nil { + return nil, err + } + + return unpadMsg, nil +} diff --git a/rres/rreslib/cgo/Makefile b/rres/rreslib/cgo/Makefile deleted file mode 100644 index e3d3c38..0000000 --- a/rres/rreslib/cgo/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -all: build - -build: - go build -buildmode=c-archive -o rreslib.a diff --git a/rres/rreslib/cgo/make.bash b/rres/rreslib/cgo/make.bash deleted file mode 100755 index 082bf0e..0000000 --- a/rres/rreslib/cgo/make.bash +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -CHROOT="/usr/x86_64-pc-linux-gnu-static" -MINGW="/usr/i686-w64-mingw32" -RPI="/usr/armv6j-hardfloat-linux-gnueabi" -ANDROID="/opt/android-toolchain-arm7" - -CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -buildmode=c-archive -o release/linux/rreslib.a -ldflags "-s -w" - -CC="i686-w64-mingw32-gcc" CXX="i686-w64-mingw32-g++" \ -CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -buildmode=c-archive -o release/win32/rreslib.a -ldflags "-s -w" - -CC="armv6j-hardfloat-linux-gnueabi-gcc" CXX="armv6j-hardfloat-linux-gnueabi-g++" \ -CGO_ENABLED=1 GOOS=linux GOARCH=arm go build -buildmode=c-archive -o release/rpi/rreslib.a -ldflags "-s -w" - -PATH="$PATH:$ANDROID/bin" \ -CC="arm-linux-androideabi-gcc" CXX="arm-linux-androideabi-g++" \ -CGO_ENABLED=1 GOOS=android GOARCH=arm go build -buildmode=c-shared -o release/android/armeabi-v7a/rreslib.so -ldflags "-s -w" diff --git a/rres/rreslib/cgo/rreslib.go b/rres/rreslib/cgo/rreslib.go deleted file mode 100644 index 51c4996..0000000 --- a/rres/rreslib/cgo/rreslib.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import "C" - -import ( - "unsafe" - - "github.com/gen2brain/raylib-go/rres/rreslib" -) - -//export Compress -func Compress(compType C.int, data *C.uchar, uncompSize C.ulong, outCompSize *C.ulong) *C.uchar { - d := C.GoBytes(unsafe.Pointer(data), C.int(uncompSize)) - - c, err := rreslib.Compress(d, int(compType)) - if err != nil { - return nil - } - - *outCompSize = C.ulong(len(c)) - return (*C.uchar)(unsafe.Pointer(&c[0])) -} - -//export Decompress -func Decompress(compType C.int, data *C.uchar, uncompSize C.ulong, compSize C.ulong) *C.uchar { - d := C.GoBytes(unsafe.Pointer(data), C.int(compSize)) - - c, err := rreslib.Decompress(d, int(compType)) - if err != nil { - return nil - } - - if len(c) != int(uncompSize) { - return nil - } - - return (*C.uchar)(unsafe.Pointer(&c[0])) -} - -//export Encrypt -func Encrypt(cryptoType C.int, key *C.char, data *C.uchar, dataSize C.ulong, outDataSize *C.ulong) *C.uchar { - k := []byte(C.GoString(key)) - d := C.GoBytes(unsafe.Pointer(data), C.int(dataSize)) - - c, err := rreslib.Encrypt(k, d, int(cryptoType)) - if err != nil { - return nil - } - - *outDataSize = C.ulong(len(c)) - return (*C.uchar)(unsafe.Pointer(&c[0])) -} - -//export Decrypt -func Decrypt(cryptoType C.int, key *C.char, data *C.uchar, dataSize C.ulong) *C.uchar { - k := []byte(C.GoString(key)) - d := C.GoBytes(unsafe.Pointer(data), C.int(dataSize)) - - c, err := rreslib.Decrypt(k, d, int(cryptoType)) - if err != nil { - return nil - } - - return (*C.uchar)(unsafe.Pointer(&c[0])) -} - -// We need the main() so we can compile as C library -func main() { -} diff --git a/rres/rreslib/rreslib.go b/rres/rreslib/rreslib.go deleted file mode 100644 index 4547864..0000000 --- a/rres/rreslib/rreslib.go +++ /dev/null @@ -1,454 +0,0 @@ -// Package rreslib provides Encrypt/Decrypt and Compress/Uncompress functions -package rreslib - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/rand" - "fmt" - "io" - "io/ioutil" - - "golang.org/x/crypto/blowfish" - "golang.org/x/crypto/xtea" - - "github.com/dsnet/compress/bzip2" - "github.com/golang/snappy" - "github.com/klauspost/compress/flate" - "github.com/pierrec/lz4" - xor "github.com/rootlch/encrypt" - "github.com/ulikunitz/xz" - - "github.com/gen2brain/raylib-go/rres" -) - -// Encrypt data -func Encrypt(key, data []byte, cryptoType int) ([]byte, error) { - switch cryptoType { - case rres.CryptoXOR: - c, err := xor.NewXor(string(key)) - if err != nil { - return nil, err - } - - return c.Encode(data), nil - case rres.CryptoAES: - b, err := encryptAES(key, data) - if err != nil { - return nil, err - } - - return b, nil - case rres.Crypto3DES: - b, err := encrypt3DES(key, data) - if err != nil { - return nil, err - } - - return b, nil - case rres.CryptoBlowfish: - b, err := encryptBlowfish(key, data) - if err != nil { - return nil, err - } - - return b, nil - case rres.CryptoXTEA: - b, err := encryptXTEA(key, data) - if err != nil { - fmt.Printf("%v\n", err) - } - - return b, nil - default: - return data, nil - } -} - -// Decrypt data -func Decrypt(key, data []byte, cryptoType int) ([]byte, error) { - switch cryptoType { - case rres.CryptoXOR: - c, err := xor.NewXor(string(key)) - if err != nil { - return nil, err - } - - b := c.Encode(data) - return b, nil - case rres.CryptoAES: - b, err := decryptAES(key, data) - if err != nil { - return nil, err - } - return b, nil - case rres.Crypto3DES: - b, err := decrypt3DES(key, data) - if err != nil { - return nil, err - } - return b, nil - case rres.CryptoBlowfish: - b, err := decryptBlowfish(key, data) - if err != nil { - return nil, err - } - return b, nil - case rres.CryptoXTEA: - b, err := decryptXTEA(key, data) - if err != nil { - return nil, err - } - return b, nil - default: - return data, nil - } -} - -// Compress data -func Compress(data []byte, compType int) ([]byte, error) { - switch compType { - case rres.CompNone: - return data, nil - case rres.CompDeflate: - buf := new(bytes.Buffer) - - w, err := flate.NewWriter(buf, flate.DefaultCompression) - if err != nil { - return nil, err - } - - _, err = w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - case rres.CompLZ4: - buf := new(bytes.Buffer) - - w := lz4.NewWriter(buf) - - _, err := w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - case rres.CompLZMA2: - buf := new(bytes.Buffer) - - w, err := xz.NewWriter(buf) - if err != nil { - return nil, err - } - - _, err = w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - case rres.CompBZIP2: - buf := new(bytes.Buffer) - - w, err := bzip2.NewWriter(buf, &bzip2.WriterConfig{Level: bzip2.BestCompression}) - if err != nil { - return nil, err - } - - _, err = w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - case rres.CompSnappy: - buf := new(bytes.Buffer) - - w := snappy.NewWriter(buf) - - _, err := w.Write(data) - if err != nil { - return nil, err - } - - w.Close() - - return buf.Bytes(), nil - default: - return data, nil - } -} - -// Decompress data -func Decompress(data []byte, compType int) ([]byte, error) { - switch compType { - case rres.CompNone: - return data, nil - case rres.CompDeflate: - r := flate.NewReader(bytes.NewReader(data)) - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - r.Close() - - return u, nil - case rres.CompLZ4: - r := lz4.NewReader(bytes.NewReader(data)) - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - return u, nil - case rres.CompLZMA2: - r, err := xz.NewReader(bytes.NewReader(data)) - if err != nil { - return nil, err - } - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - return u, nil - case rres.CompBZIP2: - r, err := bzip2.NewReader(bytes.NewReader(data), &bzip2.ReaderConfig{}) - if err != nil { - return nil, err - } - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - return u, nil - case rres.CompSnappy: - r := snappy.NewReader(bytes.NewReader(data)) - - u, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - return u, nil - default: - return data, nil - } -} - -// pad to block size -func pad(src []byte, blockSize int) []byte { - padding := blockSize - len(src)%blockSize - padtext := bytes.Repeat([]byte{byte(padding)}, padding) - return append(src, padtext...) -} - -// unpad -func unpad(src []byte) ([]byte, error) { - length := len(src) - unpadding := int(src[length-1]) - - if unpadding > length { - return nil, fmt.Errorf("unpad error. This can happen when incorrect encryption key is used.") - } - - return src[:(length - unpadding)], nil -} - -// encryptAES -func encryptAES(key, text []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - msg := pad(text, aes.BlockSize) - ciphertext := make([]byte, aes.BlockSize+len(msg)) - iv := ciphertext[:aes.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - cfb := cipher.NewCFBEncrypter(block, iv) - cfb.XORKeyStream(ciphertext[aes.BlockSize:], msg) - - return ciphertext, nil -} - -// decryptAES -func decryptAES(key, text []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - if (len(text) % aes.BlockSize) != 0 { - return nil, fmt.Errorf("blocksize must be multiple of decoded message length") - } - - iv := text[:aes.BlockSize] - msg := text[aes.BlockSize:] - - cfb := cipher.NewCFBDecrypter(block, iv) - cfb.XORKeyStream(msg, msg) - - unpadMsg, err := unpad(msg) - if err != nil { - return nil, err - } - - return unpadMsg, nil -} - -// encrypt3DES -func encrypt3DES(key, text []byte) ([]byte, error) { - block, err := des.NewTripleDESCipher(key) - if err != nil { - return nil, err - } - - msg := pad(text, des.BlockSize) - ciphertext := make([]byte, des.BlockSize+len(msg)) - iv := ciphertext[:des.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - cbc := cipher.NewCBCEncrypter(block, iv) - cbc.CryptBlocks(ciphertext[des.BlockSize:], msg) - - return ciphertext, nil -} - -// decrypt3DES -func decrypt3DES(key, text []byte) ([]byte, error) { - block, err := des.NewCipher(key) - if err != nil { - return nil, err - } - - if (len(text) % des.BlockSize) != 0 { - return nil, fmt.Errorf("blocksize must be multiple of decoded message length") - } - - iv := text[:des.BlockSize] - msg := text[des.BlockSize:] - - cbc := cipher.NewCBCDecrypter(block, iv) - cbc.CryptBlocks(msg, msg) - - unpadMsg, err := unpad(msg) - if err != nil { - return nil, err - } - - return unpadMsg, nil -} - -// encryptBlowfish -func encryptBlowfish(key, text []byte) ([]byte, error) { - block, err := blowfish.NewCipher(key) - if err != nil { - return nil, err - } - - msg := pad(text, blowfish.BlockSize) - ciphertext := make([]byte, blowfish.BlockSize+len(msg)) - iv := ciphertext[:blowfish.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - cbc := cipher.NewCBCEncrypter(block, iv) - cbc.CryptBlocks(ciphertext[blowfish.BlockSize:], msg) - - return ciphertext, nil -} - -// decryptBlowfish -func decryptBlowfish(key, text []byte) ([]byte, error) { - block, err := blowfish.NewCipher(key) - if err != nil { - return nil, err - } - - if (len(text) % blowfish.BlockSize) != 0 { - return nil, fmt.Errorf("blocksize must be multiple of decoded message length") - } - - iv := text[:blowfish.BlockSize] - msg := text[blowfish.BlockSize:] - - cbc := cipher.NewCBCDecrypter(block, iv) - cbc.CryptBlocks(msg, msg) - - unpadMsg, err := unpad(msg) - if err != nil { - return nil, err - } - - return unpadMsg, nil -} - -// encryptXTEA -func encryptXTEA(key, text []byte) ([]byte, error) { - block, err := xtea.NewCipher(key) - if err != nil { - return nil, err - } - - msg := pad(text, xtea.BlockSize) - ciphertext := make([]byte, xtea.BlockSize+len(msg)) - iv := ciphertext[:xtea.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - cbc := cipher.NewCBCEncrypter(block, iv) - cbc.CryptBlocks(ciphertext[xtea.BlockSize:], msg) - - return ciphertext, nil -} - -// decryptXTEA -func decryptXTEA(key, text []byte) ([]byte, error) { - block, err := xtea.NewCipher(key) - if err != nil { - return nil, err - } - - if (len(text) % xtea.BlockSize) != 0 { - return nil, fmt.Errorf("blocksize must be multiple of decoded message length") - } - - iv := text[:xtea.BlockSize] - msg := text[xtea.BlockSize:] - - cbc := cipher.NewCBCDecrypter(block, iv) - cbc.CryptBlocks(msg, msg) - - unpadMsg, err := unpad(msg) - if err != nil { - return nil, err - } - - return unpadMsg, nil -}