134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
2d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang//  Process IPTC data and XMP data.
334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include "jhead.h"
534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang// IPTC entry types known to Jhead (there's many more defined)
7d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define IPTC_RECORD_VERSION         0x00
834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_SUPLEMENTAL_CATEGORIES 0x14
934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_KEYWORDS               0x19
1034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_CAPTION                0x78
1134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_AUTHOR                 0x7A
1234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_HEADLINE               0x69
1334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_SPECIAL_INSTRUCTIONS   0x28
1434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_CATEGORY               0x0F
1534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_BYLINE                 0x50
1634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_BYLINE_TITLE           0x55
1734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_CREDIT                 0x6E
1834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_SOURCE                 0x73
1934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_COPYRIGHT_NOTICE       0x74
2034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_OBJECT_NAME            0x05
2134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_CITY                   0x5A
2234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_STATE                  0x5F
2334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_COUNTRY                0x65
2434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_TRANSMISSION_REFERENCE 0x67
2534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_DATE                   0x37
2634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_COPYRIGHT              0x0A
2734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_COUNTRY_CODE           0x64
2834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define IPTC_REFERENCE_SERVICE      0x2D
29d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define IPTC_TIME_CREATED           0x3C
30d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define IPTC_SUB_LOCATION           0x5C
31d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang#define IPTC_IMAGE_TYPE             0x82
3234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
3334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
3434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//  Process and display IPTC marker.
3534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
3634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//  IPTC block consists of:
3734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - Marker:               1 byte      (0xED)
3834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - Block length:         2 bytes
3934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - IPTC Signature:       14 bytes    ("Photoshop 3.0\0")
4034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - 8BIM Signature        4 bytes     ("8BIM")
4134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - IPTC Block start      2 bytes     (0x04, 0x04)
4234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - IPTC Header length    1 byte
4334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - IPTC header           Header is padded to even length, counting the length byte
4434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - Length                4 bytes
4534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//      - IPTC Data which consists of a number of entries, each of which has the following format:
4634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//              - Signature     2 bytes     (0x1C02)
4734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//              - Entry type    1 byte      (for defined entry types, see #defines above)
4834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//              - entry length  2 bytes
4934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//              - entry data    'entry length' bytes
5034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
5134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
5234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectvoid show_IPTC (unsigned char* Data, unsigned int itemlen)
5334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
5434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char IptcSig1[] = "Photoshop 3.0";
5534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char IptcSig2[] = "8BIM";
5634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char IptcSig3[] = {0x04, 0x04};
5734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned char * pos    = Data + sizeof(short);   // position data pointer after length field
5934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned char * maxpos = Data+itemlen;
6034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char  headerLen = 0;
6134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (itemlen < 25) goto corrupt;
6334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Check IPTC signatures
6534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (memcmp(pos, IptcSig1, sizeof(IptcSig1)-1) != 0) goto badsig;
6634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    pos += sizeof(IptcSig1);      // move data pointer to the next field
6734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (memcmp(pos, IptcSig2, sizeof(IptcSig2)-1) != 0) goto badsig;
6934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    pos += sizeof(IptcSig2)-1;          // move data pointer to the next field
7034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
7134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (memcmp(pos, IptcSig3, sizeof(IptcSig3)) != 0){
7234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectbadsig:
7334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ShowTags){
7434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrNonfatal("IPTC type signature mismatch\n",0,0);
7534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
7634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return;
7734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
7834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    pos += sizeof(IptcSig3);          // move data pointer to the next field
7934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
8034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (pos >= maxpos) goto corrupt;
8134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
8234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // IPTC section found
8334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
8434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Skip header
8534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    headerLen = *pos++;                     // get header length and move data pointer to the next field
8634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    pos += headerLen + 1 - (headerLen % 2); // move data pointer to the next field (Header is padded to even length, counting the length byte)
8734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
8834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (pos+4 >= maxpos) goto corrupt;
8934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
9034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Get length (from motorola format)
9134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    //length = (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3);
9234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
93d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    pos += 4;                    // move data pointer to the next field
9434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
9534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("======= IPTC data: =======\n");
9634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
9734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Now read IPTC data
9834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    while (pos < (Data + itemlen-5)) {
9934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        short  signature;
100d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        unsigned char   type = 0;
10134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        short  length = 0;
10234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        char * description = NULL;
10334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
10434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (pos+5 > maxpos) goto corrupt;
10534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
10634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        signature = (*pos << 8) + (*(pos+1));
107d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        pos += 2;
10834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
10934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (signature != 0x1C02){
11034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
11134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
11234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
11334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        type    = *pos++;
11434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        length  = (*pos << 8) + (*(pos+1));
115d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        pos    += 2;                          // Skip tag length
11634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
11734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (pos+length > maxpos) goto corrupt;
11834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Process tag here
11934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        switch (type) {
120d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_RECORD_VERSION:
121d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                printf("Record vers.  : %d\n", (*pos << 8) + (*(pos+1)));
122d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                break;
123d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
12434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_SUPLEMENTAL_CATEGORIES:  description = "SuplementalCategories"; break;
12534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_KEYWORDS:                description = "Keywords"; break;
12634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_CAPTION:                 description = "Caption"; break;
12734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_AUTHOR:                  description = "Author"; break;
12834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_HEADLINE:                description = "Headline"; break;
129d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_SPECIAL_INSTRUCTIONS:    description = "Spec. Instr."; break;
13034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_CATEGORY:                description = "Category"; break;
13134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_BYLINE:                  description = "Byline"; break;
132d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_BYLINE_TITLE:            description = "Byline Title"; break;
13334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_CREDIT:                  description = "Credit"; break;
13434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_SOURCE:                  description = "Source"; break;
13534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_COPYRIGHT_NOTICE:        description = "(C)Notice"; break;
136d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_OBJECT_NAME:             description = "Object Name"; break;
13734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_CITY:                    description = "City"; break;
13834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_STATE:                   description = "State"; break;
13934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_COUNTRY:                 description = "Country"; break;
14034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_TRANSMISSION_REFERENCE:  description = "OriginalTransmissionReference"; break;
14134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_DATE:                    description = "DateCreated"; break;
14234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case IPTC_COPYRIGHT:               description = "(C)Flag"; break;
143d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_REFERENCE_SERVICE:       description = "Country Code"; break;
144d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_COUNTRY_CODE:            description = "Ref. Service"; break;
145d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_TIME_CREATED:            description = "Time Created"; break;
146d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_SUB_LOCATION:            description = "Sub Location"; break;
147d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            case IPTC_IMAGE_TYPE:              description = "Image type"; break;
148d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
14934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            default:
15034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (ShowTags){
151d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    printf("Unrecognised IPTC tag: %d\n", type );
15234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
15334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            break;
15434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
15534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (description != NULL) {
15634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            char TempBuf[32];
15734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            memset(TempBuf, 0, sizeof(TempBuf));
158d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            memset(TempBuf, ' ', 14);
15934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            memcpy(TempBuf, description, strlen(description));
16034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            strcat(TempBuf, ":");
16134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("%s %*.*s\n", TempBuf, length, length, pos);
16234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
16334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        pos += length;
16434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
16534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return;
16634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectcorrupt:
16734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ErrNonfatal("Pointer corruption in IPTC\n",0,0);
16834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
169d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
170d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
171d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
172d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang//--------------------------------------------------------------------------
173d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang// Dump contents of XMP section
174d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang//--------------------------------------------------------------------------
175d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Changvoid ShowXmp(Section_t XmpSection)
176d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang{
177d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    unsigned char * Data;
178d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    char OutLine[101];
179d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    int OutLineChars;
180d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    int NonBlank;
181d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    unsigned a;
182d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    NonBlank = 0;
183d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    Data = XmpSection.Data;
184d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    OutLineChars = 0;
185d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
186d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
187d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    for (a=0;a<XmpSection.Size;a++){
188d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        if (Data[a] >= 32 && Data[a] < 128){
189d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            OutLine[OutLineChars++] = Data[a];
190d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            if (Data[a] != ' ') NonBlank |= 1;
191d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        }else{
192d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            if (Data[a] != '\n'){
193d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                OutLine[OutLineChars++] = '?';
194d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            }
195d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        }
196d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        if (Data[a] == '\n' || OutLineChars >= 100){
197d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            OutLine[OutLineChars] = 0;
198d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            if (NonBlank){
199d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                puts(OutLine);
200d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            }
201d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            NonBlank = (NonBlank & 1) << 1;
202d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang            OutLineChars = 0;
203d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang        }
204d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang    }
205d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang}
206