文件打包学习4

梦想的初衷 提交于 2019-11-26 15:14:56

添加自定义加密方法

CRC32.h

#pragma once

class CRC32
{
public:
    CRC32(void);
public:
    ~CRC32(void);

    static unsigned GetDataCRC32( const void*pData, unsigned dwSize, unsigned dwDefaultCRC );
};

CRC32.cpp

#include "CRC32.h"

//CRC表提取自zlib, crc32.h
static const unsigned long CRCTable32[256] =
{   
    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
    0x2d02ef8dUL
};


CRC32::CRC32(void)
{
}

CRC32::~CRC32(void)
{
}

unsigned  CRC32::GetDataCRC32( const void*pData, unsigned  dwSize, unsigned  dwDefaultCRC )
{
    if( !pData )
    {
        return 0;
    }
    const unsigned char*pByteData = ( const unsigned char*)pData;
    unsigned  dwCRC = dwDefaultCRC;
    for( unsigned  i=0; i<dwSize; i++ )
    {
        dwCRC = ( dwCRC << 8 ) ^ CRCTable32[ (dwCRC >> 24) ^ (*pByteData++) ];
    }
    return dwCRC;
}

QuickCryptor.h

#pragma once

#include <stdio.h>

class CQuickCryptor
{
public:
    CQuickCryptor(void);
public:
    ~CQuickCryptor(void);
    //初始化加密器
    void Init( const char*szPassword );
    //加密
    void Encrypt( void*pData, size_t Size );
    //解密
    void Decrypt( void*pData, size_t Size );
private:
    int NextValue( int & Seed );
private:
    int                     m_SeedValue;            //加密种子
};

QuickCryptor.cpp

#include "QuickCryptor.h"
#include "CRC32.h"
#include <string.h>

CQuickCryptor::CQuickCryptor(void)
{
    m_SeedValue = 0;
}

CQuickCryptor::~CQuickCryptor(void)
{
}

void CQuickCryptor::Init(const char*szPassword )
{
    m_SeedValue = 0;
    if( szPassword )
    {
        m_SeedValue = CRC32::GetDataCRC32( szPassword, strlen( szPassword ), 0 );
    }
}

int CQuickCryptor::NextValue( int &Seed )
{
    //模拟一下C运行库的rand这个算法
    //保证我们用固定的种子生成固定的下一个值
    return ( ( ( Seed = Seed * 214013L + 2531011L) >> 16) & 0xffff );
}

void CQuickCryptor::Encrypt(void*pData, size_t Size )
{
    //加密处理,我们把种子生成的值不断的去做变换
    int Seed = m_SeedValue;
    unsigned char*pByteData = (unsigned char*)pData;
    for( size_t i=0; i<Size; i++ )
    {
        int Value = pByteData[i] + ( NextValue( Seed ) & 0xFF );
        //加上一个种子生成的值(0-255)
        if( Value > 255 )
        {
            Value -= 256;
        }
        pByteData[i] = Value;
    }
}

void CQuickCryptor::Decrypt(void*pData, size_t Size )
{
    //解密处理,我们把种子生成的值不断的去做变换
    int Seed = m_SeedValue;
    unsigned char*pByteData = (unsigned char*)pData;
    for( size_t i=0; i<Size; i++ )
    {
        //由于加密我们做加法,解密我们就做减法
        int Value = pByteData[i] - ( NextValue( Seed ) & 0xFF );
        if( Value < 0 )
        {
            Value += 256;
        }
        pByteData[i] = Value;
    }
}

NewPackage.h

#ifndef NEWPACKAGE_H_
#define NEWPACKAGE_H_

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include <vector>
#include <string>

#include "QuickCryptor.h"

