<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>C++ &#8211; 编程技术记录</title>
	<atom:link href="https://blog.z6z8.cn/category/%E4%BB%A3%E7%A0%81%E7%89%87%E6%AE%B5/c/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.z6z8.cn</link>
	<description>世界你好!</description>
	<lastBuildDate>Fri, 04 Sep 2020 08:58:35 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>判断Unicode码是否落在了中文区间</title>
		<link>https://blog.z6z8.cn/2020/09/04/%e5%88%a4%e6%96%adunicode%e7%a0%81%e6%98%af%e5%90%a6%e8%90%bd%e5%9c%a8%e4%ba%86%e4%b8%ad%e6%96%87%e5%8c%ba%e9%97%b4/</link>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Fri, 04 Sep 2020 08:58:35 +0000</pubDate>
				<category><![CDATA[C++]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=886</guid>

					<description><![CDATA[static inline BOOL isChineseC(u_long ch) { ///https://w [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>static inline BOOL isChineseC(u_long ch)<br />
{<br />
///<a href="https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php">https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php</a><br />
return (<br />
(/<em>基本汉字</em>/ ch &gt;= 0x4E00 &amp;&amp; ch &lt;= 0x9FA5) ||<br />
(/<em>基本汉字补充</em>/   ch &gt;= 0x9FA6 &amp;&amp; ch &lt;= 0x9FEF) ||<br />
(/<em>扩展A</em>/ ch &gt;= 0x3400 &amp;&amp; ch &lt;= 0x4DB5) ||<br />
(/<em>扩展B</em>/ ch &gt;= 0x20000 &amp;&amp; ch &lt;= 0x2A6D6) ||<br />
(/<em>扩展C</em>/ ch &gt;= 0x2A700 &amp;&amp; ch &lt;= 0x2B734) ||<br />
(/<em>扩展D</em>/ ch &gt;= 0x2B740 &amp;&amp; ch &lt;= 0x2B81D) ||<br />
(/<em>扩展E</em>/ ch &gt;= 0x2B820 &amp;&amp; ch &lt;= 0x2CEA1) ||<br />
(/<em>扩展F</em>/ ch &gt;= 0x2CEB0 &amp;&amp; ch &lt;= 0x2EBE0) ||<br />
(/<em>扩展G</em>/ ch &gt;= 0x30000 &amp;&amp; ch &lt;= 0x3134A) ||<br />
(/<em>康熙部首</em>/ ch &gt;= 0x2F00 &amp;&amp; ch &lt;= 0x2FD5) ||<br />
(/<em>部首扩展</em>/ ch &gt;= 0x2E80 &amp;&amp; ch &lt;= 0x2EF3) ||<br />
(/<em>兼容汉</em>/ ch &gt;= 0xF900 &amp;&amp; ch &lt;= 0xFAD9) ||<br />
(/<em>兼容扩展</em>/ ch &gt;= 0x2F800 &amp;&amp; ch &lt;= 0x2FA1D) ||<br />
(/<em>PUA(GBK)部件</em>/ ch &gt;= 0xE815 &amp;&amp; ch &lt;= 0xE86F) ||<br />
(/<em>部件扩展</em>/ ch &gt;= 0xE400 &amp;&amp; ch &lt;= 0xE5E8) ||<br />
(/<em>PUA增补</em>/ ch &gt;= 0xE600 &amp;&amp; ch &lt;= 0xE6CF) ||<br />
(/<em>汉字笔画</em>/ ch &gt;= 0x31C0 &amp;&amp; ch &lt;= 0x31E3) ||<br />
(/<em>汉字结构</em>/ ch &gt;= 0x2FF0 &amp;&amp; ch &lt;= 0x2FFB) ||<br />
(/<em>汉语注音</em>/ ch &gt;= 0x3105 &amp;&amp; ch &lt;= 0x312F) ||<br />
(/<em>注音扩展</em>/ ch &gt;= 0x31A0 &amp;&amp; ch &lt;= 0x31BA) ||<br />
(/<em>〇</em>/    ch == 0x3007)<br />
);<br />
}</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>快速排序C++实现</title>
		<link>https://blog.z6z8.cn/2019/12/25/%e5%bf%ab%e9%80%9f%e6%8e%92%e5%ba%8fc%e5%ae%9e%e7%8e%b0/</link>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Wed, 25 Dec 2019 11:31:07 +0000</pubDate>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[代码片段]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=684</guid>

					<description><![CDATA[自己都忘了什么时候写的了，@_@ #pragma once #include &#60;list&#62; #in [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>自己都忘了什么时候写的了，@_@</p>
<pre><code class="language-cpp">#pragma once

#include &lt;list&gt;
#include &lt;vector&gt;
#include &lt;stack&gt;

using namespace std;

struct Bound
{
    size_t low;
    size_t high;
    Bound(size_t lowind,size_t highind)
    {
        this-&gt;low=lowind;
        this-&gt;high=highind;
    }
};
template &lt;typename T&gt;
void QSort(vector&lt;T&gt; &amp; vay) //从小到大排序
{
    size_t len=vay.size();
    if( len &gt; 2)
    {
        stack&lt;Bound&gt; boundS;
        Bound bd(0,len-1);
        boundS.push(bd);

        size_t low,high;
        while( ! boundS.empty() ) //当栈不为空时
        {
            bd=boundS.top();//取栈顶元素
            low=bd.low;
            high=bd.high;
            boundS.pop();//弹出栈顶元素

            low++;//用数组的排序部分的首个元素作为关键值，进行比较

            while( true ) //进行二分数组排序
            {
                while( low &lt; high &amp;&amp; vay[low] &lt;= vay[bd.low] ) //用数组的排序部分的首个元素作为关键值，进行比较
                {
                    low++;
                }
                while( low &lt; high &amp;&amp; vay[high] &gt; vay[bd.low] ) //vay[high] &gt; vay[bd.low] 不能用 &gt;=，因为要二分数组的排序部分，保证两部分的排他性
                {
                    high--;
                }
                if( low &lt; high )
                {//交换低索引和高索引元素
                    T tmp=vay[low];
                    vay[low]=vay[high];
                    vay[high]=tmp;
                }
                else 
                {//此时，low == high 为真
                    break;
                }
            }

            //此时，low == high 为真
            if( vay[low] &gt; vay[bd.low] )
            {
                low--;
            }
            //将关键值插入大元素和小元素的分界
            T tmp=vay[low];
            vay[low]=vay[bd.low];
            vay[bd.low]=tmp;

            if( low - bd.low &gt; 1 ) //若小元素部分元素个数大于1个，继续排序
            {
                Bound newbd(bd.low,low-1);
                boundS.push(newbd);
            }
            if( bd.high - low &gt; 1)//若大元素部分元素个数大于1个，继续排序
            {
                Bound newbd(low+1,bd.high);
                boundS.push(newbd);
            }
        }
    }
    else if( len == 2) //若数组长度为2，直接比较
    {
        if( vay[0] &gt; vay[1] )
        {
            T tmp=vay[0];
            vay[0]=vay[1];
            vay[1]=tmp;
        }
    }
    //若数组长度小于2，不用排序
}

template &lt;typename T&gt;
struct BoundIter
{
    BoundIter(typename list&lt;T&gt;::iterator lowiter,typename list&lt;T&gt;::iterator highiter)
    {
        this-&gt;low=lowiter;
        this-&gt;high=highiter;
    }
    typename list&lt;T&gt;::iterator low;
    typename list&lt;T&gt;::iterator high;
};

template &lt;typename T&gt;
void QSort(list&lt;T&gt; &amp; lst) //从小到大排序
{
    if( lst.size() &gt; 2)
    {
        stack&lt;BoundIter&lt;T&gt;&gt; boundIterS;
        BoundIter&lt;T&gt; bd(lst.begin(),(--lst.end()));
        boundIterS.push(bd);

        list&lt;T&gt;::iterator low,high;
        while( ! boundIterS.empty() ) //当栈不为空时
        {
            bd=boundIterS.top();//取栈顶元素
            low=bd.low;
            high=bd.high;
            boundIterS.pop();//弹出栈顶元素

            low++;//用数组的排序部分的首个元素作为关键值，进行比较

            while( true ) //进行二分数组排序
            {
                while( low != high &amp;&amp; *low &lt;= *(bd.low) ) //用数组的排序部分的首个元素作为关键值，进行比较
                {
                    low++;
                }
                while( low != high &amp;&amp; *high &gt; *(bd.low) ) //*high &gt; *(bd.low) 不能用 &gt;=，因为要二分数组的排序部分，保证两部分的排他性
                {
                    high--;
                }
                if( low != high )
                {//交换低索引和高索引元素
                    T tmp=*low;
                    *low=*high;
                    *high=tmp;
                }
                else 
                {//此时，low == high 为真
                    break;
                }
            }

            //此时，low == high 为真
            if( *low &gt; *bd.low )
            {
                low--;
            }
            //将关键值插入大元素和小元素的分界
            T tmp=*low;
            *low=*bd.low;
            *bd.low=tmp;

            if( low != bd.low ) 
            {//若小元素部分元素个数大于1个，继续排序
                low--;
                if( low != bd.low )
                {
                    BoundIter&lt;T&gt; newbd(bd.low,low);
                    boundIterS.push(newbd);
                }
                low++;
            }
            if( low != bd.high)
            {//若大元素部分元素个数大于1个，继续排序
                low++;
                if( low != bd.high )
                {
                    BoundIter&lt;T&gt; newbd(low,bd.high);
                    boundIterS.push(newbd);
                }
            }
        }
    }
    else if( lst.size() == 2) //若数组长度为2，直接比较
    {
        list&lt;T&gt;::iterator iter0=lst.begin();
        list&lt;T&gt;::iterator iter1=(++lst.begin());
        if( *iter0 &gt; *iter1 )
        {
            T tmp=*iter0;
            *iter0=*iter1;
            *iter1=tmp;
        }
    }
    //若数组长度小于2，不用排序
}</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Base64:一个仅基于C++的实现</title>
		<link>https://blog.z6z8.cn/2019/12/13/base64%e4%b8%80%e4%b8%aa%e4%bb%85%e5%9f%ba%e4%ba%8ec%e7%9a%84%e5%ae%9e%e7%8e%b0/</link>
					<comments>https://blog.z6z8.cn/2019/12/13/base64%e4%b8%80%e4%b8%aa%e4%bb%85%e5%9f%ba%e4%ba%8ec%e7%9a%84%e5%ae%9e%e7%8e%b0/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Fri, 13 Dec 2019 06:57:43 +0000</pubDate>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[代码片段]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=651</guid>

					<description><![CDATA[#pragma once //从ATL的base64库整理而来 //整理的目的是提供一个仅基于标准c++的ba [&#8230;]]]></description>
										<content:encoded><![CDATA[<pre><code class="language-cpp">#pragma once

//从ATL的base64库整理而来
//整理的目的是提供一个仅基于标准c++的base64库，提高代码的可移植性
#include &lt;string&gt;

namespace Crypt
{

class Base64
{
public:
    enum Base64_Flag
    {
        ATL_BASE64_FLAG_NONE = 0, // 0000 0000  标准的编码方式（RFC2045）
        ATL_BASE64_FLAG_NOPAD = 1 , // 0000 0001  没有补全（ = ）
        ATL_BASE64_FLAG_NOCRLF = 2 // 0000 0010   没有换行 ( crlf )
    } ;

    //计算编码后的长度
    static int EncodeGetRequiredLength(int nSrcLen, Base64_Flag dwFlags = ATL_BASE64_FLAG_NONE)
    {
        int nRet = static_cast&lt;int&gt;( (nSrcLen&lt;&lt;2) /3);

        if ((dwFlags &amp; ATL_BASE64_FLAG_NOPAD) == 0)// 需要补全 =
            nRet += nSrcLen % 3;

        int nOnLastLine = nRet % 76;
        if (nOnLastLine)
        {
            if (  (nOnLastLine &amp; 0x03)  ) //nOnLastLine % 4
                nRet += 4-(nOnLastLine &amp; 0x03 );
        }

        if ((dwFlags &amp; ATL_BASE64_FLAG_NOCRLF) == 0) //需要换行符
        {
            nRet += ((nRet / 76 + 1) &lt;&lt; 1) ;//(nRet / 76 + 1) * 2, 回车换行个数（+1是为了取最多值），根据rfc2045，编码后一行最多76个字符（不含换行）
        }

        return nRet;
    }

    inline static int DecodeGetRequiredLength(int nSrcLen)
    {
        return ((nSrcLen*3)&gt;&gt;2)+2; //(nSrcLen*3)/4+2
    }

    //pbSrcData  要编码的原始数据
    //nSrcLen  原始数据长度
    //szDest    编码后的输出
    //pnEncodeRealLen       编码后的实际长度
    static bool Encode(const unsigned char *pbSrcData,int nSrcLen,char* szDest,int *pnEncodeRealLen,Base64_Flag dwFlags = ATL_BASE64_FLAG_NONE)
    {
        static const char *s_chBase64EncodingTable="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        if (!pbSrcData || !szDest || !pnEncodeRealLen)
        {
            return false;
        }

        int nWritten = 0 ; //编码后的长度，EncodeGetRequiredLength获得的长度通常大于实际长度

        int nLen1 = (nSrcLen/3) &lt;&lt; 2; // (nSrcLen/3)*4
        int nLen2 = nLen1/76 ;  //RFC2045 base64编码后，每行最多76个字符
        int nLen3 = 19 ;

        for (int i=0; i&lt;=nLen2; i++)
        {
            if (i==nLen2)
                nLen3 = (nLen1%76)/4;

            for (int j=0; j&lt;nLen3; j++)
            {
                unsigned long dwCurr = 0;
                for (int n=0; n&lt;3; n++)
                {
                    dwCurr |= *pbSrcData++;
                    dwCurr &lt;&lt;= 8;
                }
                for (int k=0; k&lt;4; k++)
                {
                    unsigned char b = (unsigned char)(dwCurr&gt;&gt;26);
                    *szDest++ = s_chBase64EncodingTable[b];
                    dwCurr &lt;&lt;= 6;
                }
            }
            nWritten+= nLen3*4;

            if ((dwFlags &amp; ATL_BASE64_FLAG_NOCRLF)==0)
            {
                *szDest++ = '\r';
                *szDest++ = '\n';
                nWritten+= 2;
            }
        }

        if (nWritten &amp;&amp; (dwFlags &amp; ATL_BASE64_FLAG_NOCRLF)==0)
        {
            szDest-= 2;
            nWritten -= 2;
        }

        nLen2 = (nSrcLen%3) ? (nSrcLen%3 + 1) : 0;
        if (nLen2)
        {
            unsigned long dwCurr = 0;
            for (int n=0; n&lt;3; n++)
            {
                if (n&lt;(nSrcLen%3))
                    dwCurr |= *pbSrcData++;
                dwCurr &lt;&lt;= 8;
            }
            for (int k=0; k&lt;nLen2; k++)
            {
                unsigned char b = (unsigned char)(dwCurr&gt;&gt;26);
                *szDest++ = s_chBase64EncodingTable[b];
                dwCurr &lt;&lt;= 6;
            }
            nWritten+= nLen2;
            if ((dwFlags &amp; ATL_BASE64_FLAG_NOPAD)==0)
            {
                nLen3 = nLen2 ? 4-nLen2 : 0;
                for (int j=0; j&lt;nLen3; j++)
                {
                    *szDest++ = '=';
                }
                nWritten+= nLen3;
            }
        }

        *pnEncodeRealLen = nWritten;
        return true;
    }

    //szSrc  要解码的数据
    //nSrcLen  要解码数据的长度
    //pbDest   解码后的输出
    //pnDecodeRealLen  解码后的字节长度
    static bool Decode(const char* szSrc, int nSrcLen, unsigned char *pbDest, int *pnDecodeRealLen)
    {
        // walk the source buffer
        // each four character sequence is converted to 3 bytes
        // CRLFs and =, and any characters not in the encoding table
        // are skiped

        // returns -1 if the character is invalid
        // or should be skipped
        // otherwise, returns the 6-bit code for the character
        // from the encoding table
        static const int base64_decode_table[] =
        {
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
            -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
            29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
            49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
        };

        if (szSrc == 0 || pnDecodeRealLen == 0)
        {
            return false;
        }

        const char* szSrcEnd = szSrc + nSrcLen;
        int nWritten = 0;

        while (szSrc &lt; szSrcEnd &amp;&amp;(*szSrc) != 0)
        {
            unsigned long dwCurr = 0;
            int i;
            int nBits = 0;
            for (i=0; i&lt;4; i++)
            {
                if (szSrc &gt;= szSrcEnd)
                    break;
                int nCh = base64_decode_table[(unsigned char)(*szSrc)]; //强转为unsigned char，防止运行时抛出异常
                szSrc++;
                if (nCh == -1)
                {
                    // skip this char
                    i--;
                    continue;
                }
                dwCurr &lt;&lt;= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            // dwCurr has the 3 bytes to write to the output buffer
            // left to right
            dwCurr &lt;&lt;= 24-nBits;
            for (i=0; i&lt;nBits/8; i++)
            {
                *pbDest = (unsigned char) ((dwCurr &amp; 0x00ff0000) &gt;&gt; 16);
                pbDest++;

                dwCurr &lt;&lt;= 8;
                nWritten++;
            }

        }

        *pnDecodeRealLen = nWritten;

        return true;
    }

    static bool Encode(const std::string &amp; in , std::string &amp; out,Base64_Flag dwFlags = ATL_BASE64_FLAG_NONE)
    {
        int len = EncodeGetRequiredLength(static_cast&lt;int&gt;(in.size()),dwFlags);
        out.assign(len,0);
        bool ret=Encode((const unsigned char*)in.c_str(),static_cast&lt;int&gt;(in.size()),(char*)out.c_str(),&amp;len,dwFlags);
        out.resize(static_cast&lt;size_t&gt;(len));
        return ret;
    }
    static bool Encode( const unsigned char * in ,int in_len,std::string &amp; out ,Base64_Flag dwFlags = ATL_BASE64_FLAG_NONE)
    {
        int len = EncodeGetRequiredLength(in_len,dwFlags);
        out.assign(len,0);
        bool ret=Encode(in ,in_len,(char*)out.c_str(),&amp;len,dwFlags);
        out.resize(static_cast&lt;size_t&gt;(len));
        return ret;
    }
    static bool Decode(const std::string &amp; in, std::string &amp; out )
    {
        out.assign(in.size(),0);
        int len=static_cast&lt;int&gt;(out.size());
        bool ret = Decode(in.c_str(),static_cast&lt;int&gt;(in.size()), (unsigned char*) out.c_str() , &amp;len);
        out.resize(static_cast&lt;size_t&gt;(len));
        return ret;
    }
    static bool Decode(const char * in ,int in_len , std::string &amp; out )
    {
        out.assign( static_cast&lt;size_t&gt;(in_len),0);
        int outlen=static_cast&lt;int&gt;(out.size());
        bool ret = Decode(in ,in_len, (unsigned char*) out.c_str() , &amp;outlen);
        out.resize(static_cast&lt;size_t&gt;(outlen));
        return ret;
    }
};

}
</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2019/12/13/base64%e4%b8%80%e4%b8%aa%e4%bb%85%e5%9f%ba%e4%ba%8ec%e7%9a%84%e5%ae%9e%e7%8e%b0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PNG IHDR：获取PNG图像宽和高</title>
		<link>https://blog.z6z8.cn/2019/12/03/png-ihdr%ef%bc%9a%e8%8e%b7%e5%8f%96png%e5%9b%be%e5%83%8f%e5%ae%bd%e5%92%8c%e9%ab%98/</link>
					<comments>https://blog.z6z8.cn/2019/12/03/png-ihdr%ef%bc%9a%e8%8e%b7%e5%8f%96png%e5%9b%be%e5%83%8f%e5%ae%bd%e5%92%8c%e9%ab%98/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Tue, 03 Dec 2019 10:34:38 +0000</pubDate>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[代码片段]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=595</guid>

					<description><![CDATA[通过读取png图像文件的头信息 #include "stdio.h" namespace { class CF [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>通过读取png图像文件的头信息</p>
<pre><code class="language-cpp">#include "stdio.h"

namespace {
    class CFileStream
    {
    public:
        CFileStream (FILE *fs):m_fs(fs)
        {}

        ~CFileStream()
        {
            fclose(m_fs);
        }

        inline operator FILE*()
        {
            return  m_fs;
        }
        inline operator bool()
        {
            return  m_fs != 0;
        }
    private:
        FILE *m_fs;
    };

    inline unsigned long Convert4char( unsigned char c[4]) //网络端字节序
    {
        unsigned long n = ((unsigned long)c[0]) &lt;&lt; 24;
        n += ((unsigned long)c[1]) &lt;&lt; 16;
        n += ((unsigned long)c[2]) &lt;&lt; 8;
        n += ((unsigned long)c[3]);
        return n;
    }
}

#define png_signature_len 8 //png文件签名
#define png_chunk_len_len  4 //idhr长度信息
#define png_chunk_type_len 4 //ihdr类型码
#define png_ihdr_data_len 13 //ihdr数据

+ (BOOL)imageSizeFromPNGFile:(NSString *)pngFile size:(CGSize *)size;
{
    if (!pngFile || !size) {
        return NO;
    }

    CFileStream fs = fopen([pngFile UTF8String], "rb");
    if (!fs) {
        return NO;
    }

    unsigned char buf[png_signature_len+png_chunk_len_len+png_chunk_type_len+png_ihdr_data_len];
    if (sizeof(buf) != fread(buf, 1, sizeof(buf), fs)) {
        return NO;
    }
    //校验文件签名
    if ( memcmp(buf, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", png_signature_len) != 0 ) {
        return NO;
    }
    //校验ihdr长度
    if (memcmp(buf + png_signature_len, "\x00\x00\x00\x0d", png_chunk_len_len) != 0) {
        return NO;
    }
    //校验ihdr类型码
    if (memcmp(buf + png_signature_len +png_chunk_len_len, "IHDR", png_chunk_len_len) != 0) {
        return NO;
    }

    size-&gt;width = Convert4char(buf + png_signature_len+png_chunk_len_len+png_chunk_type_len );
    size-&gt;height = Convert4char(buf + png_signature_len+png_chunk_len_len+png_chunk_type_len+4);

    return YES;
}
#undef png_signature_len
#undef png_chunk_len_len
#undef png_chunk_type_len
#undef png_ihdr_data_len
</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2019/12/03/png-ihdr%ef%bc%9a%e8%8e%b7%e5%8f%96png%e5%9b%be%e5%83%8f%e5%ae%bd%e5%92%8c%e9%ab%98/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SSL EVP框架：AES加密</title>
		<link>https://blog.z6z8.cn/2019/11/21/ssl-evp%e6%a1%86%e6%9e%b6%ef%bc%9aaes%e5%8a%a0%e5%af%86/</link>
					<comments>https://blog.z6z8.cn/2019/11/21/ssl-evp%e6%a1%86%e6%9e%b6%ef%bc%9aaes%e5%8a%a0%e5%af%86/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Thu, 21 Nov 2019 02:41:47 +0000</pubDate>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[代码片段]]></category>
		<category><![CDATA[AES]]></category>
		<category><![CDATA[GMSSL]]></category>
		<category><![CDATA[ssl]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=581</guid>

					<description><![CDATA[AES加密几个要点 对称加密(Symmetry Crypto) 加密和解密的钥匙是同一把----加密方和解密方 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>AES加密几个要点</h1>
<ul>
<li>
<p>对称加密(Symmetry Crypto)<br />
加密和解密的钥匙是同一把----加密方和解密方拥有相同的密钥（音yue，四声）。</p>
</li>
<li>
<p>密钥(key)<br />
任意数据（不一定非得字符串），长度常见为128比特、192比特、256比特，也有支持512比特的算法库</p>
</li>
<li>
<p>初始化向量(IV)<br />
这不是AES算法标准强制要求的，是一种增加AES破解难度的手段。IV和密钥共同参与加密和解密运算。IV长度固定为128比特。</p>
</li>
<li>
<p>加密块(block)<br />
每次加密的块长度都是128比特；输入和输出长度相同，考虑补全模式的情况下，输出的最大长度 = 输入长度+128比特</p>
</li>
<li>
<p>加密模式<br />
是指当需要加密的源数据长度大于128比特时，加密块和加密块之间的运算模式。<br />
常见的有 CBC密码分组链接模式、ECB电码本模式（不推荐）、CTR计算器模式、CFB密码反馈模式、OFB输出反馈模式。</p>
</li>
<li>
<p>补全模式模式（padding）<br />
因为AES一个加密块为16字节，当源数据的最后一个块不足16字节时，需要手动补全为16字节。</p>
</li>
</ul>
<p>一般使用PKCS7模式，手动补全N个N，N为不足的字节数。</p>
<pre><code>例如，最后一个块为 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x10
需要补6个字节，那么就是6个6
 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x10 0x06 0x06 0x06 0x06 0x06 0x06</code></pre>
<h1>EVP AES 加密</h1>
<pre><code class="language-cpp">
#include "openssl/crypto.h"
#include "openssl/aes.h"
#include "openssl/evp.h"

//引入c++的string，作为buffer使用
#include &lt;string&gt;

//std::string 作为返回值其实可以右值优化的。
std::string encrypt(std::string &amp;data , std::string &amp;key ,std::string &amp;iv)
{
     //这里应该做必要的参数校验，如检查key和iv长度
    //指定算法模式
    EVP_CIPHER *ciper = NULL;
    switch (data.size())
    {
        case 128 / 8: ciper =  EVP_aes_128_cbc();break;
        case 192 / 8: ciper =  EVP_aes_192_cbc();break;
        case 256 / 8: ciper =  EVP_aes_256_cbc();break;
        default:return "需要做一些错误处理";
    }

    //初始化ctx
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    EVP_CIPHER_CTX_init(ctx);

    //指定加密算法及key和iv
    int ret = EVP_EncryptInit_ex(ctx, ciper, NULL, (unsigned char *)key.c_str(),  (unsigned char *)iv.c_str());
    if(ret != 1)
    {//EVP_EncryptInit_ex failed
        EVP_CIPHER_CTX_free(ctx);
        return "需要做一些错误处理";
    }

    // 设置padding EVP框架默认使用的就是PKCS7
    EVP_CIPHER_CTX_set_padding(ctx, 1);

   std::string buffer;
   buffer.append(0,AES_BLOCK_SIZE + data.size());

    int mlen = 0;
    //进行加密操作
    ret = EVP_EncryptUpdate(ctx, (unsigned char *)buffer.c_str(), &amp;mlen, (unsigned char *)data.c_str(),(int)buffer.size());
    if(ret != 1)
    {
        EVP_CIPHER_CTX_free(ctx);
        return "需要做一些错误处理";
    }

    int flen = 0;
    //结束加密操作
    ret = EVP_EncryptFinal_ex(ctx, (unsigned char *)buffer.c_str()+mlen, &amp;flen);
    if(ret != 1)
    {
        EVP_CIPHER_CTX_free(ctx);
        return "需要做一些错误处理";
    }
    EVP_CIPHER_CTX_free(ctx);
    buffer.resize(mlen + flen);
    return buffer;
}
</code></pre>
<h1>EVP AES 解密</h1>
<pre><code class="language-cpp">
std::string decrypt(std::string &amp;data , std::string &amp;key ,std::string &amp;iv)
{
   //这里应该做必要的参数校验，如检查key和iv长度
    //指定算法模式
    EVP_CIPHER *ciper = NULL;
    switch (data.size())
    {
        case 128 / 8: ciper =  EVP_aes_128_cbc();break;
        case 192 / 8: ciper =  EVP_aes_192_cbc();break;
        case 256 / 8: ciper =  EVP_aes_256_cbc();break;
        default:return "需要做一些错误处理";
    }

    //初始化ctx
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    EVP_CIPHER_CTX_init(ctx);

    //指定加密算法及key和iv
    int ret = EVP_DecryptInit_ex(ctx, ciper, NULL,  (unsigned char *)key.c_str(),  (unsigned char *)iv.c_str());
    if(ret != 1)
    {//EVP_EncryptInit_ex failed
        EVP_CIPHER_CTX_free(ctx);
        return  "需要做一些错误处理";
    }

    // 设置padding功能 EVP框架默认使用的就是PKCS7
    EVP_CIPHER_CTX_set_padding(ctx, 1);

    std::string buffer;
    buffer.append(0,data.size());

    int mlen = 0;
    //进行解密操作
    ret = EVP_DecryptUpdate(ctx,  (unsigned char *)buffer.c_str(), &amp;mlen,  (unsigned char *)data.c_str(),(int) data.size());
    if(ret != 1)
    {
        EVP_CIPHER_CTX_free(ctx);
        return  "需要做一些错误处理";
    }

    int flen = 0;
    //结束解密操作
    ret = EVP_DecryptFinal_ex(ctx, (unsigned char *)buffer.c_str()+mlen, &amp;flen);
    if(ret != 1)
    {
        EVP_CIPHER_CTX_free(ctx);
        return  "需要做一些错误处理";
    }

    EVP_CIPHER_CTX_free(ctx);
    buffer.resize(mlen + flen);
    return buffer;
}</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2019/11/21/ssl-evp%e6%a1%86%e6%9e%b6%ef%bc%9aaes%e5%8a%a0%e5%af%86/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>C++ 判断机器的大小端</title>
		<link>https://blog.z6z8.cn/2019/11/12/c-%e5%88%a4%e6%96%ad%e6%9c%ba%e5%99%a8%e7%9a%84%e5%a4%a7%e5%b0%8f%e7%ab%af/</link>
					<comments>https://blog.z6z8.cn/2019/11/12/c-%e5%88%a4%e6%96%ad%e6%9c%ba%e5%99%a8%e7%9a%84%e5%a4%a7%e5%b0%8f%e7%ab%af/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Tue, 12 Nov 2019 02:28:24 +0000</pubDate>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[代码片段]]></category>
		<category><![CDATA[大小端]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=563</guid>

					<description><![CDATA[class __judge_little_endian { public: static inline boo [&#8230;]]]></description>
										<content:encoded><![CDATA[<pre><code class="language-cpp">    class __judge_little_endian
    {
    public:
        static inline bool isle()
        {
            static const int _a = 0xAABBCCDD; 
            return *(unsigned char *)(&amp;_a) == 0xDD;
        }
    };</code></pre>
<p>对于整数  0xAABBCCDD<br />
大端机器 内存中的排布为： AA BB CC DD<br />
小端机器 内存中的排布为： DD CC BB AA</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2019/11/12/c-%e5%88%a4%e6%96%ad%e6%9c%ba%e5%99%a8%e7%9a%84%e5%a4%a7%e5%b0%8f%e7%ab%af/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>大小端转换的C++ 封装 ：hton ， ntol</title>
		<link>https://blog.z6z8.cn/2019/11/12/%e5%a4%a7%e5%b0%8f%e7%ab%af%e8%bd%ac%e6%8d%a2%e7%9a%84c-%e5%b0%81%e8%a3%85-%ef%bc%9ahton-%ef%bc%8c-ntol/</link>
					<comments>https://blog.z6z8.cn/2019/11/12/%e5%a4%a7%e5%b0%8f%e7%ab%af%e8%bd%ac%e6%8d%a2%e7%9a%84c-%e5%b0%81%e8%a3%85-%ef%bc%9ahton-%ef%bc%8c-ntol/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Tue, 12 Nov 2019 02:24:50 +0000</pubDate>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[代码片段]]></category>
		<category><![CDATA[hton]]></category>
		<category><![CDATA[ntoh]]></category>
		<category><![CDATA[大小端]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=560</guid>

					<description><![CDATA[使用C++的模板、自动类型推导技术 #ifndef HtoN_h #define HtoN_h #includ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>使用C++的模板、自动类型推导技术</p>
<pre><code class="language-cpp">#ifndef  HtoN_h
#define HtoN_h

#include &lt;arpa/inet.h&gt;

#if __ANDROID__
    #ifndef htonll
        #define htonll(x) htonq(x)
    #endif

    #ifndef ntohll
        #define ntohll(x) ntohq(x)
    #endif
#endif

namespace zxszl
{
    template &lt;typename T&gt; T zl_hton (T t) { return t;}
    template &lt;&gt; inline uint16_t zl_hton&lt;uint16_t&gt; (uint16_t t) { return htons(t); }
    template &lt;&gt; inline int16_t zl_hton&lt;int16_t&gt; (int16_t t) { return htons(t); }
    template &lt;&gt; inline uint32_t zl_hton&lt;uint32_t&gt; (uint32_t t) { return htonl(t); }
    template &lt;&gt; inline int32_t zl_hton&lt;int32_t&gt; (int32_t t) { return htonl(t); }
    template &lt;&gt; inline uint64_t zl_hton&lt;uint64_t&gt; (uint64_t t) { return htonll(t); }
    template &lt;&gt; inline int64_t zl_hton&lt;int64_t&gt; (int64_t t) { return htonll(t); }

    template &lt;typename T&gt; T zl_ntoh (T t) { return t;}
    template &lt;&gt; inline uint16_t zl_ntoh&lt;uint16_t&gt; (uint16_t t) { return ntohs(t); }
    template &lt;&gt; inline int16_t zl_ntoh&lt;int16_t&gt; (int16_t t) { return ntohs(t); }
    template &lt;&gt; inline uint32_t zl_ntoh&lt;uint32_t&gt; (uint32_t t) { return ntohl(t); }
    template &lt;&gt; inline int32_t zl_ntoh&lt;int32_t&gt; (int32_t t) { return ntohl(t); }
    template &lt;&gt; inline uint64_t zl_ntoh&lt;uint64_t&gt; (uint64_t t) { return ntohll(t); }
    template &lt;&gt; inline int64_t zl_ntoh&lt;int64_t&gt; (int64_t t) { return ntohll(t); }

    class __judge_little_endian
    {
    public:
        static inline bool isle() { static const int _a = 0xAABBCCDD; return *(unsigned char *)(&amp;_a) == 0xDD;}
    };

#define zl_rorder_s(x) \
            ((__uint16_t)((((__uint16_t)(x) &amp; 0xff00) &gt;&gt; 8) | \
            (((__uint16_t)(x) &amp; 0x00ff) &lt;&lt; 8)))

#define zl_rorder_l(x) \
            ((__uint32_t)((((__uint32_t)(x) &amp; 0xff000000) &gt;&gt; 24) | \
            (((__uint32_t)(x) &amp; 0x00ff0000) &gt;&gt;  8) | \
            (((__uint32_t)(x) &amp; 0x0000ff00) &lt;&lt;  8) | \
            (((__uint32_t)(x) &amp; 0x000000ff) &lt;&lt; 24)))

#define zl_rorder_ll(x) \
            ((__uint64_t)((((__uint64_t)(x) &amp; 0xff00000000000000ULL) &gt;&gt; 56) | \
            (((__uint64_t)(x) &amp; 0x00ff000000000000ULL) &gt;&gt; 40) | \
            (((__uint64_t)(x) &amp; 0x0000ff0000000000ULL) &gt;&gt; 24) | \
            (((__uint64_t)(x) &amp; 0x000000ff00000000ULL) &gt;&gt;  8) | \
            (((__uint64_t)(x) &amp; 0x00000000ff000000ULL) &lt;&lt;  8) | \
            (((__uint64_t)(x) &amp; 0x0000000000ff0000ULL) &lt;&lt; 24) | \
            (((__uint64_t)(x) &amp; 0x000000000000ff00ULL) &lt;&lt; 40) | \
            (((__uint64_t)(x) &amp; 0x00000000000000ffULL) &lt;&lt; 56)))

    template &lt;typename T&gt; T zl_htole (T t) { return t;}
    template &lt;&gt; inline uint16_t zl_htole&lt;uint16_t&gt; (uint16_t t) {return __judge_little_endian::isle() ? t : zl_rorder_s(t);}
    template &lt;&gt; inline int16_t zl_htole&lt;int16_t&gt; (int16_t t) {return __judge_little_endian::isle() ? t :  zl_rorder_s(t);}
    template &lt;&gt; inline uint32_t zl_htole&lt;uint32_t&gt; (uint32_t t) {return __judge_little_endian::isle() ? t :  zl_rorder_l(t);}
    template &lt;&gt; inline int32_t zl_htole&lt;int32_t&gt; (int32_t t) {return __judge_little_endian::isle() ? t :  zl_rorder_l(t);}
    template &lt;&gt; inline uint64_t zl_htole&lt;uint64_t&gt; (uint64_t t) { return __judge_little_endian::isle() ? t :  zl_rorder_ll(t); }
    template &lt;&gt; inline int64_t zl_htole&lt;int64_t&gt; (int64_t t) { return __judge_little_endian::isle() ? t :  zl_rorder_ll(t); }

    template &lt;typename T&gt; T zl_letoh (T t) { return t;}
    template &lt;&gt; inline uint16_t zl_letoh&lt;uint16_t&gt; (uint16_t t) {return __judge_little_endian::isle() ? t : zl_rorder_s(t);}
    template &lt;&gt; inline int16_t zl_letoh&lt;int16_t&gt; (int16_t t) {return __judge_little_endian::isle() ? t :  zl_rorder_s(t);}
    template &lt;&gt; inline uint32_t zl_letoh&lt;uint32_t&gt; (uint32_t t) {return __judge_little_endian::isle() ? t :  zl_rorder_l(t);}
    template &lt;&gt; inline int32_t zl_letoh&lt;int32_t&gt; (int32_t t) {return __judge_little_endian::isle() ? t :  zl_rorder_l(t);}
    template &lt;&gt; inline uint64_t zl_letoh&lt;uint64_t&gt; (uint64_t t) { return __judge_little_endian::isle() ? t :  zl_rorder_ll(t); }
    template &lt;&gt; inline int64_t zl_letoh&lt;int64_t&gt; (int64_t t) { return __judge_little_endian::isle() ? t :  zl_rorder_ll(t); }

#undef zl_rorder_s
#undef zl_rorder_l
#undef zl_rorder_ll
}

#endif /* HtoN_h */</code></pre>
<p>使用示例</p>
<pre><code class="language-cpp">using namespace zxszl;

short m = 10;
short n = zl_hton(m);
m = zl_ntoh(n);

int x = 100;
int y = zl_hton(x);
x = zl_ntoh(y);</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2019/11/12/%e5%a4%a7%e5%b0%8f%e7%ab%af%e8%bd%ac%e6%8d%a2%e7%9a%84c-%e5%b0%81%e8%a3%85-%ef%bc%9ahton-%ef%bc%8c-ntol/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
