1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*******************************************************************************
3ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*   Copyright (C) 2000-2003, International Business Machines
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*   Corporation and others.  All Rights Reserved.
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*******************************************************************************
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru* File writejava.c
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru* Modification History:
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*   Date        Name        Description
14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*   01/11/02    Ram        Creation.
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*******************************************************************************
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*/
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "rle.h"
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * The ESCAPE character is used during run-length encoding.  It signals
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * a run of identical chars.
21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const uint16_t ESCAPE = 0xA5A5;
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * The ESCAPE_BYTE character is used during run-length encoding.  It signals
26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * a run of identical bytes.
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const uint8_t ESCAPE_BYTE = (uint8_t)0xA5;
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Append a byte to the given StringBuffer, packing two bytes into each
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * character.  The state parameter maintains intermediary data between
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * calls.
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param state A two-element array, with state[0] == 0 if this is the
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * first byte of a pair, or state[0] != 0 if this is the second byte
36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * of a pair, in which case state[1] is the first byte.
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic uint16_t*
39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruappendEncodedByte(uint16_t* buffer, uint16_t* buffLimit, uint8_t value, uint8_t state[],UErrorCode* status) {
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(!status || U_FAILURE(*status)){
41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (state[0] != 0) {
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        uint16_t c = (uint16_t) ((state[1] << 8) | (((int32_t) value) & 0xFF));
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if(buffer < buffLimit){
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            *buffer++ = c;
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }else{
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            *status = U_BUFFER_OVERFLOW_ERROR;
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        state[0] = 0;
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return buffer;
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    else {
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        state[0] = 1;
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        state[1] = value;
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return buffer;
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Encode a run, possibly a degenerate run (of < 4 values).
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param length The length of the run; must be > 0 && <= 0xFF.
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic uint16_t*
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruencodeRunByte(uint16_t* buffer,uint16_t* bufLimit, uint8_t value, int32_t length, uint8_t state[], UErrorCode* status) {
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(!status || U_FAILURE(*status)){
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (length < 4) {
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t j=0;
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (; j<length; ++j) {
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (value == ESCAPE_BYTE) {
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                buffer = appendEncodedByte(buffer,bufLimit, ESCAPE_BYTE, state,status);
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            buffer = appendEncodedByte(buffer,bufLimit, value, state, status);
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    else {
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (length == ESCAPE_BYTE) {
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (value == ESCAPE_BYTE){
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru               buffer =  appendEncodedByte(buffer, bufLimit,ESCAPE_BYTE, state,status);
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            buffer = appendEncodedByte(buffer,bufLimit, value, state, status);
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            --length;
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        buffer = appendEncodedByte(buffer,bufLimit, ESCAPE_BYTE, state,status);
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        buffer = appendEncodedByte(buffer,bufLimit, (char)length, state, status);
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        buffer = appendEncodedByte(buffer,bufLimit, value, state, status); /* Don't need to escape this value*/
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return buffer;
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define APPEND( buffer, bufLimit, value, num, status){  \
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(buffer<bufLimit){                    \
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *buffer++=(value);                  \
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }else{                                  \
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *status = U_BUFFER_OVERFLOW_ERROR;  \
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }                                       \
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    num++;                                  \
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Encode a run, possibly a degenerate run (of < 4 values).
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param length The length of the run; must be > 0 && <= 0xFFFF.
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic uint16_t*
106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruencodeRunShort(uint16_t* buffer,uint16_t* bufLimit, uint16_t value, int32_t length,UErrorCode* status) {
107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t num=0;
108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (length < 4) {
109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int j=0;
110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (; j<length; ++j) {
111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (value == (int32_t) ESCAPE){
112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                APPEND(buffer,bufLimit,ESCAPE, num, status);
113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            APPEND(buffer,bufLimit,value,num, status);
116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    else {
119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (length == (int32_t) ESCAPE) {
120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (value == (int32_t) ESCAPE){
121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                APPEND(buffer,bufLimit,ESCAPE,num,status);
122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            APPEND(buffer,bufLimit,value,num,status);
125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            --length;
126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        APPEND(buffer,bufLimit,ESCAPE,num,status);
128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        APPEND(buffer,bufLimit,(uint16_t) length, num,status);
129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        APPEND(buffer,bufLimit,(uint16_t)value, num, status); /* Don't need to escape this value */
130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return buffer;
132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Construct a string representing a char array.  Use run-length encoding.
136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * A character represents itself, unless it is the ESCAPE character.  Then
137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * the following notations are possible:
138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *   ESCAPE ESCAPE   ESCAPE literal
139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *   ESCAPE n c      n instances of character c
140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Since an encoded run occupies 3 characters, we only encode runs of 4 or
141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * more characters.  Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF.
142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * If we encounter a run where n == ESCAPE, we represent this as:
143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *   c ESCAPE n-1 c
144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * The ESCAPE value is chosen so as not to collide with commonly
145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * seen values.
146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t
148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruusArrayToRLEString(const uint16_t* src,int32_t srcLen,uint16_t* buffer, int32_t bufLen,UErrorCode* status) {
149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    uint16_t* bufLimit =  buffer+bufLen;
150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    uint16_t* saveBuffer = buffer;
151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(buffer < bufLimit){
152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *buffer++ =  (uint16_t)(srcLen>>16);
153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if(buffer<bufLimit){
154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            uint16_t runValue = src[0];
155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t runLength = 1;
156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int i=1;
157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            *buffer++ = (uint16_t) srcLen;
158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            for (; i<srcLen; ++i) {
160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                uint16_t s = src[i];
161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (s == runValue && runLength < 0xFFFF){
162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    ++runLength;
163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }else {
164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    buffer = encodeRunShort(buffer,bufLimit, (uint16_t)runValue, runLength,status);
165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    runValue = s;
166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    runLength = 1;
167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            buffer= encodeRunShort(buffer,bufLimit,(uint16_t)runValue, runLength,status);
170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }else{
171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            *status = U_BUFFER_OVERFLOW_ERROR;
172ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }else{
174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *status = U_BUFFER_OVERFLOW_ERROR;
175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return (int32_t)(buffer - saveBuffer);
177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Construct a string representing a byte array.  Use run-length encoding.
181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Two bytes are packed into a single char, with a single extra zero byte at
182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * the end if needed.  A byte represents itself, unless it is the
183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * ESCAPE_BYTE.  Then the following notations are possible:
184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *   ESCAPE_BYTE ESCAPE_BYTE   ESCAPE_BYTE literal
185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *   ESCAPE_BYTE n b           n instances of byte b
186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Since an encoded run occupies 3 bytes, we only encode runs of 4 or
187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * more bytes.  Thus we have n > 0 and n != ESCAPE_BYTE and n <= 0xFF.
188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * If we encounter a run where n == ESCAPE_BYTE, we represent this as:
189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *   b ESCAPE_BYTE n-1 b
190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * The ESCAPE_BYTE value is chosen so as not to collide with commonly
191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * seen values.
192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t
194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerubyteArrayToRLEString(const uint8_t* src,int32_t srcLen, uint16_t* buffer,int32_t bufLen, UErrorCode* status) {
195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    const uint16_t* saveBuf = buffer;
196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    uint16_t* bufLimit =  buffer+bufLen;
197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(buffer < bufLimit){
198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *buffer++ = ((uint16_t) (srcLen >> 16));
199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if(buffer<bufLimit){
201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            uint8_t runValue = src[0];
202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int runLength = 1;
203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            uint8_t state[2]= {0};
204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int i=1;
205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            *buffer++=((uint16_t) srcLen);
206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            for (; i<srcLen; ++i) {
207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                uint8_t b = src[i];
208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (b == runValue && runLength < 0xFF){
209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    ++runLength;
210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                else {
212ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    buffer = encodeRunByte(buffer, bufLimit,runValue, runLength, state,status);
213ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    runValue = b;
214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    runLength = 1;
215ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
216ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            buffer = encodeRunByte(buffer,bufLimit, runValue, runLength, state, status);
218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            /* We must save the final byte, if there is one, by padding
220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru             * an extra zero.
221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru             */
222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (state[0] != 0) {
223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                buffer = appendEncodedByte(buffer,bufLimit, 0, state ,status);
224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }else{
226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            *status = U_BUFFER_OVERFLOW_ERROR;
227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
228ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }else{
229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *status = U_BUFFER_OVERFLOW_ERROR;
230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return (int32_t) (buffer - saveBuf);
232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Construct an array of shorts from a run-length encoded string.
237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t
239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerurleStringToUCharArray(uint16_t* src, int32_t srcLen, uint16_t* target, int32_t tgtLen, UErrorCode* status) {
240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t length = 0;
241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t ai = 0;
242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int i=2;
243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(!status || U_FAILURE(*status)){
245ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
246ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    /* the source is null terminated */
248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(srcLen == -1){
249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        srcLen = u_strlen(src);
250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
251ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(srcLen <= 2){
252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 2;
253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    length = (((int32_t) src[0]) << 16) | ((int32_t) src[1]);
255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(target == NULL){
257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return length;
258ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(tgtLen < length){
260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *status = U_BUFFER_OVERFLOW_ERROR;
261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return length;
262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
264ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (; i<srcLen; ++i) {
265ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        uint16_t c = src[i];
266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (c == ESCAPE) {
267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            c = src[++i];
268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (c == ESCAPE) {
269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                target[ai++] = c;
270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t runLength = (int32_t) c;
272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                uint16_t runValue = src[++i];
273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int j=0;
274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                for (; j<runLength; ++j) {
275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    target[ai++] = runValue;
276ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
277ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
278ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
279ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        else {
280ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            target[ai++] = c;
281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
282ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
283ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
284ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (ai != length){
285ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *status = U_INTERNAL_PROGRAM_ERROR;
286ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
287ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return length;
289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Construct an array of bytes from a run-length encoded string.
293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t
295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerurleStringToByteArray(uint16_t* src, int32_t srcLen, uint8_t* target, int32_t tgtLen, UErrorCode* status) {
296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t length = 0;
298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool nextChar = TRUE;
299ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    uint16_t c = 0;
300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t node = 0;
301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t runLength = 0;
302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t i = 2;
303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t ai=0;
304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(!status || U_FAILURE(*status)){
306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
308ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    /* the source is null terminated */
309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(srcLen == -1){
310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        srcLen = u_strlen(src);
311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(srcLen <= 2){
313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 2;
314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    length = (((int32_t) src[0]) << 16) | ((int32_t) src[1]);
316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(target == NULL){
318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return length;
319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if(tgtLen < length){
321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *status = U_BUFFER_OVERFLOW_ERROR;
322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return length;
323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (; ai<tgtLen; ) {
326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru       /* This part of the loop places the next byte into the local
327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        * variable 'b' each time through the loop.  It keeps the
328ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        * current character in 'c' and uses the boolean 'nextChar'
329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        * to see if we've taken both bytes out of 'c' yet.
330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        */
331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        uint8_t b;
332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (nextChar) {
333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            c = src[i++];
334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            b = (uint8_t) (c >> 8);
335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            nextChar = FALSE;
336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        else {
338ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            b = (uint8_t) (c & 0xFF);
339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            nextChar = TRUE;
340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru       /* This part of the loop is a tiny state machine which handles
343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        * the parsing of the run-length encoding.  This would be simpler
344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        * if we could look ahead, but we can't, so we use 'node' to
345ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        * move between three nodes in the state machine.
346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        */
347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        switch (node) {
348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case 0:
349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            /* Normal idle node */
350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (b == ESCAPE_BYTE) {
351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                node = 1;
352ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            else {
354ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                target[ai++] = b;
355ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
356ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
357ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case 1:
358ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru           /* We have seen one ESCAPE_BYTE; we expect either a second
359ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            * one, or a run length and value.
360ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            */
361ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (b == ESCAPE_BYTE) {
362ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                target[ai++] = ESCAPE_BYTE;
363ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                node = 0;
364ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
365ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            else {
366ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                runLength = b;
367ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                node = 2;
368ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
369ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
370ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case 2:
371ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            {
372ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int j=0;
373ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru               /* We have seen an ESCAPE_BYTE and length byte.  We interpret
374ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                * the next byte as the value to be repeated.
375ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                */
376ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                for (; j<runLength; ++j){
377ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if(ai<tgtLen){
378ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        target[ai++] = b;
379ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }else{
380ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        *status = U_BUFFER_OVERFLOW_ERROR;
381ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        return ai;
382ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
383ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
384ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                node = 0;
385ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
386ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
387ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
388ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
389ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
390ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (node != 0){
391ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *status = U_INTERNAL_PROGRAM_ERROR;
392ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        /*("Bad run-length encoded byte array")*/
393ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
394ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
395ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
396ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
397ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (i != srcLen){
398ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        /*("Excess data in RLE byte array string");*/
399ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        *status = U_INTERNAL_PROGRAM_ERROR;
400ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return ai;
401ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
402ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
403ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return ai;
404ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
405ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
406