class CFileBuffer
{
public:
    CFileBuffer():m_pBuffer(nullptr),m_nSize(0)
    {
    }
    ~CFileBuffer()
    {
        Destroy();
    }
    //创建一块内存
    bool Create(size_t Size)
    {
        Destroy();
        m_pBuffer = malloc(Size);
        if(!m_pBuffer)
        {
            return false;
        }
        m_nSize = Size;
        return true;
    }
    //销毁一块内存
    void Destroy()
    {
        if(m_pBuffer)
        {
            free(m_pBuffer);
            m_pBuffer = nullptr;
        }
        m_nSize = 0;
    }
    //获取申请内存地址
    void* GetBuffer()const
    {
        return m_pBuffer;
    }    
    //获取申请内存大小
    size_t GetSize()const
    {
        return m_nSize;
    }
    //将内存写入到磁盘文件
    bool Save(const char* szFileName)
    {

        //检查m_pBuffer是否为空,如果为空,表示当前指针没有指向任何数据,不需要写入
        if(!m_pBuffer)
            return false;

        //以二进制写的方式打开文件,准备写入文件
        FILE* fp = fopen(szFileName, "wb");
        if(!fp)
        {
            fprintf(stderr, "fopen %s error : %s \n",szFileName, strerror(errno));
        }

        //开始写入文件
        if(m_nSize != fwrite(m_pBuffer, 1, m_nSize, fp))
        {
            fclose(fp);
            return false;
        }

        fclose(fp);
        return true;
    }

private:
    void* m_pBuffer;    
    size_t m_nSize;
};

struct NewPackageItem
{
    size_t FileNameLen;         //文件名的长度
    size_t FileSize;            //文件的大小
    size_t OffsetPackage;       //文件在包裹的偏移位置
    char FileName[0];           //可变文件名
};

//我们定义一个标识,表示这个是我们的包裹格式
static const char   MY_PACKAGE_FLAG[] = "NewPackage";
static const size_t MY_ENCRYPT_METHOD_XOR = 0;      //xor加密
static const size_t MY_ENCRYPT_METHOD_EASY = 0;     //自定义的简单的快速加密

struct PackageInfo
{
    size_t              EncryptMethod;  //加密算法
};

class CNewPackage
{
public:
    CNewPackage();
    ~CNewPackage();
    //重置一个包裹
    void ResetPackage( );
    //读取一个包裹
    bool OpenPackage( const char*szPackageName, const char*szPassword);
    //添加一个文件,忽略大小写
    bool AddFile( const char*szFileName );
    //删除一个文件,忽略大小写
    bool RemoveFile( const char*szFileName );
    //重复性检查,忽略大小写
    bool HasFile( const char*szFileName );
    //保存包裹到指定文件名
    bool SavePackage( const char*szPackageName, const char*szPassword);
    //导出文件数据到FileBuffer里面
    bool ExportPackageItem( const char*szFileName, CFileBuffer & FileBuffer );
    
private:
    FILE*                           m_fpPackage;        //包裹文件指针
    CQuickCryptor                   m_Cryptor;          //操作加密解密的对象
    std::vector<std::string>        m_AddFiles;         //待添加到包裹的文件
    std::vector<NewPackageItem*>    m_PackageItems;     //已经打包到包裹的文件信息
};

#endif // !NEWPACKAGE_H_

NewPackage.cpp

#include "NewPackage.h"

/*
┌------------┬-------------┬-------------┬------┬--------┬-------┬-------┐
├  size_t n  │     Item    │     Item    │. . . │ FILE1  │ FILE1 │ . . . │
└------------┴-------------┴-------------┴------┴--------┴-------┴-------┘
┌-----------┬-----------┬--------┬-----------┬-----------┬------┬--------┬-------┬-------┐
├  size_t n │PackageItem│FileName│PackageItem│ FileName  │. . . │ FILE1  │ FILE1 │ . . . │
└-----------┴-----------┴--------┴-----------┴-----------┴------┴--------┴-------┴-------┘
*/

struct FileItemForWrite
{
    FILE *fp;                     //要打包的文件的文件指针
    size_t FileOffset;            //在文件中的偏移位置
    size_t FileSize;              //要读取的文件的大小
    std::string FileName;         //要读取的文件的文件名
    NewPackageItem *pPackageItem; //要读取的文件基本信息
};

CNewPackage::CNewPackage()
{
    m_fpPackage = nullptr;
}

