home *** CD-ROM | disk | FTP | other *** search
/ Dynamic HTML in Action / Dynamicke-HTML-v-akci-covermount.bin / XML / PARSER / XMLINST.EXE / classes / com / ms / xml / xmlstream / XMLURLStream / XMLStream.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-27  |  8.6 KB  |  321 lines

  1. // XMLStream.cpp : Implementation of CXMLStream
  2. #include "stdafx.h"
  3. #include "XMLURLStream.h"
  4. #include "XMLStream.h"
  5. #include "urlmon.h"
  6. #include "stdio.h"
  7.  
  8. //########################
  9. // WARING: - the SIZE variable has to be larger than the buffer length
  10. // given in 'read' so that we do not lose first buffer in the case
  11. // that setEncoding is called.  For example, switching from the default
  12. // UTF8 to windows-cp1252 doesn't work if the buffers are the same size.
  13. // 
  14.  
  15. /////////////////////////////////////////////////////////////////////////////
  16. // CXMLStream
  17. /////////////////////////////////////////////////////////////////////////////
  18.  
  19. /////////////////////////////////////////////////////////////////////////////
  20. // opens an input stream for @url and guesses encoding
  21. // return: encoding, or -1 if failed
  22. /////////////////////////////////////////////////////////////////////////////
  23. STDMETHODIMP CXMLStream::Open(BSTR url, int * outEncoding)
  24. {
  25.     DWORD dwGot;
  26.     unsigned char c1, c2, c3, c4;
  27.  
  28.     encoding = -1;
  29. //    HRESULT hr = URLOpenBlockingStream(NULL, url, &pStream, 0, NULL);
  30.     IMoniker *moniker;
  31.     HRESULT hr = CreateURLMoniker(NULL, url, &moniker);
  32.     if (hr != S_OK)
  33.         return hr;
  34.     IBindCtx *pbc;
  35.     CreateBindCtx(0, &pbc);
  36.     hr = moniker->BindToStorage(pbc, NULL, IID_IStream, (void **)(&pStream));
  37.     
  38.     if (hr == S_OK)
  39.     {
  40.         index = size = 0;
  41.         littleendian   = false;
  42.         byteOrderMark  = false;
  43.         encoding       = UTF8;    // Default encoding
  44.                  
  45.         pStream->Read(buffer, SIZE, &dwGot);
  46.         if (dwGot < 4)
  47.             return -1;
  48.         size = (int)dwGot;
  49.         index = 0;
  50.  
  51.         // checks the first four bytes of the IStream in order to make a guess
  52.         // as to the character encoding of the file.
  53.         // Assumes that the document is following the XML standard and that
  54.         // any non-UTF-8 file will begin with a <?XML> tag.
  55.         c1 = buffer[0];
  56.         c2 = buffer[1];
  57.         c3 = buffer[2];
  58.         c4 = buffer[3];
  59.         if( c1 == 0xFE && c2 == 0xFF && c3 == 0x00 && c4 == 0x3C )
  60.         {
  61.             // UCS-2, big-endian
  62.             byteOrderMark = true;
  63.             encoding      = UCS2;
  64.         }
  65.         else if( c1 == 0xFF && c2 == 0xFE && c3 == 0x3C && c4 == 0x00 )
  66.         {
  67.             // UCS-2, little-endian
  68.             littleendian  = true;
  69.             byteOrderMark = true;
  70.             encoding      = UCS2;
  71.         }
  72.         else if( c1 == 0x00 && c2 == 0x3C && c3 == 0x00 && c4 == 0x3F )
  73.         {
  74.             // UCS-2, big-endian, no Byte Order Mark
  75.             encoding      = UCS2;
  76.         }
  77.         else if( c1 == 0x3C && c2 == 0x00 && c3 == 0x3F && c4 == 0x00 )
  78.         {
  79.             // UCS-2, little-endian, no Byte Order Mark
  80.             littleendian  = true;
  81.             encoding      = UCS2;           
  82.         }
  83.         else if( c1 == 0x3C && c2 == 0x3F && 
  84.             c3 - 'x' + 'X' == 0x58 && 
  85.             c4 - 'm' + 'M' == 0x4D )
  86.         {
  87.             // UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC,
  88.             // or any other encoding that ensures that ASCII has normal positions
  89.             encoding      = ASCII;
  90.         }
  91.         else if( c1 == 0x00 && c2 == 0x00 && c3 == 0x00 && c4 == 0x3C )
  92.         {
  93.             // UCS-4, big-endian machine (1234 order)
  94.             // Until UCS-4 is implemented
  95.             encoding  = UCS4;
  96.         }
  97.         else if( c1 == 0x3C && c2 == 0x00 && c3 == 0x00 && c4 == 0x00 )
  98.         {
  99.             // UCS-4, little-endian machine (4321 order)
  100.             // Until UCS-4 is implemented
  101.             encoding  = UCS4;
  102.         }
  103.         else if( c1 == 0x00 && c2 == 0x00 && c3 == 0x3C && c4 == 0x00 )
  104.         {
  105.             // UCS-4, unusual octet order (2143 order)
  106.             // Until UCS-4 is implemented
  107.             encoding  = UCS4;
  108.         }
  109.         else if( c1 == 0x00 && c2 == 0x3C && c3 == 0x00 && c4 == 0x00 )
  110.         {
  111.             // UCS-4, unusual octet order (3412 order)
  112.             // Until UCS-4 is implemented
  113.             encoding  = UCS4;
  114.         }
  115.         else if( c1 == 0x4C && c2 == 0x6F && c3 == 0xE7 && c4 == 0xD4 )
  116.         {
  117.             // EBCDIC - We do NOT support this!
  118.             // Until EBCDIC is implemented
  119.             encoding  = EBCDIC;
  120.         }
  121.  
  122.         if (encoding == UCS2 && byteOrderMark)
  123.             index = 2;
  124.     }
  125.     else
  126.         return hr;
  127.  
  128.     *outEncoding = encoding; 
  129.     return S_OK;
  130. }
  131.  
  132. /////////////////////////////////////////////////////////////////////////////
  133. // close the stream
  134. /////////////////////////////////////////////////////////////////////////////
  135. STDMETHODIMP CXMLStream::Close()
  136. {
  137.     if (pStream)
  138.     {
  139.         pStream->Release();
  140.         pStream = NULL;
  141.     }
  142.     return S_OK;
  143. }
  144.  
  145. /////////////////////////////////////////////////////////////////////////////
  146. // reads up to @len characters into @buf 
  147. // return: number of characters in @buf
  148. /////////////////////////////////////////////////////////////////////////////
  149. STDMETHODIMP CXMLStream::Read(int * buf, int len, int * al)
  150. {
  151.     DWORD dwGot;
  152.     HRESULT hr = NOERROR;
  153.     int l = 0;
  154.     int state = 0, v = 0, c = 0;
  155.     bool eof = false;
  156.  
  157.     switch (encoding)
  158.     {
  159.         case UCS2:
  160.             while (l < len)
  161.             {
  162.                 if (index >= size)
  163.                 {
  164.                     *al = l;
  165.                     if (eof)
  166.                         return S_OK;
  167.                     hr = pStream->Read(buffer, SIZE, &dwGot);
  168.                     if (dwGot == 0)
  169.                     {
  170.                         return S_OK;
  171.                     }
  172.                     else if (dwGot < SIZE)
  173.                         eof = true;
  174.                     index = 0;
  175.                     size = (int)dwGot;
  176.                 }
  177.                
  178.                 int b1 = buffer[index++];
  179.                 int b2 = buffer[index++];
  180.                 if (littleendian)  // byte swap
  181.                     buf[l++] = ((b2 << 8) | b1);
  182.                 else 
  183.                     buf[l++] = ((b1 << 8) | b2);
  184.             }
  185.             *al = l;
  186.             return S_OK;
  187.         case UTF8:
  188.             while (l < len)
  189.             {
  190.                 if (index >= size)
  191.                 {
  192.                     *al = l;
  193.                     if (eof)
  194.                         return S_OK;
  195.                     hr = pStream->Read(buffer, SIZE, &dwGot);
  196.                     if (dwGot == 0)
  197.                     {
  198.                         return S_OK;
  199.                     }
  200.                     else if (dwGot < SIZE)
  201.                         eof = true;
  202.                     index = 0;
  203.                     size = dwGot;
  204.                 }
  205.                 c = (int)buffer[index++];
  206.                 switch (state) 
  207.                 {
  208.                     case 0: // first byte of characters
  209.                         if (c >> 7 == 0)  // 0xxxxxxx, one byte, \u0000 - \u007F
  210.                         {
  211.                             buf[l++] = (int)c;
  212.                         }
  213.                         else if (c >> 5 == 0x06) // 110xxxxx, 10xxxxxx, two bytes, \u0080 - \u07FF
  214.                         {
  215.                             v = (int) c & 0x1f;
  216.                             state = 1;
  217.                         }
  218.                         else // 1110xxxx, 10xxxxxx, 10xxxxxx, three bytes, \u0800 - \uFFFF
  219.                         {
  220.                             v = (int) c & 0x0f;
  221.                             state = 2;
  222.                         }
  223.                         break;
  224.                     case 1: // second byte of a two-byte character, 10xxxxxx
  225.                         buf[l++] = (v << 6) + (c & 0x3f);
  226.                         state = 0;
  227.                         break;
  228.                     case 2: // second byte of a three-byte character, 10xxxxxx
  229.                         v = (v << 6) + (c & 0x3f);
  230.                         state = 3;
  231.                         break;
  232.                     case 3: // third byte of a three-byte character, 10xxxxxx
  233.                         buf[l++] = (v << 6) + (c & 0x3f);
  234.                         state = 0;
  235.                         break;
  236.                 }
  237.             }
  238.             *al = l;
  239.             return S_OK;
  240.         case UCS4: // until UCS4 & EBCDIC are implemented, uses ASCII decoding
  241.         case EBCDIC:
  242.         case ASCII:
  243.         case W1252:
  244.         {
  245.             while (l < len)
  246.             {
  247.                 if (index >= size)
  248.                 {
  249.                     *al = l;
  250.                     if (eof)
  251.                         return S_OK;
  252.                     hr = pStream->Read(buffer, SIZE, &dwGot);
  253.                     
  254.                     if (dwGot == 0)
  255.                     {
  256.                         return S_OK;
  257.                     }
  258.                     else if (dwGot < SIZE)
  259.                         eof = true;
  260.                     index = 0;
  261.                     size = dwGot;
  262.                 }
  263.                 buf[l++] = (int)buffer[index++];
  264.             }
  265.             *al = l;
  266.             return S_OK;
  267.         }
  268.         default: *al = -1; return -1;
  269.     }
  270. }
  271.  
  272. /////////////////////////////////////////////////////////////////////////////
  273. // resets encoding. 
  274. // we assume that setEncoding happens within the first SIZE bytes of input
  275. // <code>index is reseted to @offset
  276. /////////////////////////////////////////////////////////////////////////////
  277. STDMETHODIMP CXMLStream::SetEncoding(int encoding, int offset)
  278. {
  279.     int c = 0, l = 0;
  280.  
  281.     // reset index
  282.     switch (encoding)
  283.     {
  284.         case UCS2:
  285.             index = 2 * offset;
  286.             if (byteOrderMark)
  287.                 index += 2;
  288.             break;
  289.         case UTF8:
  290.             index = 0;
  291.             while (l < offset)
  292.             {
  293.                 c = (int)buffer[index];
  294.                 if (c >> 7 == 0) // one byte
  295.                 {
  296.                     index++;
  297.                 }
  298.                 else if (c >> 5 == 0x06) // two bytes
  299.                 {
  300.                     index += 2;
  301.                 }
  302.                 else // three bytes
  303.                 {
  304.                     index += 3;
  305.                 }
  306.                 l++;
  307.             }
  308.             break;
  309.         case UCS4: // until UCS4 & EBCDIC are implemented, uses ASCII decoding
  310.         case EBCDIC:
  311.         case ASCII:
  312.         case W1252:
  313.         default:
  314.             index = offset;
  315.             break;
  316.     }
  317.  
  318.     this->encoding = encoding;
  319.     return S_OK;
  320. }
  321.