• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            3d Game Walkman

            3d圖形渲染,網絡引擎 — tonykee's Blog
            隨筆 - 45, 文章 - 0, 評論 - 309, 引用 - 0
            數據加載中……

            上午寫了兩個類,實現了自定義資源文件,數據流的存取,一個字爽

            精確的概括是:

            按名稱從資源文件里面讀和寫二進制raw數據(raw在文件里面是按zlib壓縮的形式存儲的)

            這樣我就可以把一些文件資源用對應的api讀入到內存的buffer中去,然后通過我的資源庫壓縮buffer再寫入到資源文件里面去,下次真正調用的時候讀出來解壓還原到內存的buffer里面去使用。

            下面要做的事情就是把游戲里面所有的資源文件都打包了。
            只是目前還沒有加上加密的算法

            //看一段測試代碼
            void testFilestream()
            {
               FileStream filestream;
               filestream.Open("aaa.bin", "r+");
               char *p=0;
               DWORD ln = 0;
               char *src = "hello,a big boy";
               filestream.Write("xxx.xxx", src, strlen(src));

               filestream.Read("xxx.xxx", (void **)&p, ln);
              
               printf("%s :%d\r\n", p, ln);
               DELS(p);
               filestream.Close();
            }

            結果:

            hello,a big boy :15
            請按任意鍵繼續. . .

            源碼如下:
            /************************************************************************/
            /* 按命名從資源文件里面讀和寫raw數據(raw在文件里面是按zlib壓縮的形式存儲的)
            /************************************************************************/
            #pragma once
            #ifndef FILESTREAM_H
            #define FILESTREAM_H


            #include <stdio.h>
            #include <WTypes.h>
            #include <string>
            #include <assert.h>
            #include "../include/zlib.h"
            #pragma comment(lib,"../lib/zdll.lib")


            namespace LK3D
            {
            class FileStream;

            //////////////////////////////////////////////////////////////////////////////////////
            // 文件或數據流(不支持同時讀寫多個數據區,只能一次對FileStream的一個數據區進行讀寫操作)
            class FileDataStreamBuffer
            {
            private:
             
             DWORD  zipbuflen;       //zip raw buffer len    
             void * zipbuf;          //zip raw buffer         壓縮字節流
             
             //按照buflen重新分配空間
             void realloc();

             DWORD  srcbuflen;       //source raw buffer len 

             std::string dataname;   //該數據流的名字

            public:

             DWORD GetSrcBufLen();

             //構造
                FileDataStreamBuffer(const char *dname);

             //析構
             ~FileDataStreamBuffer();

             //寫字節,寫之前一定要設定dataname
             DWORD WriteBytes(const void *from,DWORD len);

             //讀字節,寫之前一定要設定dataname
             DWORD ReadBytes(void *to);

             //debug
             void DumpBuffer();

                DWORD GetLen() const;   //總長度,是計算出來的

                bool operator ==(const FileDataStreamBuffer &other) const;

                friend class FileStream;
            };

             


            class FileStream
            {
            FILE *pFile;

            private:

             //寫文件包,寫之前一定要設定filebuf.dataname
             DWORD Write(FileDataStreamBuffer& filebuf);

             //讀文件包,讀之前一定要設定filebuf.dataname
             DWORD Read(FileDataStreamBuffer& filebuf);

             

            public:

             FileStream(void);
             
             ~FileStream(void);
             
             //打開一個文檔
             DWORD Open(const char* archive,const char *mode);
             
             //寫某個數據段落
             DWORD Write(const char* dname, const void *from, DWORD len);

             //讀取某個數據段落
             DWORD Read(const char* dname, void **to, DWORD &len);

             //關閉文件流
             void Close();

             friend void testFileStream();
            };

            void testFileStream();

            void testFileStream1();
            }
            #endif

            //FileStream.cpp

            #include "FileStream.h"

            #ifndef DEL
            #define DEL(p)  { if(p) { delete (p); (p) = NULL; } }
            #endif

            #ifndef DELS
            #define DELS(p)  { if(p) { delete[] (p); (p) = NULL; } }
            #endif

            #ifndef RELEASE
            #define RELEASE(p)  { if(p) { (p)->Release(); (p) = NULL; } }
            #endif

            using namespace LK3D;

            FileDataStreamBuffer::FileDataStreamBuffer(const char *dname)
            {
             zipbuflen = 0;
             zipbuf = 0;
             srcbuflen = 0;
             dataname = dname;
            }


            DWORD FileDataStreamBuffer::GetSrcBufLen()
            {
                return srcbuflen;
            }

            FileDataStreamBuffer::~FileDataStreamBuffer()
            {
             DELS(zipbuf);
            }


            void FileDataStreamBuffer::realloc()
            {
                DELS(zipbuf);
             zipbuf = new char[zipbuflen];
            }


            bool FileDataStreamBuffer::operator ==(const FileDataStreamBuffer &other) const
            {
              return GetLen() == other.GetLen() &&
                  dataname == other.dataname &&
               zipbuflen == other.zipbuflen &&
               memcmp((const char *)zipbuf, (const char *)other.zipbuf, zipbuflen) == 0 &&
               srcbuflen == other.srcbuflen;
            }


            DWORD FileDataStreamBuffer::GetLen() const
            {
               //     文件名長度占位  文件名長度               srcbuf長度占位  zipbuf長度占位  zipbuf長度
               return sizeof(DWORD) + (DWORD)dataname.size() + sizeof(DWORD) + sizeof(DWORD) + zipbuflen;
            }

             

            //寫字節
            DWORD FileDataStreamBuffer::WriteBytes(const void *from,DWORD len)
            {
               if(dataname.empty())
                   return 0;    //還未給要寫入的部分命名

               if(!from)
                return 0;
              
               //記錄原字節數據區的長度
               srcbuflen = len;

               //重新分配zipbuf的空間
               //DELS(zipbuf);
               zipbuflen =(DWORD)(len+ (len * 0.1) + 12); //這是個公式,官方網站上提供的,預留的最小的壓縮空間的大小
              
               realloc();
              
               //壓縮原數據到zipbuf中去
               compress2((Bytef*)zipbuf,(uLongf*)&zipbuflen,(const Bytef*)from,(uLongf)srcbuflen, Z_DEFAULT_COMPRESSION);

               return len;
            }

            //讀字節
            DWORD FileDataStreamBuffer::ReadBytes(void *to)
            {
               //if(dataname.empty())
                //  return 0;    //還未給要讀取的部分命名

               if(!to)
               return 0;

               uncompress((Bytef*)to, (uLongf *)&srcbuflen, (const Bytef*)zipbuf, (uLong)zipbuflen);

               return zipbuflen;
            }

             

            void FileDataStreamBuffer::DumpBuffer()
            {
             DWORD len = zipbuflen;
             printf("Buffer: size=%d", len);
             if (len > 0)
             {
              printf("  [ ");
              const UCHAR* pBuf = (const UCHAR*) zipbuf;
              for (DWORD i = 0; i < len; ++i)
               printf("%02X ", pBuf[i]);
              printf("]");
             }
             printf("\n");
            }

             

            FileStream::FileStream(void)
            {
             pFile = 0;
            }


            FileStream::~FileStream(void)
            {
             Close();
            }

             //打開一個文檔
            DWORD FileStream::Open(const char* archive,const char *mode)
            {
             pFile = fopen(archive, mode);
             assert(pFile);

             return 0;
            }

            //寫文件包
            DWORD FileStream::Write(FileDataStreamBuffer& filebuf)
            {
             if(filebuf.dataname.empty())
             {
              return 0; //指定要讀取的數據區的名稱
             }

             DWORD writebytes = 0;
             
             //寫入文件名的長度占位
             DWORD filenamelen = (DWORD)filebuf.dataname.size();
                writebytes+=(DWORD)(fwrite(&filenamelen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));

             //寫入文件名
             writebytes+=(DWORD)(fwrite(filebuf.dataname.c_str(), sizeof(char), filebuf.dataname.size(), pFile) * sizeof(char));

             //寫入srcbuf長度的占位
             writebytes+=(DWORD)(fwrite(&filebuf.srcbuflen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));

             //寫入zipbuf的長度占位
             writebytes+=(DWORD)(fwrite(&filebuf.zipbuflen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));

             //寫入zipbuf
             writebytes+=(DWORD)(fwrite(filebuf.zipbuf, sizeof(char), filebuf.zipbuflen, pFile) * sizeof(char));

             return writebytes;
            }


            //讀文件包
            DWORD FileStream::Read(FileDataStreamBuffer& filebuf)
            {
               if(filebuf.dataname.empty())
               {
                return 0; //指定要讀取的數據區的名稱
               }

               //從文件頭開始
               rewind(pFile);
               char filename[100]; //文件名預留100應該足夠了
               ZeroMemory(filename, 100);

               //實際讀取的數量
               DWORD readbytes = 0;
               bool founded = false;


              // bool bt = false;
              // fseek(filebuf,1000, SEEK_CUR);

               while(filebuf.dataname != filename)
               {  

                //讀入文件名長度的占位
                DWORD filenamelen = 0;
                readbytes += (DWORD)(fread(&filenamelen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));

                if(readbytes == 0)
                 break; //已經無法讀取數據了,說明已經eof了

                //讀入文件名
                readbytes += (DWORD)(fread(&filename, sizeof(char), filenamelen, pFile) * sizeof(char));

                //讀入srcbuf長度占位
                readbytes += (DWORD)(fread(&filebuf.srcbuflen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));

                //讀入zipbuf長度占位
                readbytes += (DWORD)(fread(&filebuf.zipbuflen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));
               
                if(filebuf.dataname == filename)
                {
                 //重新分配可以裝載數據的空間
                       filebuf.realloc();
                 readbytes += (DWORD)(fread(filebuf.zipbuf, sizeof(char), filebuf.zipbuflen, pFile) * sizeof(char));
                       founded = true;
                 break;
                }
                else
                {
                 readbytes = 0;  //重新計數
                 //不是要找的data直接后移filebuf.zipbuflen
                 fseek(pFile, filebuf.zipbuflen, SEEK_CUR);
                 filebuf.zipbuflen = 0; //讀取的zipbuffer長度也清0,作廢處理
                 filebuf.srcbuflen = 0; //讀取的srcbuffer長度也清0,作廢處理
                }
                ZeroMemory(filename, 100);
               }

               if(founded)
                   return readbytes; //返回實際讀取的字節數
               else
                return 0;         //讀取失敗了
            }

             

             

            //關閉文件流
            void FileStream::Close()
            {
             if(pFile)
             {
              fclose(pFile);
              pFile = 0;
             }
            }


            DWORD FileStream::Write(const char* dname, const void *from,DWORD len)
            {
               FileDataStreamBuffer streambuf(dname);
               if(!streambuf.WriteBytes(from, len))
                 return 0;

               return Write(streambuf);
            }

             


            DWORD FileStream::Read(const char* dname, void **to, DWORD &len)
            {
             FileDataStreamBuffer streambuf(dname);

                if(Read(streambuf))
             {
               if(*to)
               {
                 printf("warning, 銷毀接收緩沖...");
              DELS(*to)
               }
               len = streambuf.GetSrcBufLen();
               *to = new char[len];
               streambuf.ReadBytes(*to);
               return len;
             }
             else
              return 0;
            }


            void LK3D::testFileStream()
            {
              FileDataStreamBuffer f1("file1.txt");
              char *str1 ="one 111";
              f1.WriteBytes(str1, (DWORD)strlen(str1));
             


              FileDataStreamBuffer f2("file2.txt");
              char *str2 ="a111111111111111111b";
              f2.WriteBytes(str2, (DWORD)strlen(str2));

              FileStream stream;
             
              //寫
              stream.Open("aaa.bin", "wb");
              DWORD d1 = stream.Write(f1);
              DWORD d2 = stream.Write(f2);

              assert(d1 == f1.GetLen());
              assert(d2 == f2.GetLen());

              stream.Close();

              f2.DumpBuffer();

              //讀
              FileStream stream1;
              stream1.Open("aaa.bin", "rb");

              FileDataStreamBuffer val_bf("file2.txt");
              DWORD vd2 = stream1.Read(val_bf);
              stream1.Close();

              val_bf.DumpBuffer();


              if(vd2)
              {
               assert(vd2 == d2);
               assert(f2 == val_bf);

               char *c = new char[val_bf.GetSrcBufLen() +1];
               ZeroMemory(c, val_bf.GetSrcBufLen() +1);
               val_bf.ReadBytes(c);
               printf("%s \r\n", c);
              } else
              {
               printf("沒找到數據\r\n");
              }
             
            }


            void LK3D::testFileStream1()
            {
               FileStream filestream;
               filestream.Open("aaa.bin", "r+");
               char *p=0;
               DWORD ln = 0;
               char *src = "hello,a big boy";
               filestream.Write("xxx.xxx", src, (DWORD)strlen(src));

               filestream.Read("xxx.xxx", (void **)&p, ln);
              
               printf("%s :%d\r\n", p, ln);
               DELS(p);
               filestream.Close();
            }

             

            posted on 2008-03-08 15:02 李侃 閱讀(3081) 評論(6)  編輯 收藏 引用 所屬分類: 網絡模塊

            評論

            # re: 上午寫了兩個類,實現了自定義資源文件,數據流的存取,一個字爽  回復  更多評論   

            兩年前搞了個帶分頁的file,每4KB一個頁,這樣package的內容就可以隨時修改而不用解包數據再打包;碎片多了再重新整理...不過bug很多,而且也覺得沒啥必要就放棄了...現在覺得boost的iostreams和serialization不錯.
            2008-03-08 15:30 | 空明流轉

            # re: 上午寫了兩個類,實現了自定義資源文件,數據流的存取,一個字爽  回復  更多評論   

            http://www.xzllq.cn
            2008-03-08 16:01 | 征途私服

            # re: 上午寫了兩個類,實現了自定義資源文件,數據流的存取,一個字爽  回復  更多評論   

            boost 庫感覺太復雜,看源碼好辛苦啊,memory 序列化已經實現,現在想寫文件序列化,可能會說我再做重復勞動,可自己寫也會有很多好處的。

            我現在只是想做個輕量級的,游戲資源包生成器,上面的方案對于修改來說的確是個問題。

            還有兩個思路

            1. 寫個腳本,用執行腳本的方式來生成資源包文件,并且資源包分類,多搞一些資源包,生成資源包嚴格用腳本來控制,“慢”就慢一點,方便就好,最重要的是保證讀取和運行的效率高,修改那個資源包就重新生成哪個資源包。

            2. 如果要修改文件,把整個文件都讀入到 vector<char> buf 里面去然后對vector<char>buf 進行修改,然后一次性覆蓋回去實現修改。
            2008-03-08 22:49 | 李侃

            # re: 上午寫了兩個類,實現了自定義資源文件,數據流的存取,一個字爽  回復  更多評論   

            思路3
            直接打包文件進行操作

            實現數據塊向前搬移操作,這個相當于刪除操作了
            而 刪除+添加=修改

            不需要太高效的情況下,這個方法思路更好一些
            2008-03-08 23:11 | 李侃

            # re: 上午寫了兩個類,實現了自定義資源文件,數據流的存取,一個字爽  回復  更多評論   

            為什么要 friend class FileStream;
            這樣有什么好處嗎?不會用友元這個東東!望賜教!
            2008-10-07 14:06 | RichardHe

            # re: 上午寫了兩個類,實現了自定義資源文件,數據流的存取,一個字爽  回復  更多評論   

            可以看看mpqlib,讀寫暴雪的mpq文件的
            2009-02-28 19:30 | liuc
            久久亚洲av无码精品浪潮| 亚洲精品乱码久久久久久| 少妇久久久久久被弄高潮| 免费一级做a爰片久久毛片潮| 欧美精品一区二区精品久久| 人人狠狠综合久久88成人| 伊人久久大香线蕉综合热线| 久久播电影网| 欧美激情精品久久久久久久九九九| 久久伊人精品青青草原高清| 国产亚洲婷婷香蕉久久精品| 国产精品久久久久影院色| 久久久久女人精品毛片| 99久久成人国产精品免费| 欧美熟妇另类久久久久久不卡| 亚洲日本va中文字幕久久| 亚洲色大成网站WWW久久九九| 99精品久久久久久久婷婷| 久久99国产综合精品免费| 91精品国产综合久久香蕉| 久久天天日天天操综合伊人av| 日韩亚洲国产综合久久久| 精品久久久久久久国产潘金莲| 熟妇人妻久久中文字幕| 91久久国产视频| 亚洲精品美女久久久久99| 久久婷婷五月综合国产尤物app | 久久久久久国产精品无码下载| 免费精品久久天干天干| 国产精品久久久久久久久鸭| 91久久精品国产成人久久| 亚洲国产精品狼友中文久久久 | 99久久夜色精品国产网站| 国产精品99精品久久免费| 久久久久人妻精品一区三寸蜜桃| 中文字幕久久精品无码| 国产精品无码久久久久| 亚洲中文久久精品无码ww16| 国产精品成人精品久久久 | 久久人人妻人人爽人人爽| 国产精品欧美久久久久无广告 |