CNewPackage::~CNewPackage()
{
    ResetPackage();
}

void CNewPackage::ResetPackage()
{

    for (size_t i = 0; i < m_PackageItems.size(); i++)
    {
        NewPackageItem *pItem = m_PackageItems[i];
        free(pItem);
    }
    //clear是为了清除vector内部的index,size;如果不清除,这两个值会一直增加
    m_PackageItems.clear();

    //关闭包裹文件指针
    if (m_fpPackage)
    {
        fclose(m_fpPackage);
        m_fpPackage = nullptr;
    }

    //清理待添加的文件容器
    m_AddFiles.clear();
}

bool CNewPackage::AddFile(const char *szFileName)
{
    //如果有同名的,做替换处理
    RemoveFile(szFileName);

    m_AddFiles.push_back(szFileName);

    return true;
}

bool CNewPackage::RemoveFile(const char *szFileName)
{
    //从待添加的文件查找
    for (size_t i = 0; i < m_AddFiles.size(); i++)
    {
        if (strcasecmp(m_AddFiles[i].c_str(), szFileName) == 0)
        {
            m_AddFiles.erase(m_AddFiles.begin() + i);
            return true;
        }
    }

    //从包裹文件中查找
    for (size_t i = 0; i < m_PackageItems.size(); i++)
    {
        NewPackageItem *pItem = m_PackageItems[i];
        if (strcasecmp(pItem->FileName, szFileName))
        {
            m_PackageItems.erase(m_PackageItems.begin() + i);
            return true;
        }
    }
}

bool CNewPackage::HasFile(const char *szFileName)
{
    //从待添加的文件查找
    for (size_t i = 0; i < m_AddFiles.size(); i++)
    {
        if (strcasecmp(m_AddFiles[i].c_str(), szFileName) == 0)
        {
            return true;
        }
    }

    //从包裹文件中查找
    for (size_t i = 0; i < m_PackageItems.size(); i++)
    {
        NewPackageItem *pItem = m_PackageItems[i];
        if (strcasecmp(pItem->FileName, szFileName) == 0)
        {
            return true;
        }
    }
}

inline size_t NewPackageEncryptWrite( CQuickCryptor & Cryptor, const void*pBuffer, size_t Size, FILE*fp )
{
    unsigned char*pByteBuffer = (unsigned char*)malloc( Size );
    if( !pByteBuffer )
    {
        return 0;
    }
    memcpy( pByteBuffer, pBuffer, Size );
    Cryptor.Encrypt( pByteBuffer, Size );
    size_t WriteSize = fwrite( pByteBuffer, 1, Size, fp );
    free( pByteBuffer );
    return WriteSize;   
}

inline size_t NewPackageDecryptRead( CQuickCryptor & Cryptor, void*pBuffer, size_t Size, FILE*fp )
{
    size_t ReadSize = fread( pBuffer, 1, Size, fp );
    Cryptor.Decrypt( pBuffer, ReadSize );
    return ReadSize;
}

