Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

Buffer.cpp

Go to the documentation of this file.
00001 //
00002 // Buffer.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 // CBuffer holds some memory, and takes care of allocating and freeing it itself
00023 // http://wiki.shareaza.com/static/Developers.Code.CBuffer
00024 
00025 // Copy in the contents of these files here before compiling
00026 #include "StdAfx.h"
00027 #include "Shareaza.h"
00028 #include "Settings.h"
00029 #include "Buffer.h"
00030 #include "Packet.h"
00031 #include "ZLib.h"
00032 #include "Statistics.h"
00033 #include <zlib.h>
00034 
00035 // If we are compiling in debug mode, replace the text "THIS_FILE" in the code with the name of this file
00036 #ifdef _DEBUG
00037 #undef THIS_FILE
00038 static char THIS_FILE[]=__FILE__;
00039 #define new DEBUG_NEW
00040 #endif
00041 
00042 // Define memory sizes to use in these methods
00043 #define TEMP_BUFFER 4096       // Use a 4 KB buffer as a temporary store between a socket and the buffer object
00044 #define BLOCK_SIZE  1024       // Change the allocated size of the buffer in 1 KB sized blocks
00045 #define BLOCK_MASK  0xFFFFFC00 // Aids in rounding to the next biggest KB of size
00046 
00048 // CBuffer construction
00049 
00050 // Takes access to a DWORD that is not used (do)
00051 // Makes a new blank CBuffer object with no memory block allocated yet
00052 CBuffer::CBuffer(DWORD* pLimit)
00053 {
00054         // Null pointers and zero counts
00055         m_pNext   = NULL; // This object isn't in a list yet
00056         m_pBuffer = NULL; // No memory block has been allocated for this object yet
00057         m_nBuffer = 0;    // The size of the memory block is 0
00058         m_nLength = 0;    // No bytes have been written here yet
00059 }
00060 
00061 // Delete this CBuffer object
00062 // Frees the memory taken up by the buffer
00063 CBuffer::~CBuffer()
00064 {
00065         // If the member variable points to some memory, free it
00066         if ( m_pBuffer ) free( m_pBuffer );
00067 }
00068 
00070 // CBuffer add
00071 
00072 // Takes a pointer to memory, and how many bytes are stored there
00073 // Adds that memory to this buffer
00074 void CBuffer::Add(const void * pData, DWORD nLength)
00075 {
00076         // If the buffer isn't big enough to hold the new memory
00077         if ( m_nLength + nLength > m_nBuffer )
00078         {
00079                 // Set the buffer size to the size needed
00080                 m_nBuffer = m_nLength + nLength;
00081 
00082                 // Make the size larger to the nearest multiple of 1024 bytes, or 1 KB
00083                 m_nBuffer = ( m_nBuffer + BLOCK_SIZE - 1 ) & BLOCK_MASK; // 1-1024 becomes 1024, 1025 becomes 2048
00084 
00085                 // Allocate more space at the end of the memory block
00086                 m_pBuffer = (BYTE*)realloc( m_pBuffer, m_nBuffer ); // This may move the block, returning a different pointer
00087 
00088         } // If the buffer is larger than 512 KB, but what it needs to hold is less than 256 KB
00089         else if ( m_nBuffer > 0x80000 && m_nLength + nLength < 0x40000 )
00090         {
00091                 // Reallocate it to make it half as big
00092                 m_nBuffer = 0x40000;
00093                 m_pBuffer = (BYTE*)realloc( m_pBuffer, m_nBuffer ); // This may move the block, returning a different pointer
00094         }
00095 
00096         // Copy the given memory into the end of the memory block
00097         CopyMemory( m_pBuffer + m_nLength, pData, nLength );
00098         m_nLength += nLength; // Add the length of the new memory to the total length in the buffer
00099 }
00100 
00102 // CBuffer insert
00103 
00104 // Takes offset, a position in the memory block to insert some new memory at
00105 // Inserts the memory there, shifting anything after it further to the right
00106 void CBuffer::Insert(DWORD nOffset, const void * pData, DWORD nLength)
00107 {
00108         // If the buffer isn't big enough to hold the new memory
00109         if ( m_nLength + nLength > m_nBuffer )
00110         {
00111                 // Set the buffer size to the size needed
00112                 m_nBuffer = m_nLength + nLength;
00113 
00114                 // Make the size larger to the nearest multiple of 1024 bytes, or 1 KB
00115                 m_nBuffer = ( m_nBuffer + BLOCK_SIZE - 1 ) & BLOCK_MASK; // 1-1024 becomes 1024, 1025 becomes 2048
00116 
00117                 // Allocate more space at the end of the memory block
00118                 m_pBuffer = (BYTE*)realloc( m_pBuffer, m_nBuffer ); // This may move the block, returning a different pointer
00119 
00120         } // If the buffer is larger than 512 KB, but what it needs to hold is less than 256 KB
00121         else if ( m_nBuffer > 0x80000 && m_nLength + nLength < 0x40000 )
00122         {
00123                 // Reallocate it to make it half as big
00124                 m_nBuffer = 0x40000;
00125                 m_pBuffer = (BYTE*)realloc( m_pBuffer, m_nBuffer ); // This may move the block, returning a different pointer
00126         }
00127 
00128         // Cut the memory block sitting in the buffer in two, slicing it at offset and shifting that part forward nLength
00129         MoveMemory(
00130                 m_pBuffer + nOffset + nLength, // Destination is the offset plus the length of the memory block to insert
00131                 m_pBuffer + nOffset,           // Source is at the offset
00132                 m_nLength - nOffset );         // Length is the size of the memory block beyond the offset
00133 
00134         // Now that there is nLength of free space in the buffer at nOffset, copy the given memory to fill it
00135         CopyMemory(
00136                 m_pBuffer + nOffset, // Destination is at the offset in the buffer
00137                 pData,               // Source is the given pointer to the memory to insert
00138                 nLength );           // Length is the length of that memory
00139 
00140         // Add the length of the new memory to the total length in the buffer
00141         m_nLength += nLength;
00142 }
00143 
00145 // CBuffer remove
00146 
00147 // Takes a number of bytes
00148 // Removes this number from the start of the buffer, shifting the memory after it to the start
00149 void CBuffer::Remove(DWORD nLength)
00150 {
00151         // Check the given length
00152         if ( nLength > m_nLength // We're being asked to remove more bytes than are stores in the buffer
00153                 || nLength == 0 )    // We're being asked to remove nothing
00154                 return;              // Leave now
00155 
00156         // Subtract the removed bytes from the count of how many are stored here
00157         m_nLength -= nLength;
00158 
00159         // Shift the bytes at nLength in the buffer back up to the start of the buffer
00160         MoveMemory(
00161                 m_pBuffer,           // Destination is the start of the buffer
00162                 m_pBuffer + nLength, // Source is nLength into the buffer
00163                 m_nLength );         // Length to copy is the new adjusted length
00164 }
00165 
00166 // Clears the memory from the buffer
00167 void CBuffer::Clear()
00168 {
00169         // Record that there are no bytes stored in the buffer
00170         m_nLength = 0; // Note that the buffer still has the same allocated size of m_nLength
00171 }
00172 
00174 // CBuffer add utilities
00175 
00176 // Takes ASCII text
00177 // Prints it into the buffer, does not write a null terminator
00178 void CBuffer::Print(LPCSTR pszText)
00179 {
00180         // If the text is blank, don't do anything
00181         if ( pszText == NULL ) return;
00182 
00183         // Add the characters of the text to the buffer, each ASCII character takes up 1 byte
00184         Add( (void*)pszText, strlen( pszText ) ); // Length is 5 for "hello", this adds the characters without the null terminator
00185 }
00186 
00187 // Takes Unicode text, along with the code page it uses
00188 // Converts it to ASCII and prints each ASCII character into the buffer, not printing a null terminator
00189 void CBuffer::Print(LPCWSTR pszText, UINT nCodePage)
00190 {
00191         // If the text is blank, don't do anything
00192         if ( pszText == NULL ) return;
00193 
00194         // Find the number of wide characters in the Unicode text
00195         int nLength = wcslen(pszText); // Length of "hello" is 5, does not include null terminator
00196 
00197         // Find out the required buffer size, in bytes, for the translated string
00198         int nBytes = WideCharToMultiByte( // Bytes required for "hello" is 5, does not include null terminator
00199                 nCodePage, // Specify the code page used to perform the conversion
00200                 0,         // No special flags to handle unmapped characters
00201                 pszText,   // Wide character string to convert
00202                 nLength,   // The number of wide characters in that string
00203                 NULL,      // No output buffer given, we just want to know how long it needs to be
00204                 0,
00205                 NULL,      // No replacement character given
00206                 NULL );    // We don't want to know if a character didn't make it through the translation
00207 
00208         // Make sure the buffer is big enough for this, making it larger if necessary
00209         EnsureBuffer( (DWORD)nBytes );
00210 
00211         // Convert the Unicode string into ASCII characters in the buffer
00212         WideCharToMultiByte( // Writes 5 bytes "hello", does not write a null terminator after that
00213                 nCodePage, // Specify the code page used to perform the conversion
00214                 0,         // No special flags to handle unmapped characters
00215                 pszText,   // Wide character string to convert
00216                 nLength,   // The number of wide characters in that string
00217                 (LPSTR)( m_pBuffer + m_nLength ), // Put the output ASCII characters at the end of the buffer
00218                 nBytes,                           // There is at least this much space there
00219                 NULL,      // No replacement character given
00220                 NULL );    // We don't want to know if a character didn't make it through the translation
00221 
00222         // Add the newly written bytes to the buffer's record of how many bytes it is holding
00223         m_nLength += nBytes;
00224 }
00225 
00226 // Takes another CBuffer object, and a number of bytes there to copy, or the default -1 to copy the whole thing
00227 // Moves the memory from pBuffer into this one
00228 // Returns the number of bytes moved
00229 DWORD CBuffer::AddBuffer(CBuffer* pBuffer, DWORD nLength)
00230 {
00231         // If the call specified a length, use it, otherwise use the length of pBuffer
00232         nLength = nLength < 0xFFFFFFFF ? ( min( pBuffer->m_nLength, nLength ) ) : pBuffer->m_nLength;
00233 
00234         // Move nLength bytes from the start of pBuffer into this one
00235         Add( pBuffer->m_pBuffer, nLength ); // Copy the memory across
00236         pBuffer->Remove( nLength );         // Remove the memory from the source buffer
00237 
00238         // Report how many bytes we moved
00239         return nLength;
00240 }
00241 
00242 // Takes a pointer to some memory, and the number of bytes we can read there
00243 // Adds them to this buffer, except in reverse order
00244 void CBuffer::AddReversed(const void *pData, DWORD nLength)
00245 {
00246         // Make sure this buffer has enough memory allocated to hold another nLength bytes
00247         EnsureBuffer( nLength );
00248 
00249         // Copy nLength bytes from pData to the end of the buffer, except in reverse order
00250         ReverseBuffer( pData, m_pBuffer + m_nLength, nLength );
00251 
00252         // Record the new length
00253         m_nLength += nLength;
00254 }
00255 
00256 // Takes ASCII text
00257 // Inserts it at the start of this buffer, shifting what is already here forward, does not write a null terminator
00258 void CBuffer::Prefix(LPCSTR pszText)
00259 {
00260         // If the text is blank, do nothing
00261         if ( NULL == pszText ) return;
00262 
00263         // Insert the bytes of the text at
00264         Insert(                  // Insert memory in the middle of the filled block of a buffer, splitting the block to the right
00265                 0,                   // Insert the bytes at position 0, the start
00266                 (void*)pszText,      // Insert the bytes of the ASCII text
00267                 strlen( pszText ) ); // Insert each character byte, like 5 for "hello", does not insert a null terminator
00268 }
00269 
00270 // Takes a number of new bytes we're about to add to this buffer
00271 // Makes sure the buffer will be big enough to hold them, allocating more memory if necessary
00272 void CBuffer::EnsureBuffer(DWORD nLength)
00273 {
00274         // If the size of the buffer minus the size filled is bigger than or big enough for the given length, do nothing
00275         if ( m_nBuffer - m_nLength >= nLength ) return; // There is enough room to write nLength bytes without allocating anything
00276 
00277         // Make m_nBuffer the size of what's written plus what's requested
00278         m_nBuffer = m_nLength + nLength;
00279 
00280         // Round that up to the nearest multiple of 1024, or 1 KB
00281         m_nBuffer = ( m_nBuffer + BLOCK_SIZE - 1 ) & BLOCK_MASK;
00282 
00283         // Reallocate the memory block to this size
00284         m_pBuffer = (BYTE*)realloc( m_pBuffer, m_nBuffer ); // May return a different pointer
00285 }
00286 
00288 // CBuffer read string helper
00289 
00290 // Takes a maximum number of bytes to examine at the start of the buffer, and a code page which is ASCII by default
00291 // Reads the given number of bytes as ASCII characters, copying them into a string
00292 // Returns the text in a string, which will contain Unicode or ASCII characters depending on the compile
00293 CString CBuffer::ReadString(DWORD nBytes, UINT nCodePage)
00294 {
00295         // Make a new blank string to hold the text we find
00296         CString str;
00297 
00298         // Set nSource to whichever is smaller, the number of bytes in the buffer, or the number we can look at there
00299         int nSource = (int)min( nBytes, m_nLength );
00300 
00301         // Find out how many wide characters a buffer must be able to hold to convert this text to Unicode, null terminator not included
00302         int nLength = MultiByteToWideChar( // If the bytes "hello" are in the buffer, and nSource is 5, nLength will be 5 also
00303                 nCodePage,                     // Code page to use, CP_ACP ANSI code page for ASCII text, the default
00304                 0,                             // No special options about difficult to translate characters
00305                 (LPCSTR)m_pBuffer,             // Use the start of this buffer as the source, where the ASCII text is
00306                 nSource,                       // Convert this number of bytes there
00307                 NULL,                          // No output buffer, we want to find out how long one must be
00308                 0 );
00309 
00310         // Convert the ASCII characters at the start of this buffer to Unicode
00311         MultiByteToWideChar(          // Convert ASCII text to Unicode
00312                 nCodePage,                // Code page to use, CP_ACP ANSI code page for ASCII text, the default
00313                 0,                        // No special options about difficult to translate characters
00314                 (LPCSTR)m_pBuffer,        // Use the start of this buffer as the source, where the ASCII text is
00315                 nSource,                  // Convert this number of bytes there
00316                 str.GetBuffer( nLength ), // Get direct access to the memory buffer for the CString object, telling it to be able to hold nLength characters
00317                 nLength );                // Size of the buffer in wide characters
00318 
00319         // Release our direct manipulation of the CString's buffer
00320         str.ReleaseBuffer( nLength ); // Tell it how many wide characters we wrote there, null terminator not included
00321 
00322         // Return the string
00323         return str;
00324 }
00325 
00327 // CBuffer read line helper
00328 
00329 // Takes access to a string, default peek false to move a line from the buffer to the string, and default CP_ACP to read ASCII text
00330 // Looks for bytes like "line\r\n" in the buffer, and moves them from the buffer to the string, throwing away the "\r\n" part
00331 // Returns true if a line was found and moved from the buffer to the string, false if there isn't a '\n' in the buffer right now
00332 BOOL CBuffer::ReadLine(CString& strLine, BOOL bPeek, UINT nCodePage)
00333 {
00334         // Empty the string, making it blank
00335         strLine.Empty();
00336 
00337         // If this buffer is empty, tell the caller we didn't find a complete line
00338         if ( ! m_nLength ) return FALSE;
00339 
00340         // Scan down each byte in the buffer
00341         DWORD nLength;
00342         for ( nLength = 0 ; nLength < m_nLength ; nLength++ )
00343         {
00344                 // If the byte at this length is the newline character '\n', exit the loop
00345                 if ( m_pBuffer[ nLength ] == '\n' ) break;
00346         }
00347 
00348         // If the loop didn't find a '\n' and instead stopped because nLength grew to equal m_nLength
00349         if ( nLength >= m_nLength ) return FALSE; // There isn't an '\n' in the buffer, tell the caller we didn't find a complete line
00350 
00351         // Convert the nLength ASCII characters in the buffer into wide characters in strLine
00352         int nWide = MultiByteToWideChar( nCodePage, 0, (LPCSTR)m_pBuffer, nLength, NULL, 0 );
00353     MultiByteToWideChar( nCodePage, 0, (LPCSTR)m_pBuffer, nLength, strLine.GetBuffer( nWide ), nWide );
00354         strLine.ReleaseBuffer( nWide );
00355 
00356         // Find the last carriage return '\r' character in the string
00357         int nCR = strLine.ReverseFind( '\r' );   // Find the distance to the last \r, "hello\r" would be 5
00358         if ( nCR >= 0 ) strLine.Truncate( nCR ); // Cut the string to that length, like "hello"
00359 
00360         // Now that the line has been copied into the string, remove it and the '\n' from the buffer
00361         if ( ! bPeek ) Remove( nLength + 1 ); // Unless we're peeking, then leave it in the buffer
00362 
00363         // Report that we found a line and moved it from the buffer to the string
00364         return TRUE;
00365 }
00366 
00368 // CBuffer starts with helper
00369 
00370 // Takes a pointer to ASCII text, and the option to remove these characters from the start of the buffer if they are found there
00371 // Looks at the bytes at the start of the buffer, and determines if they are the same as the given ASCII text
00372 // Returns true if the text matches, false if it doesn't
00373 BOOL CBuffer::StartsWith(LPCSTR pszString, BOOL bRemove)
00374 {
00375         // If the buffer isn't long enough to contain the given string, report the buffer doesn't start with it
00376         if ( m_nLength < (int)strlen( pszString ) ) return FALSE;
00377 
00378         // If the first characters in the buffer don't match those in the ASCII string, return false
00379         if ( strncmp(               // Returns 0 if all the characters are the same
00380                 (LPCSTR)m_pBuffer,      // Look at the start of the buffer as ASCII text
00381                 (LPCSTR)pszString,      // The given text
00382                 strlen( pszString ) ) ) // Don't look too far into the buffer, we know it's long enough to hold the string
00383                 return FALSE;           // If one string would sort above another, the result is positive or negative
00384 
00385         // If we got the option to remove the string if it matched, do it
00386         if ( bRemove ) Remove( strlen( pszString ) );
00387 
00388         // Report that the buffer does start with the given ASCII text
00389         return TRUE;
00390 }
00391 
00393 // CBuffer socket receive
00394 
00395 // Takes a handle to a socket
00396 // Reads in data from the socket, moving it into the buffer
00397 // Returns the number of bytes we got
00398 DWORD CBuffer::Receive(SOCKET hSocket)
00399 {
00400         // Make a local 4 KB buffer
00401         BYTE pData[TEMP_BUFFER];
00402 
00403         // Record how many bytes we get from the socket in this call to this method
00404         DWORD nTotal = 0;
00405 
00406         // Loop forever
00407         while ( TRUE )
00408         {
00409                 // Move up to 4 KB of data from the socket to our pData buffer
00410                 int nLength = recv( // Read data in from the socket, nLength is how many bytes we got
00411                         hSocket,        // The socket that is connected to a remote computer
00412                         (char *)pData,  // Put the data in our little local 4 KB buffer
00413                         TEMP_BUFFER,    // Tell recv that it has 4 KB of space there
00414                         0 );            // No advanced options
00415 
00416                 // If we got 0 bytes, or SOCKET_ERROR -1, exit the loop
00417                 if ( nLength <= 0 ) break;
00418 
00419                 // Copy the data from the 4 KB buffer into this CBuffer object
00420                 Add( pData, nLength );
00421 
00422                 // Record this method has read nLength more bytes
00423                 nTotal += nLength;
00424         }
00425 
00426         // Add the amount we read to the incoming bandwidth statistic, and return it
00427         Statistics.Current.Bandwidth.Incoming += nTotal;
00428         return nTotal;
00429 }
00430 
00432 // CBuffer socket send
00433 
00434 // Takes a handle to a socket
00435 // Sends all the data in this buffer to the remote computer at the other end of it
00436 // Returns how many bytes were sent
00437 DWORD CBuffer::Send(SOCKET hSocket)
00438 {
00439         // Record the total bytes we send in this call to this method
00440         DWORD nTotal = 0;
00441 
00442         // Loop until this buffer is empty
00443         while ( m_nLength )
00444         {
00445                 // Copy the contents of this buffer into the socket
00446                 int nLength = send(    // Send data out through the socket, nLength will be how much was sent
00447                         hSocket,           // The socket that is connected to the remote computer
00448                         (char *)m_pBuffer, // Send data from the start of this buffer
00449                         m_nLength,         // Try to send all the data in the buffer
00450                         0 );               // No advanced options
00451 
00452                 // If no data was sent, or send returned SOCKET_ERROR -1, exit the loop
00453                 if ( nLength <= 0 ) break;
00454 
00455                 // Remove the bytes that we copied into the socket from this buffer
00456                 Remove( nLength );
00457 
00458                 // Record that we sent these bytes
00459                 nTotal += nLength;
00460         }
00461 
00462         // Add the amount we sent to the outgoing bandwidth statistic, and return it
00463         Statistics.Current.Bandwidth.Outgoing += nTotal;
00464         return nTotal;
00465 }
00466 
00468 // CBuffer deflate and inflate compression
00469 
00470 // Takes an option to avoid compressing a small buffer and to make sure compressing didn't actually make it bigger
00471 // Compresses the data in this buffer in place
00472 // Returns true if the data is compressed, false if there was an error
00473 BOOL CBuffer::Deflate(BOOL bIfSmaller)
00474 {
00475         // If the caller requested we check for small buffers, and this one contains less than 45 bytes, return false
00476         if ( bIfSmaller && m_nLength < 45 ) return FALSE; // This buffer is too small for compression to work
00477 
00478         // Compress this buffer
00479         DWORD nCompress = 0; // Compress will write the size of the buffer it allocates and returns in this variable
00480         BYTE* pCompress = CZLib::Compress( m_pBuffer, m_nLength, &nCompress ); // Returns a buffer we must free
00481         if ( ! pCompress ) return FALSE; // Compress had an error
00482 
00483         // If compressing the data actually made it bigger, and we were told to watch for this happening
00484         if ( bIfSmaller && nCompress >= m_nLength )
00485         {
00486                 // Delete the buffer that Compress allocated, and report error
00487                 delete [] pCompress;
00488                 return FALSE;
00489         }
00490 
00491         // Move the compressed data from the buffer Compress returned to this one
00492         m_nLength = 0;               // Record that there is no memory stored in this buffer
00493         Add( pCompress, nCompress ); // Copy the compressed data into this buffer
00494         delete [] pCompress;         // Free the memory that Compress allocated
00495         return TRUE;                 // Report success
00496 }
00497 
00498 // Takes the size we think the data will be when decompressed, or 0 if we don't know
00499 // Decompresses the data in this buffer in place
00500 // Returns true if the data is decompressed, false if there was an error
00501 BOOL CBuffer::Inflate(DWORD nSuggest)
00502 {
00503         // The bytes in this buffer are compressed, decompress them
00504         DWORD nCompress = 0; // Decompress will write the size of the buffer it allocates and returns in this variable
00505         BYTE* pCompress = CZLib::Decompress( m_pBuffer, m_nLength, &nCompress, nSuggest ); // Returns a buffer we must free
00506         if ( pCompress == NULL ) return FALSE; // Decompress had an error
00507 
00508         // Move the decompressed data from the buffer Decompress returned to this one
00509         m_nLength = 0;               // Record that there is no memory stored in this buffer
00510         Add( pCompress, nCompress ); // Copy the decompressed data into this buffer
00511         delete [] pCompress;         // Free the memory that Decompress allocated
00512         return TRUE;                 // Report success
00513 }
00514 
00515 // If the contents of this buffer are between headers and compressed with gzip, this method can remove all that
00516 // Returns false on error
00517 BOOL CBuffer::Ungzip()
00518 {
00519         // Make sure there are at least 10 bytes in this buffer
00520         if ( m_nLength < 10 ) return FALSE;
00521 
00522         // Make sure the first 3 bytes are not 1f8b08
00523         if ( m_pBuffer[0] != 0x1F || m_pBuffer[1] != 0x8B || m_pBuffer[2] != 8 ) return FALSE;
00524 
00525         // At a distance of 3 bytes into the buffer, read the byte there and call it nFlags
00526         BYTE nFlags = m_pBuffer[3];
00527 
00528         // Remove the first 10 bytes of the buffer
00529         Remove( 10 );
00530 
00531         // If there is a 1 in position 0000 0100 in the flags byte
00532         if ( nFlags & 0x04 )
00533         {
00534                 // Make sure the buffer has 2 or more bytes
00535                 if ( m_nLength < 2 ) return FALSE;
00536 
00537                 // Look at the first 2 bytes in the buffer as a word, this says how long the data it beyond it
00538                 WORD nLen = *(WORD*)m_pBuffer;
00539 
00540                 // If the buffer has less data than it should, return false
00541                 if ( (int)m_nLength < (int)nLen + 2 ) return FALSE;
00542 
00543                 // Remove the length word and the length it describes from the front of the buffer
00544                 Remove( 2 + nLen );
00545         }
00546 
00547         // If there is a 1 in position 0000 1000 in the flags byte
00548         if ( nFlags & 0x08 )
00549         {
00550                 // Loop until after we remove a 0 byte from the buffer
00551                 for ( ;; )
00552                 {
00553                         // If the buffer is empty, return false
00554                         if ( m_nLength == 0 ) return FALSE;
00555 
00556                         // Move the first byte of the buffer into an int
00557                         int nChar = m_pBuffer[0]; // Copy one byte from the start of the buffer into an int named nChar
00558                         Remove( 1 );              // Remove that first byte from the buffer
00559 
00560                         // If we just removed a 0 byte, exit the loop
00561                         if ( nChar == 0 ) break;
00562                 }
00563         }
00564 
00565         // If there is a 1 in position 0001 0000 in the flags byte
00566         if ( nFlags & 0x10 )
00567         {
00568                 // Loop until after we remove a 0 byte from the buffer
00569                 for ( ;; )
00570                 {
00571                         // If the buffer is empty, return false
00572                         if ( m_nLength == 0 ) return FALSE;
00573 
00574                         // Move the first byte of the buffer into an int
00575                         int nChar = m_pBuffer[0]; // Copy one byte from the start of the buffer into an int named nChar
00576                         Remove( 1 );              // Remove that first byte from the buffer
00577 
00578                         // If we just removed a 0 byte, exit the loop
00579                         if ( nChar == 0 ) break;
00580                 }
00581         }
00582 
00583         // If there is a 1 in position 0000 0010 in the flags byte
00584         if ( nFlags & 0x02 )
00585         {
00586                 // Make sure the buffer has at least 2 bytes, and then remove them
00587                 if ( m_nLength < 2 ) return FALSE;
00588                 Remove( 2 );
00589         }
00590 
00591         // After removing all that header information from the front, remove the last 8 bytes from the end
00592         if ( m_nLength <= 8 ) return FALSE; // Make sure the buffer has more than 8 bytes
00593         m_nLength -= 8;                     // Remove the last 8 bytes in the buffer
00594 
00595         // Setup a z_stream structure to perform a raw inflate
00596         z_stream pStream;
00597         ZeroMemory( &pStream, sizeof(pStream) );
00598         if ( Z_OK != inflateInit2( // Initialize a stream inflation with more options than just inflateInit
00599                 &pStream,              // Stream structure to initialize
00600                 -MAX_WBITS ) ) {       // Window bits value of -15 to perform a raw inflate
00601 
00602                 // The Zlib function inflateInit2 returned something other than Z_OK, report error
00603                 return FALSE;
00604         }
00605 
00606         // Make a new buffer for the output
00607         CBuffer pOutput;
00608         pOutput.EnsureBuffer( m_nLength * 6 ); // Guess that inflating the data won't make it more than 6 times as big
00609 
00610         // Tell the z_stream structure where to work
00611         pStream.next_in   = m_pBuffer;         // Decompress the memory here
00612         pStream.avail_in  = m_nLength;         // There is this much of it
00613         pStream.next_out  = pOutput.m_pBuffer; // Write decompressed data here
00614         pStream.avail_out = pOutput.m_nBuffer; // Tell ZLib it has this much space, it make this smaller to show how much space is left
00615 
00616         // Call ZLib inflate to decompress all the data, and see if it returns Z_STREAM_END
00617         BOOL bSuccess = ( Z_STREAM_END == inflate( &pStream, Z_FINISH ) );
00618 
00619         // The inflate call returned Z_STREAM_END
00620         if ( bSuccess )
00621         {
00622                 // Move the decompressed data from the output buffer into this one
00623                 Clear();                   // Record there are no bytes stored here, doesn't change the allocated block size
00624                 Add(pOutput.m_pBuffer,     // Add the memory at the start of the output buffer
00625                         pOutput.m_nBuffer      // The amount of space the buffer had when we gave it to Zlib
00626                         - pStream.avail_out ); // Minus the amount it said it left, this is the number of bytes it wrote
00627 
00628                 // Close ZLib and report success
00629                 inflateEnd( &pStream );
00630                 return TRUE;
00631 
00632         } // The inflate call returned something else
00633         else
00634         {
00635                 // Close ZLib and report error
00636                 inflateEnd( &pStream );
00637                 return FALSE;
00638         }
00639 }
00640 
00642 // CBuffer reverse buffer
00643 
00644 // This method is static, which means you can call it like CBuffer::ReverseBuffer() without having a CBuffer object at all
00645 // Takes pointers to input memory and an output buffer, and a length, which is both the memory in input and the space in output
00646 // Copies the bytes from input to output, but in reverse order
00647 void CBuffer::ReverseBuffer(const void* pInput, void* pOutput, DWORD nLength)
00648 {
00649         // Point pInputWords at the end of the input memory block
00650         const DWORD* pInputWords = (const DWORD*)( (const BYTE*)pInput + nLength ); // This is a DWORD pointer, so it will move in steps of 4
00651 
00652         // Point pOutputWords at the start of the output buffer
00653         DWORD* pOutputWords      = (DWORD*)( pOutput );
00654 
00655         // Make a new local DWORD called nTemp, and request that Visual Studio place it in a machine register
00656         register DWORD nTemp; // The register keyword asks that nTemp be a machine register, making it really fast
00657 
00658         // Loop while nLength is bigger than 4, grabbing bytes 4 at a time and reversing them
00659         while ( nLength > 4 )
00660         {
00661                 // Move pInputWords back 4 bytes, then copy the 4 bytes there into nTemp, the fast machine register DWORD
00662                 nTemp = *--pInputWords;
00663 
00664                 // Have SWAP_LONG reverse the order of the 4 bytes, copy them under pOutputWords, and then move that pointer 4 bytes forward
00665                 *pOutputWords++ = SWAP_LONG( nTemp ); // If nTemp is "ABCD", SWAP_LONG( nTemp ) will be "DCBA", bit order is not changed
00666 
00667                 // We've just reverse 4 bytes, subtract the length to reflect this
00668                 nLength -= 4;
00669         }
00670 
00671         // If there are still some input bytes to add reversed
00672         if ( nLength )
00673         {
00674                 // Point pInputBytes and pOutputBytes at the same places
00675                 const BYTE* pInputBytes = (const BYTE*)pInputWords; // This is a byte pointer, so it will move in steps of 1
00676                 BYTE* pOutputBytes              = (BYTE*)pOutputWords;
00677 
00678                 // Loop until there are no more bytes to copy over
00679                 while ( nLength-- )
00680                 {
00681                         // Move pInputBytes back to grab a byte, copy it under pOutputBytes, then move pOutputBytes forward
00682                         *pOutputBytes++ = *--pInputBytes;
00683                 }
00684         }
00685 }
00686 
00688 // CBuffer DIME handling
00689 
00690 // DIME is a specification for sending and receiving SOAP messages along with additional attachments, like binary files or XML fragments
00691 // Takes information to create a DIME message
00692 // Composes the DIME message and writes it into this buffer
00693 void CBuffer::WriteDIME(
00694         DWORD nFlags,   // 0, 1, or 2
00695         LPCSTR pszID,   // Blank, or a GUID in hexadecimal encoding
00696         LPCSTR pszType, // "text/xml" or a URI to an XML specification
00697         LPCVOID pBody,  // The XML fragment we're wrapping
00698         DWORD nBody)    // How long it is
00699 {
00700         // Format lengths into the bytes of the DIME header
00701         EnsureBuffer( 12 );                                               // Make sure this buffer has at least 12 bytes of space
00702         BYTE* pOut = m_pBuffer + m_nLength;                               // Point pOut at the end of the memory block in this buffer
00703         *pOut++ = 0x08 | ( nFlags & 1 ? 4 : 0 ) | ( nFlags & 2 ? 2 : 0 ); // *pOut++ = 0x08 sets the byte at pOut and then moves the pointer forward
00704         *pOut++ = strchr( pszType, ':' ) ? 0x20 : 0x10;
00705         *pOut++ = 0x00; *pOut++ = 0x00;
00706         *pOut++ = ( ( strlen( pszID ) & 0xFF00 ) >> 8 );
00707         *pOut++ = ( strlen( pszID ) & 0xFF );
00708         *pOut++ = ( ( strlen( pszType ) & 0xFF00 ) >> 8 );
00709         *pOut++ = ( strlen( pszType ) & 0xFF );
00710         *pOut++ = (BYTE)( ( nBody & 0xFF000000 ) >> 24 );
00711         *pOut++ = (BYTE)( ( nBody & 0x00FF0000 ) >> 16 );
00712         *pOut++ = (BYTE)( ( nBody & 0x0000FF00 ) >> 8 );
00713         *pOut++ = (BYTE)( nBody & 0x000000FF );
00714         m_nLength += 12;                                                  // Record that we wrote 12 bytes, but we really only wrote 11 (do)
00715 
00716         // Print pszID, which is blank or a GUID in hexadecimal encoding, and bytes of 0 until the total length we added is a multiple of 4
00717         Print( pszID );
00718         DWORD nPad;
00719         for ( nPad = strlen( pszID ) ; nPad & 3 ; nPad++ ) Add( "", 1 ); // If we added "a", add "000" to get to the next group of 4
00720 
00721         // Print pszType, which is "text/xml" or a URI to an XML specification, and bytes of 0 until the total length we added is a multiple of 4
00722         Print( pszType );
00723         for ( nPad = strlen( pszType ) ; nPad & 3 ; nPad++ ) Add( "", 1 ); // If we added "abcdef", add "00" to get to the next group of 4
00724 
00725         // If there is body text
00726         if ( pBody != NULL )
00727         {
00728                 // Add it, followed by bytes of 0 until the total length we added is a multiple of 4
00729                 Add( pBody, nBody );
00730                 for ( nPad = nBody ; nPad & 3 ; nPad++ ) Add( "", 1 );
00731         }
00732 }
00733 
00734 // DIME is a specification for sending and receiving SOAP messages along with additional attachments, like binary files or XML fragments
00735 // If there is a DIME message sitting in this buffer, this method can read it
00736 // Takes DWORD and CString pointers to fill with information from the DIME message
00737 // Returns false if the DIME message wasn't formatted correctly
00738 BOOL CBuffer::ReadDIME(
00739         DWORD* pnFlags,  // Writes the flags byte from the DIME message
00740         CString* psID,   // Writes a GUID in hexadecimal encoding from the DIME message
00741         CString* psType, // Writes "text/xml" or a URI to an XML specification
00742         DWORD* pnBody)   // Writes how long the body of the DIME message is
00743 {
00744         // Make sure the buffer has at least 12 bytes
00745         if ( m_nLength < 12 ) return FALSE;
00746 
00747         // Point pIn at the start of this buffer
00748         BYTE* pIn = m_pBuffer;
00749 
00750         // The first 5 bits of the first byte, 00000---, must not be 00001---
00751         if ( ( *pIn & 0xF8 ) != 0x08 ) return FALSE;
00752 
00753         // If this method was passed a pnFlags DWORD
00754         if ( pnFlags != NULL )
00755         {
00756                 // Write it for the caller
00757                 *pnFlags = 0;                  // Start it out as 0
00758                 if ( *pIn & 4 ) *pnFlags |= 1; // If the first byte in the buffer has a bit here -----1--, put one here -------1 in pnFlags
00759                 if ( *pIn & 2 ) *pnFlags |= 2; // If the first byte in the buffer has a bit here ------1-, put one here ------1- in pnFlags
00760         }
00761 
00762         // Move the pIn pointer to the second byte in the buffer, and make sure it's not 00001010 or 00010100
00763         pIn++;
00764         if ( *pIn != 0x10 && *pIn != 0x20 ) return FALSE;
00765 
00766         // Make sure bytes 3 and 4 in the buffer aren't 0, and move pIn a distance of 4 bytes into the buffer, pointing at the 5th byte
00767         pIn++;
00768         if ( *pIn++ != 0x00 ) return FALSE;
00769         if ( *pIn++ != 0x00 ) return FALSE;
00770 
00771         // Read nID, nType, and pnBody from the buffer, and move the pointer forward 8 bytes
00772         ASSERT( pnBody != NULL ); // Make sure the caller gave us access to a DWORD to write the body length
00773         WORD nID   = ( pIn[0] << 8 ) + pIn[1]; pIn += 2;
00774         WORD nType = ( pIn[0] << 8 ) + pIn[1]; pIn += 2;
00775         *pnBody    = ( pIn[0] << 24 ) + ( pIn[1] << 16 ) + ( pIn[2] << 8 ) + pIn[3]; // Write the body length in the DWORD from the caller
00776         pIn += 4; // Move forward another 4 bytes to total 8 bytes for this section
00777 
00778         // Skip forward a distance determined by the lengths we just read
00779         DWORD nSkip = 12 + ( ( nID + 3 ) & ~3 ) + ( ( nType + 3 ) & ~3 );
00780         if ( m_nLength < nSkip + ( ( *pnBody + 3 ) & ~3 ) ) return FALSE; // Make sure the buffer is big enough to skip this far forward
00781 
00782         // Read psID, a GUID in hexadecimal encoding
00783         ASSERT( psID != NULL );            // Make sure the caller gave us access to a string to write the guid in hexadecimal encoding
00784         LPSTR pszID = new CHAR[ nID + 1 ]; // Make a new buffer for the text
00785         CopyMemory( pszID, pIn, nID );     // Copy the text into the buffer
00786         pszID[ nID ] = 0;                  // Set a null terminator
00787         *psID = pszID;                     // Copy the text into the string
00788         delete [] pszID;                   // Delete our temporary buffer
00789         pIn += nID;                        // Move pIn forward beyond the psID text
00790         while ( nID++ & 3 ) pIn++;         // Move pIn forward to the next boundary of 4 bytes
00791 
00792         // Read psType, a GUID in hexadecimal encoding
00793         ASSERT( psType != NULL ); // Make sure the caller gave us access to a string to write the message body
00794         LPSTR pszType = new CHAR[ nType + 1 ]; // Make a new buffer for the text
00795         CopyMemory( pszType, pIn, nType );     // Copy the text into the buffer
00796         pszType[ nType ] = 0;                  // Set a null terminator
00797         *psType = pszType;                     // Copy the text into the string
00798         delete [] pszType;                     // Delete our temporary buffer
00799         pIn += nType;                          // Move pIn forward beyond the pszType text
00800         while ( nType++ & 3 ) pIn++;           // Move pIn forward to the next boundary of 4 bytes
00801 
00802         // Remove the first part of the DIME message from the buffer, and report success
00803         Remove( nSkip );
00804         return TRUE;
00805 }

Generated on Thu Dec 15 10:39:33 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2