Changes On Branch improve_looks_like_binary
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch improve_looks_like_binary Excluding Merge-Ins

This is equivalent to a diff from ef6c243ed9 to 5963c2dde8

2012-11-02
02:27
Merge commit warning and file content type detection changes to trunk. check-in: 0c7c61447f user: mistachkin tags: trunk
2012-11-01
20:09
Improve detection of UTF-8, UTF-16, binary data, and carriage returns during commit operations. check-in: c837e44445 user: mistachkin tags: commitWarningV2
15:38
Correct wrong manual merge. Closed-Leaf check-in: 5963c2dde8 user: jan.nijtmans tags: improve_looks_like_binary
14:49
Add back checks for FFFE and FFFF in looks_like_text: - FFFE is a reversed BOM. It could arise when an UTF-16LE and an UTF-16BE file are concatenated. This is always a fatal error, so diff should bail out early. - FFFF is a permanently unassigned character as well, which doesn't exist in any font. Sometimes uninitialized variables are eithe... check-in: 64868f2b98 user: jan.nijtmans tags: improve_looks_like_binary
12:32
merge trunk check-in: 9e97de3410 user: jan.nijtmans tags: use-blob_strip_bom
11:48
merge trunk let looks_like_text() give different values for UTF-16 BE/LE. Not used yet. check-in: 348637dedf user: jan.nijtmans tags: improve_looks_like_binary
10:20
Restore Style fix, which got lost by [618258421767778c] check-in: ef6c243ed9 user: jan.nijtmans tags: trunk
07:40
dont check for same BOM twice check-in: 8c32e6f0dd user: jan.nijtmans tags: trunk