bool CNewPackage::SavePackage(const char *szPackageName, const char*szPassword)
{
    FILE *fpPackage = fopen(szPackageName, "wb");
    if (!fpPackage)
    {
        fprintf(stderr, " fopen %s error %s \n", szPackageName, strerror(errno));
        return false;
    }

    CQuickCryptor Crptor;
    Crptor.Init(szPassword);

    //写入文件头标识
    if( sizeof( MY_PACKAGE_FLAG ) != NewPackageEncryptWrite(Crptor, MY_PACKAGE_FLAG, sizeof( MY_PACKAGE_FLAG ), fpPackage ) )
    {
        fprintf(stderr, " 写入文件头信息失败 error %s \n", strerror(errno));
        return false;
    }

    PackageInfo Info;
    Info.EncryptMethod = MY_ENCRYPT_METHOD_XOR;
    if( sizeof( Info ) != NewPackageEncryptWrite(Crptor, &Info, sizeof( Info ), fpPackage ) )
    {
        fprintf(stderr, " 写入文件信息 error %s \n", strerror(errno));
        return false;
    }

    //将包裹中原有的文件 和 待添加的文件 全部放入这个WriteItems中
    std::vector<FileItemForWrite> WriteItems;

    //预留一个sizeof(size_t)的大小,TotalHeadIndexSize是n个PackageItem所占的字节数
    size_t TotalHeadIndexSize = sizeof(size_t);

    //处理待添加的文件
    for (size_t i = 0; i < m_AddFiles.size(); i++)
    {
        FILE *fpRead = fopen(m_AddFiles[i].c_str(), "rb");
        if (!fpRead)
        {
            fprintf(stderr, "fopen %s error %s \n", m_AddFiles[i].c_str(), strerror(errno));
            return false;
        }
        fseek(fpRead, 0, SEEK_END);

        //填充FileItemForWrite信息
        FileItemForWrite Item;
        Item.fp = fpRead;
        Item.FileOffset = 0;
        Item.FileSize = ftell(fpRead);
        Item.FileName = m_AddFiles[i];
        size_t FileNameLen = Item.FileName.length() + 1;

        //申请一块内存存放文件的头部信息
        NewPackageItem *pNewItem = (NewPackageItem *)malloc(sizeof(NewPackageItem) + FileNameLen);
        if (!pNewItem)
        {
            continue;
        }
        Item.pPackageItem = pNewItem;

        //填充文件的头部信息
        pNewItem->FileNameLen = FileNameLen;
        pNewItem->FileSize = Item.FileSize;
        strcpy(pNewItem->FileName, m_AddFiles[i].c_str());

        //更新TotalHeadIndexSize的大小
        TotalHeadIndexSize += sizeof(NewPackageItem) + FileNameLen;

        //将待写入的文件添加到容器中
        WriteItems.push_back(Item);
    }

    //处理原来包裹中已经存在的文件
    for (size_t i = 0; i < m_PackageItems.size(); i++)
    {
        NewPackageItem *pItem = m_PackageItems[i];

        FileItemForWrite Item;
        Item.fp = m_fpPackage;
        Item.FileOffset = pItem->OffsetPackage;
        Item.FileSize = pItem->FileSize;
        Item.FileName = pItem->FileName;

        size_t FileNameLen = Item.FileName.length();
        NewPackageItem *pNewItem = (NewPackageItem *)malloc(sizeof(NewPackageItem) + FileNameLen);
        if (!pNewItem)
        {
            continue;
        }
        Item.pPackageItem = pNewItem;

        pNewItem->FileNameLen = FileNameLen;
        pNewItem->FileSize = Item.FileSize;
        strcpy(pNewItem->FileName, Item.FileName.c_str());

        TotalHeadIndexSize += sizeof(NewPackageItem) + pNewItem->FileNameLen;

        WriteItems.push_back(Item);
    }

    //有多少个PackageItem
    size_t TotalPackageItems = WriteItems.size();

    //开始写入文件
    if( sizeof( TotalPackageItems ) != NewPackageEncryptWrite(Crptor, &TotalPackageItems, sizeof( TotalPackageItems ), fpPackage ) )
    {
        fprintf(stderr, "fwrite %lu error %s \n ", TotalPackageItems, strerror(errno));
        return false;
    }

    //记录当前的文件指针位置
    size_t IndexOffset = ftell(fpPackage);
    //预留TotalHeadIndexSize的空间供索引写入
    fseek(fpPackage, TotalHeadIndexSize, SEEK_SET);

    //先写入文件
    bool bError = false;
    size_t CurOffset = TotalHeadIndexSize;
    for (size_t i = 0; i < WriteItems.size(); i++)
    {
        FileItemForWrite &Item = WriteItems[i];
        if (bError == false)
        {
            //填充偏移信息
            Item.pPackageItem->OffsetPackage = CurOffset;
            //更新偏移信息
            CurOffset += Item.FileSize;

            //将要写入的文件的文件指针移动到文件头
            fseek(Item.fp, Item.FileOffset, SEEK_SET);

            char szBuffer[65536];
            size_t LeftSize = Item.FileSize;
            while (1)
            {
                //实际要读取的大小
                size_t ReadSize = LeftSize;
                //如果大于缓冲区,我们就只读取缓冲区大小的内容,剩余的下次读取
                if (ReadSize > sizeof(szBuffer))
                {
                    ReadSize = sizeof(szBuffer);
                }
                //读取文件
                size_t nReadBytes = fread(szBuffer, 1, ReadSize, Item.fp);
                //ReadSize必须要等于nReadBytes
                if (ReadSize != nReadBytes)
                {
                    fprintf(stderr, "读取 %s 失败 %s\n",Item.FileName.c_str(), strerror(errno));
                    bError = true;
                    break;
                }
                //写入包裹
                if( nReadBytes != NewPackageEncryptWrite(Crptor, szBuffer, nReadBytes, fpPackage ) )
                {
                    fprintf(stderr, "读取 %s 失败 %s\n",szPackageName, strerror(errno));
                    bError = true;
                    break;
                }
                LeftSize -= nReadBytes;
                //如果剩余大小为0,就读取完成了
                if (LeftSize == 0)
                {
                    break;
                }
            }
        }

        //关闭需要打包的文件
        if (Item.fp != m_fpPackage)
        {
            fclose(Item.fp);
            Item.fp = NULL;
        }
    }

    //如果没错误,写入索引
    if (!bError)
    {
        fseek(fpPackage, IndexOffset, SEEK_SET);
        for (size_t i = 0; i < WriteItems.size(); i++)
        {
            FileItemForWrite &Item = WriteItems[i];
            NewPackageItem *pItem = Item.pPackageItem;

            if (!bError)
            {
                //加密写入,我们先写入文件名长度
                if( sizeof( pItem->FileNameLen ) != NewPackageEncryptWrite( Crptor, &pItem->FileNameLen, sizeof( pItem->FileNameLen ), fpPackage ) )
                {
                    printf( "写入%s失败,打包失败\n", szPackageName );
                    bError = true;
                }

                if( !bError )
                {
                    //写入剩余的内容
                    int WriteSize = sizeof( NewPackageItem ) + pItem->FileNameLen - sizeof( pItem->FileNameLen );
                    if( WriteSize != NewPackageEncryptWrite( Crptor, ((unsigned char*)pItem) + sizeof( pItem->FileNameLen ), WriteSize, fpPackage ) )
                    {
                        printf( "写入%s失败,打包失败\n", szPackageName );
                        bError = true;
                    }
                }
            }
            free(pItem);
        }
    }

    fclose(fpPackage);

    return !bError;
}

