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