Changes to src/checkin.c.

   885    885   /*
   886    886   ** Issue a warning and give the user an opportunity to abandon out
   887    887   ** if a Unicode (UTF-16) byte-order-mark (BOM) or a \r\n line ending
   888    888   ** is seen in a text file.
   889    889   */
   890    890   static void commit_warning(const Blob *p, int crnlOk, const char *zFilename){
   891    891     int eType;              /* return value of looks_like_text() */
   892         -  int fUnicode;           /* return value of starts_with_utf16_bom() */
   893    892     char *zMsg;             /* Warning message */
   894    893     Blob fname;             /* Relative pathname of the file */
   895    894     static int allOk = 0;   /* Set to true to disable this routine */
   896    895   
   897    896     if( allOk ) return;
   898    897     eType = looks_like_text(p);
   899         -  fUnicode = starts_with_utf16_bom(p);
   900         -  if( eType==-1 || fUnicode ){
   901         -    const char *zWarning;
          898  +  if( eType<0 ){
          899  +    const char *zWarning ;
   902    900       Blob ans;
   903    901       char cReply;
   904    902   
   905         -    if( eType==-1 && fUnicode ){
   906         -      zWarning = "Unicode and CR/NL line endings";
   907         -    }else if( eType==-1 ){
          903  +    if( eType==-3 ){
   908    904         if( crnlOk ){
   909    905           return; /* We don't want CR/NL warnings for this file. */
   910    906         }
   911    907         zWarning = "CR/NL line endings";
   912    908       }else{
   913    909         zWarning = "Unicode";
   914    910       }

Changes to src/diff.c.

    46     46   */
    47     47   #define DIFF_CANNOT_COMPUTE_BINARY \
    48     48       "cannot compute difference between binary files\n"
    49     49   
    50     50   #define DIFF_CANNOT_COMPUTE_SYMLINK \
    51     51       "cannot compute difference between symlink and regular file\n"
    52     52   
    53         -#define looks_like_binary(blob) (looks_like_text((blob)) == 0)
           53  +#define looks_like_binary(blob) ((looks_like_text(blob)&3) != 1)
    54     54   #endif /* INTERFACE */
    55     55   
    56     56   /*
    57     57   ** Maximum length of a line in a text file.  (8192)
    58     58   */
    59     59   #define LENGTH_MASK_SZ  13
    60     60   #define LENGTH_MASK     ((1<<LENGTH_MASK_SZ)-1)
................................................................................
   177    177   ** values are:
   178    178   **
   179    179   **  (1) -- The content appears to consist entirely of text, with lines
   180    180   **         delimited by line-feed characters; however, the encoding may
   181    181   **         not be UTF-8.
   182    182   **
   183    183   **  (0) -- The content appears to be binary because it contains embedded
   184         -**         NUL (\000) characters or an extremely long line.  Since this
   185         -**         function does not understand UTF-16, it may falsely consider
   186         -**         UTF-16 text to be binary.
          184  +**         NUL (\000) characters or an extremely long line.
   187    185   **
   188         -** (-1) -- The content appears to consist entirely of text, with lines
          186  +** (-1) -- The content appears to consist entirely of text, in the
          187  +**         UTF-16 (LE) encoding.
          188  +**
          189  +** (-2) -- The content appears to consist entirely of text, in the
          190  +**         UTF-16 (BE) encoding.
          191  +**
          192  +** (-3) -- The content appears to consist entirely of text, with lines
   189    193   **         delimited by carriage-return, line-feed pairs; however, the
   190    194   **         encoding may not be UTF-8.
   191    195   **
   192    196   */
   193    197   int looks_like_text(const Blob *pContent){
   194         -  const char *z = blob_buffer(pContent);
          198  +  unsigned char *z = (unsigned char *) blob_buffer(pContent);
   195    199     unsigned int n = blob_size(pContent);
   196         -  int j, c;
          200  +  int j;
          201  +  unsigned char c;
   197    202     int result = 1;  /* Assume text with no CR/NL */
   198    203   
   199    204     /* Check individual lines.
   200    205     */
   201    206     if( n==0 ) return result;  /* Empty file -> text */
   202    207     c = *z;
   203    208     if( c==0 ) return 0;  /* \000 byte in a file -> binary */
   204         -  j = (c!='\n');
          209  +  if ( (n&1)==0 ){ /* UTF-16 must have an even blob length */
          210  +    if ( (c==0xff) && (z[1]==0xfe) ){ /* UTF-16 LE BOM */
          211  +      result = -1;
          212  +      j = LENGTH_MASK/3;
          213  +      while( (n-=2)>0 ){
          214  +        c = *(z+=2);
          215  +        if( z[1]==0 ){ /* High-byte must be 0 for further checks */
          216  +          if( c==0 ) return 0;  /* \000 char in a file -> binary */
          217  +          if( c=='\n' ){
          218  +            j = LENGTH_MASK/3;
          219  +          }
          220  +        }else if( (z[1]==0xff)&&(c>0xfd) ){
          221  +          /* FFFE and FFFF are invalid UTF-16. */
          222  +          return 0;
          223  +        }
          224  +        if( --j==0 ){
          225  +          return 0;  /* Very long line -> binary */
          226  +        }
          227  +      }
          228  +      return result;
          229  +    } else if ( (c==0xfe) && (z[1]==0xff) ){ /* UTF-16 BE BOM */
          230  +      result = -2;
          231  +      ++z; j = LENGTH_MASK/3;
          232  +       while( (n-=2)>0 ){
          233  +        c = *(z+=2);
          234  +        if ( z[-1]==0 ){ /* High-byte must be 0 for further checks */
          235  +          if( c==0 ) return 0;  /* \000 char in a file -> binary */
          236  +          if( c=='\n' ){
          237  +            j = LENGTH_MASK/3;
          238  +          }
          239  +        }else if( (z[-1]==0xff)&&(c>0xfd) ){
          240  +          /* FFFE and FFFF are invalid UTF-16. */
          241  +          return 0;
          242  +        }
          243  +        if( --j==0 ){
          244  +          return 0;  /* Very long line -> binary */
          245  +        }
          246  +      }
          247  +      return result;
          248  +    }
          249  +  }
          250  +  j = LENGTH_MASK - (c!='\n');
   205    251     while( --n>0 ){
   206         -    c = *++z; ++j;
          252  +    c = *++z;
   207    253       if( c==0 ) return 0;  /* \000 byte in a file -> binary */
   208    254       if( c=='\n' ){
   209    255         if( z[-1]=='\r' ){
   210         -        result = -1;  /* Contains CR/NL, continue */
          256  +        result = -3;  /* Contains CR/NL, continue */
   211    257         }
   212         -      if( j>LENGTH_MASK ){
   213         -        return 0;  /* Very long line -> binary */
   214         -      }
   215         -      j = 0;
          258  +      j = LENGTH_MASK;
          259  +    }
          260  +    if( --j==0 ){
          261  +      return 0;  /* Very long line -> binary */
   216    262       }
   217    263     }
   218         -  if( j>LENGTH_MASK ){
   219         -    return 0;  /* Very long line -> binary */
   220         -  }
   221    264     return result;  /* No problems seen -> not binary */
   222    265   }
   223    266   
   224         -/*
   225         -** This function returns non-zero if the blob starts with a UTF-16le or
   226         -** UTF-16be byte-order-mark (BOM).
   227         -*/
   228         -int starts_with_utf16_bom(const Blob *pContent){
   229         -  const char *z = blob_buffer(pContent);
   230         -  int c1, c2;
   231         -
   232         -  if( blob_size(pContent)<2 ) return 0;
   233         -  c1 = z[0]; c2 = z[1];
   234         -  if( (c1==(char)0xff) && (c2==(char)0xfe) ){
   235         -    return 1;
   236         -  }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
   237         -    return 1;
   238         -  }
   239         -  return 0;
   240         -}
   241         -
   242    267   /*
   243    268   ** Return true if two DLine elements are identical.
   244    269   */
   245    270   static int same_dline(DLine *pA, DLine *pB){
   246    271     return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
   247    272   }
   248    273   

Changes to src/doc.c.

    24     24   
    25     25   /*
    26     26   ** Try to guess the mimetype from content.
    27     27   **
    28     28   ** If the content is pure text, return NULL.
    29     29   **
    30     30   ** For image types, attempt to return an appropriate mimetype
    31         -** name like "image/gif" or "image/jpeg".  
           31  +** name like "image/gif" or "image/jpeg".
    32     32   **
    33     33   ** For any other binary type, return "unknown/unknown".
    34     34   */
    35     35   const char *mimetype_from_content(Blob *pBlob){
    36     36     int i;
    37     37     int n;
    38     38     const unsigned char *x;
    39     39   
    40         -  static const char isBinary[] = {
    41         -     1, 1, 1, 1,  1, 1, 1, 1,    1, 0, 0, 1,  0, 0, 1, 1,
    42         -     1, 1, 1, 1,  1, 1, 1, 1,    1, 1, 1, 0,  1, 1, 1, 1,
           40  +  static const char isBinary[256] = {
           41  +     1, 1, 1, 1,  1, 1, 1, 1,    1, 0, 0, 0,  0, 0, 1, 1,
           42  +     1, 1, 1, 1,  1, 1, 1, 1,    1, 1, 0, 0,  1, 1, 1, 1,
    43     43     };
    44     44   
    45     45     /* A table of mimetypes based on file content prefixes
    46     46     */
    47     47     static const struct {
    48     48       const char *zPrefix;       /* The file prefix */
    49     49       int size;                  /* Length of the prefix */
................................................................................
    56     56       { "\377\330\377",            3, "image/jpeg" },
    57     57     };
    58     58   
    59     59     x = (const unsigned char*)blob_buffer(pBlob);
    60     60     n = blob_size(pBlob);
    61     61     for(i=0; i<n; i++){
    62     62       unsigned char c = x[i];
    63         -    if( c<=0x1f && isBinary[c] ){
           63  +    if( isBinary[c] ){
    64     64         break;
    65     65       }
    66     66     }
    67     67     if( i>=n ){
    68     68       return 0;   /* Plain text */
    69     69     }
    70     70     for(i=0; i<sizeof(aMime)/sizeof(aMime[0]); i++){
................................................................................
    81     81   const char *mimetype_from_name(const char *zName){
    82     82     const char *z;
    83     83     int i;
    84     84     int first, last;
    85     85     int len;
    86     86     char zSuffix[20];
    87     87   
    88         -  /* A table of mimetypes based on file suffixes. 
           88  +  /* A table of mimetypes based on file suffixes.
    89     89     ** Suffixes must be in sorted order so that we can do a binary
    90     90     ** search to find the mime-type
    91     91     */
    92     92     static const struct {
    93     93       const char *zSuffix;       /* The file suffix */
    94     94       int size;                  /* Length of the suffix */
    95     95       const char *zMimetype;     /* The corresponding mimetype */
................................................................................
   472    472       if( content_get(rid, &filebody)==0 ){
   473    473         goto doc_not_found;
   474    474       }
   475    475       db_end_transaction(0);
   476    476     }
   477    477   
   478    478     /* The file is now contained in the filebody blob.  Deliver the
   479         -  ** file to the user 
          479  +  ** file to the user
   480    480     */
   481    481     zMime = P("mimetype");
   482    482     if( zMime==0 ){
   483    483       zMime = mimetype_from_name(zName);
   484    484     }
   485    485     Th_Store("doc_name", zName);
   486    486     Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
................................................................................
   511    511   
   512    512   doc_not_found:
   513    513     /* Jump here when unable to locate the document */
   514    514     db_end_transaction(0);
   515    515     style_header("Document Not Found");
   516    516     @ <p>No such document: %h(zName)</p>
   517    517     style_footer();
   518         -  return;  
          518  +  return;
   519    519   }
   520    520   
   521    521   /*
   522    522   ** The default logo.
   523    523   */
   524    524   static const unsigned char aLogo[] = {
   525         -    71,  73,  70,  56,  55,  97,  62,   0,  71,   0, 244,   0,   0,  85, 
   526         -   129, 149,  95, 136, 155,  99, 139, 157, 106, 144, 162, 113, 150, 166, 
   527         -   116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184, 
   528         -   195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201, 
   529         -   215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237, 
   530         -   233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255,   0,   0, 
   531         -     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
   532         -     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  44,   0,   0, 
   533         -     0,   0,  62,   0,  71,   0,   0,   5, 255,  96, 100, 141, 100, 105, 
   534         -   158, 168,  37,  41, 132, 192, 164, 112,  44, 207, 102,  99,   0,  56, 
   535         -    16,  84, 116, 239, 199, 141,  65, 110, 232, 248,  25, 141, 193, 161, 
   536         -    82, 113, 108, 202,  32,  55, 229, 210,  73,  61,  41, 164,  88, 102, 
   537         -   181,  10,  41,  96, 179,  91, 106,  35, 240,   5, 135, 143, 137, 242, 
   538         -    87, 123, 246,  33, 190,  81, 108, 163, 237, 198,  14,  30, 113, 233, 
   539         -   131,  78, 115,  72,  11, 115,  87, 101,  19, 124,  51,  66,  74,   8, 
   540         -    19,  16,  67, 100,  74, 133,  50,  15, 101, 135,  56,  11,  74,   6, 
   541         -   143,  49, 126, 106,  56,   8, 145,  67,   9, 152,  48, 139, 155,   5, 
   542         -    22,  13,  74, 115, 161,  41, 147, 101,  13, 130,  57, 132, 170,  40, 
   543         -   167, 155,   0,  94,  57,   3, 178,  48, 183, 181,  57, 160, 186,  40, 
   544         -    19, 141, 189,   0,  69, 192,  40,  16, 195, 155, 185, 199,  41, 201, 
   545         -   189, 191, 205, 193, 188, 131, 210,  49, 175,  88, 209, 214,  38,  19, 
   546         -     3,  11,  19, 111, 127,  60, 219,  39,  55, 204,  19,  11,   6, 100, 
   547         -     5,  10, 227, 228,  37, 163,   0, 239, 117,  56, 238, 243,  49, 195, 
   548         -   177, 247,  48, 158,  56, 251,  50, 216, 254, 197,  56, 128, 107, 158, 
   549         -     2, 125, 171, 114,  92, 218, 246,  96,  66,   3,   4,  50, 134, 176, 
   550         -   145,   6,  97,  64, 144,  24,  19, 136, 108,  91, 177, 160,   0, 194, 
   551         -    19, 253,   0, 216, 107, 214, 224, 192, 129,   5,  16,  83, 255, 244, 
   552         -    43, 213, 195,  24, 159,  27, 169,  64, 230,  88, 208, 227, 129, 182, 
   553         -    54,   4,  89, 158,  24, 181, 163, 199,   1, 155,  52, 233,   8, 130, 
   554         -   176,  83,  24, 128, 137,  50,  18,  32,  48,  48, 114,  11, 173, 137, 
   555         -    19, 110,   4,  64, 105,   1, 194,  30, 140,  68,  15,  24,  24, 224, 
   556         -    50,  76,  70,   0,  11, 171,  54,  26, 160, 181, 194, 149, 148,  40, 
   557         -   174, 148, 122,  64, 180, 208, 161,  17, 207, 112, 164,   1, 128,  96, 
   558         -   148,  78,  18,  21, 194,  33, 229,  51, 247,  65, 133,  97,   5, 250, 
   559         -    69, 229, 100,  34, 220, 128, 166, 116, 190,  62,   8, 167, 195, 170, 
   560         -    47, 163,   0, 130,  90, 152,  11, 160, 173, 170,  27, 154,  26,  91, 
   561         -   232, 151, 171,  18,  14, 162, 253,  98, 170,  18,  70, 171,  64, 219, 
   562         -    10,  67, 136, 134, 187, 116,  75, 180,  46, 179, 174, 135,   4, 189, 
   563         -   229, 231,  78,  40,  10,  62, 226, 164, 172,  64, 240, 167, 170,  10, 
   564         -    18, 124, 188,  10, 107,  65, 193,  94,  11,  93, 171,  28, 248,  17, 
   565         -   239,  46, 140,  78,  97,  34,  25, 153,  36,  99,  65, 130,   7, 203, 
   566         -   183, 168,  51,  34, 136,  25, 140,  10,   6,  16,  28, 255, 145, 241, 
   567         -   230, 140,  10,  66, 178, 167, 112,  48, 192, 128, 129,   9,  31, 141, 
   568         -    84, 138,  63, 163, 162,   2, 203, 206, 240,  56,  55,  98, 192, 188, 
   569         -    15, 185,  50, 160,   6,   0, 125,  62,  33, 214, 195,  33,   5,  24, 
   570         -   184,  25, 231,  14, 201, 245, 144,  23, 126, 104, 228,   0, 145,   2, 
   571         -    13, 140, 244, 212,  17,  21,  20, 176, 159,  17,  95, 225, 160, 128, 
   572         -    16,   1,  32, 224, 142,  32, 227, 125,  87,  64,   0,  16,  54, 129, 
   573         -   205,   2, 141,  76,  53, 130, 103,  37, 166,  64, 144, 107,  78, 196, 
   574         -     5, 192,   0,  54,  50, 229,   9, 141,  49,  84, 194,  35,  12, 196, 
   575         -   153,  48, 192, 137,  57,  84,  24,   7,  87, 159, 249, 240, 215, 143, 
   576         -   105, 241, 118, 149,   9, 139,   4,  64, 203, 141,  35, 140, 129, 131, 
   577         -    16, 222, 125, 231, 128,   2, 238,  17, 152,  66,   3,   5,  56, 224, 
   578         -   159, 103,  16,  76,  25,  75,   5,  11, 164, 215,  96,   9,  14,  16, 
   579         -    36, 225,  15,  11,  40, 144, 192, 156,  41,  10, 178, 199,   3,  66, 
   580         -    64,  80, 193,   3, 124,  90,  48, 129, 129, 102, 177,  18, 192, 154, 
   581         -    49,  84, 240, 208,  92,  22, 149,  96,  39,   9,  31,  74,  17,  94, 
   582         -     3,   8, 177, 199,  72,  59,  85,  76,  25, 216,   8, 139, 194, 197, 
   583         -   138, 163,  69,  96, 115,   0, 147,  72,  72,  84,  28,  14,  79,  86, 
   584         -   233, 230,  23, 113,  26, 160, 128,   3,  10,  58, 129, 103,  14, 159, 
   585         -   214, 163, 146, 117, 238, 213, 154, 128, 151, 109,  84,  64, 217,  13, 
   586         -    27,  10, 228,  39,   2, 235, 164, 168,  74,   8,   0,  59, 
          525  +    71,  73,  70,  56,  55,  97,  62,   0,  71,   0, 244,   0,   0,  85,
          526  +   129, 149,  95, 136, 155,  99, 139, 157, 106, 144, 162, 113, 150, 166,
          527  +   116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184,
          528  +   195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201,
          529  +   215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237,
          530  +   233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255,   0,   0,
          531  +     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          532  +     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  44,   0,   0,
          533  +     0,   0,  62,   0,  71,   0,   0,   5, 255,  96, 100, 141, 100, 105,
          534  +   158, 168,  37,  41, 132, 192, 164, 112,  44, 207, 102,  99,   0,  56,
          535  +    16,  84, 116, 239, 199, 141,  65, 110, 232, 248,  25, 141, 193, 161,
          536  +    82, 113, 108, 202,  32,  55, 229, 210,  73,  61,  41, 164,  88, 102,
          537  +   181,  10,  41,  96, 179,  91, 106,  35, 240,   5, 135, 143, 137, 242,
          538  +    87, 123, 246,  33, 190,  81, 108, 163, 237, 198,  14,  30, 113, 233,
          539  +   131,  78, 115,  72,  11, 115,  87, 101,  19, 124,  51,  66,  74,   8,
          540  +    19,  16,  67, 100,  74, 133,  50,  15, 101, 135,  56,  11,  74,   6,
          541  +   143,  49, 126, 106,  56,   8, 145,  67,   9, 152,  48, 139, 155,   5,
          542  +    22,  13,  74, 115, 161,  41, 147, 101,  13, 130,  57, 132, 170,  40,
          543  +   167, 155,   0,  94,  57,   3, 178,  48, 183, 181,  57, 160, 186,  40,
          544  +    19, 141, 189,   0,  69, 192,  40,  16, 195, 155, 185, 199,  41, 201,
          545  +   189, 191, 205, 193, 188, 131, 210,  49, 175,  88, 209, 214,  38,  19,
          546  +     3,  11,  19, 111, 127,  60, 219,  39,  55, 204,  19,  11,   6, 100,
          547  +     5,  10, 227, 228,  37, 163,   0, 239, 117,  56, 238, 243,  49, 195,
          548  +   177, 247,  48, 158,  56, 251,  50, 216, 254, 197,  56, 128, 107, 158,
          549  +     2, 125, 171, 114,  92, 218, 246,  96,  66,   3,   4,  50, 134, 176,
          550  +   145,   6,  97,  64, 144,  24,  19, 136, 108,  91, 177, 160,   0, 194,
          551  +    19, 253,   0, 216, 107, 214, 224, 192, 129,   5,  16,  83, 255, 244,
          552  +    43, 213, 195,  24, 159,  27, 169,  64, 230,  88, 208, 227, 129, 182,
          553  +    54,   4,  89, 158,  24, 181, 163, 199,   1, 155,  52, 233,   8, 130,
          554  +   176,  83,  24, 128, 137,  50,  18,  32,  48,  48, 114,  11, 173, 137,
          555  +    19, 110,   4,  64, 105,   1, 194,  30, 140,  68,  15,  24,  24, 224,
          556  +    50,  76,  70,   0,  11, 171,  54,  26, 160, 181, 194, 149, 148,  40,
          557  +   174, 148, 122,  64, 180, 208, 161,  17, 207, 112, 164,   1, 128,  96,
          558  +   148,  78,  18,  21, 194,  33, 229,  51, 247,  65, 133,  97,   5, 250,
          559  +    69, 229, 100,  34, 220, 128, 166, 116, 190,  62,   8, 167, 195, 170,
          560  +    47, 163,   0, 130,  90, 152,  11, 160, 173, 170,  27, 154,  26,  91,
          561  +   232, 151, 171,  18,  14, 162, 253,  98, 170,  18,  70, 171,  64, 219,
          562  +    10,  67, 136, 134, 187, 116,  75, 180,  46, 179, 174, 135,   4, 189,
          563  +   229, 231,  78,  40,  10,  62, 226, 164, 172,  64, 240, 167, 170,  10,
          564  +    18, 124, 188,  10, 107,  65, 193,  94,  11,  93, 171,  28, 248,  17,
          565  +   239,  46, 140,  78,  97,  34,  25, 153,  36,  99,  65, 130,   7, 203,
          566  +   183, 168,  51,  34, 136,  25, 140,  10,   6,  16,  28, 255, 145, 241,
          567  +   230, 140,  10,  66, 178, 167, 112,  48, 192, 128, 129,   9,  31, 141,
          568  +    84, 138,  63, 163, 162,   2, 203, 206, 240,  56,  55,  98, 192, 188,
          569  +    15, 185,  50, 160,   6,   0, 125,  62,  33, 214, 195,  33,   5,  24,
          570  +   184,  25, 231,  14, 201, 245, 144,  23, 126, 104, 228,   0, 145,   2,
          571  +    13, 140, 244, 212,  17,  21,  20, 176, 159,  17,  95, 225, 160, 128,
          572  +    16,   1,  32, 224, 142,  32, 227, 125,  87,  64,   0,  16,  54, 129,
          573  +   205,   2, 141,  76,  53, 130, 103,  37, 166,  64, 144, 107,  78, 196,
          574  +     5, 192,   0,  54,  50, 229,   9, 141,  49,  84, 194,  35,  12, 196,
          575  +   153,  48, 192, 137,  57,  84,  24,   7,  87, 159, 249, 240, 215, 143,
          576  +   105, 241, 118, 149,   9, 139,   4,  64, 203, 141,  35, 140, 129, 131,
          577  +    16, 222, 125, 231, 128,   2, 238,  17, 152,  66,   3,   5,  56, 224,
          578  +   159, 103,  16,  76,  25,  75,   5,  11, 164, 215,  96,   9,  14,  16,
          579  +    36, 225,  15,  11,  40, 144, 192, 156,  41,  10, 178, 199,   3,  66,
          580  +    64,  80, 193,   3, 124,  90,  48, 129, 129, 102, 177,  18, 192, 154,
          581  +    49,  84, 240, 208,  92,  22, 149,  96,  39,   9,  31,  74,  17,  94,
          582  +     3,   8, 177, 199,  72,  59,  85,  76,  25, 216,   8, 139, 194, 197,
          583  +   138, 163,  69,  96, 115,   0, 147,  72,  72,  84,  28,  14,  79,  86,
          584  +   233, 230,  23, 113,  26, 160, 128,   3,  10,  58, 129, 103,  14, 159,
          585  +   214, 163, 146, 117, 238, 213, 154, 128, 151, 109,  84,  64, 217,  13,
          586  +    27,  10, 228,  39,   2, 235, 164, 168,  74,   8,   0,  59,
   587    587   };
   588    588   
   589    589   /*
   590    590   ** WEBPAGE: logo
   591    591   **
   592    592   ** Return the logo image.  This image is available to anybody who can see
   593    593   ** the login page.  It is designed for use in the upper left-hand corner