bool CNewPackage::OpenPackage(const char *szPackageName, const char*szPassword)
{
    ResetPackage();

    m_Cryptor.Init( szPassword );

    m_fpPackage = fopen(szPackageName, "rb");
    if (!m_fpPackage)
    {
        fprintf(stderr, "打开 %s 失败 %s\n",szPackageName, strerror(errno));
        return false;
    }

    //读入文件头标识
    char FileFlag[ sizeof( MY_PACKAGE_FLAG ) ];
    if( sizeof( MY_PACKAGE_FLAG ) != NewPackageDecryptRead(m_Cryptor, FileFlag, sizeof( FileFlag ), m_fpPackage ) )
    {
        fprintf(stderr, "读取文件头标识失败 %s\n", strerror(errno));
        return false;
    }

    //判断一下我们读取到的文件头是否是我们定义的,做个最简单的格式判断
    if( memcmp( FileFlag, MY_PACKAGE_FLAG, sizeof( FileFlag ) ) != 0 )
    {
        fprintf( stderr, "包裹%s格式错误\n", szPackageName );
        return false;
    }
    PackageInfo Info;
    if( sizeof( Info ) != NewPackageDecryptRead(m_Cryptor, &Info, sizeof( Info ), m_fpPackage ) )
    {
        fprintf( stderr, "读取%s失败 %s\n", szPackageName, strerror(errno));
        return false;
    }
    if( Info.EncryptMethod != MY_ENCRYPT_METHOD_XOR )
    {
        fprintf( stderr, "无法识别%s的加密格式\n", szPackageName );
        return false;
    }


    //先读取包裹中Item的个数
    size_t PackageItemCount = 0;
    if( sizeof( PackageItemCount ) != NewPackageDecryptRead(m_Cryptor, &PackageItemCount, sizeof( PackageItemCount ), m_fpPackage ) )
    {
        fprintf(stderr, "读取%s失败 %s\n", szPackageName, strerror(errno));
        return false;
    }

    //根据读到的Item的个数遍历,把所有包裹中的文件放入m_PackageItems中
    for (size_t i = 0; i < PackageItemCount; i++)
    {
        //先读取文件名的长度,因为文件名是变长的,方便后面申请内存
        size_t FileNameLen = 0;
        if( sizeof( FileNameLen ) != NewPackageDecryptRead(m_Cryptor, &FileNameLen, sizeof( FileNameLen ), m_fpPackage ) )
        {
            fprintf(stderr, "读取%s失败 %s\n", szPackageName, strerror(errno));
            return false;
        }

        char *pBuffer = (char *)malloc(sizeof(NewPackageItem) + FileNameLen);
        if (!pBuffer)
        {
            fprintf(stderr, "读取%s失败 %s\n", szPackageName, strerror(errno));
            return false;
        }
        NewPackageItem *pItem = (NewPackageItem *)pBuffer;
        pItem->FileNameLen = FileNameLen;

        //我们已经读取FileNameLen了,所以剩余读取的部分减掉FileNameLen
        size_t ReadSize = sizeof(NewPackageItem) + FileNameLen - sizeof(FileNameLen);
        if( ReadSize != NewPackageDecryptRead(m_Cryptor, pBuffer + sizeof( FileNameLen ), ReadSize, m_fpPackage ) )
        {
            fprintf(stderr, "读取%s失败 %s\n", szPackageName, strerror(errno));
            return false;
        }
        m_PackageItems.push_back(pItem);
    }
    return true;
}

bool CNewPackage::ExportPackageItem(const char *szFileName, CFileBuffer &FileBuffer)
{
    //先从待添加的文件查找
    for (size_t i = 0; i < m_AddFiles.size(); i++)
    {
        if (strcasecmp(m_AddFiles[i].c_str(), szFileName) == 0)
        {
            FILE *fp = fopen(szFileName, "rb");
            if (!fp)
            {
                return false;
            }
            fseek(fp, 0, SEEK_END);
            size_t Size = ftell(fp);
            fseek(fp, 0, SEEK_SET);
            //申请内存
            if (!FileBuffer.Create(Size))
            {
                fclose(fp);
                return false;
            }
            //把文件读入内存中
            if (Size != fread(FileBuffer.GetBuffer(), 1, Size, fp))
            {
                fclose(fp);
                return false;
            }
            return true;
        }
    }
    //再从包裹文件中查找
    for (size_t i = 0; i < m_PackageItems.size(); i++)
    {
        NewPackageItem *pItem = m_PackageItems[i];
        if (strcasecmp(pItem->FileName, szFileName) == 0)
        {
            if (!FileBuffer.Create(pItem->FileSize))
            {
                return false;
            }
            fseek(m_fpPackage, pItem->OffsetPackage, SEEK_SET);
            if( pItem->FileSize != NewPackageDecryptRead(m_Cryptor,FileBuffer.GetBuffer(), pItem->FileSize, m_fpPackage ) )
            {
                return false;
            }
            return true;
        }
    }
    return false;
}

main.cpp

#include "NewPackage.h"


int main(void)
{
    CNewPackage pkg;
    pkg.AddFile( "test1.txt" );
    pkg.AddFile( "test2.txt" );
    pkg.AddFile( "test3.txt" );
    pkg.SavePackage( "test.pkg","abcd");
    pkg.RemoveFile( "test2.txt" );
    pkg.SavePackage( "test1.pkg","abcd");
    
    pkg.OpenPackage( "test1.pkg","abcd");
    CFileBuffer bf;
    pkg.ExportPackageItem( "test3.txt", bf );
    bf.Save( "testout.txt" );

    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!