KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jxl > read > biff > SSTRecord


1 /*********************************************************************
2 *
3 * Copyright (C) 2002 Andrew Khan
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ***************************************************************************/

19
20 package jxl.read.biff;
21
22 import common.Assert;
23
24 import jxl.WorkbookSettings;
25 import jxl.biff.IntegerHelper;
26 import jxl.biff.RecordData;
27 import jxl.biff.StringHelper;
28
29 /**
30  * Holds all the strings in the shared string table
31  */

32 class SSTRecord extends RecordData
33 {
34   /**
35    * The total number of strings in this table
36    */

37   private int totalStrings;
38   /**
39    * The number of unique strings
40    */

41   private int uniqueStrings;
42   /**
43    * The shared strings
44    */

45   private String JavaDoc[] strings;
46   /**
47    * The array of continuation breaks
48    */

49   private int[] continuationBreaks;
50
51   /**
52    * A holder for a byte array
53    */

54   private static class ByteArrayHolder
55   {
56     /**
57      * the byte holder
58      */

59     public byte[] bytes;
60   }
61
62   /**
63    * A holder for a boolean
64    */

65   private static class BooleanHolder
66   {
67     /**
68      * the holder holder
69      */

70     public boolean value;
71   }
72
73   /**
74    * Constructs this object from the raw data
75    *
76    * @param t the raw data
77    * @param continuations the continuations
78    * @param ws the workbook settings
79    */

80   public SSTRecord(Record t, Record[] continuations, WorkbookSettings ws)
81   {
82     super(t);
83
84     // If a continue record appears in the middle of
85
// a string, then the encoding character is repeated
86

87     // Concatenate everything into one big bugger of a byte array
88
int totalRecordLength = 0;
89
90     for (int i = 0; i < continuations.length; i++)
91     {
92       totalRecordLength += continuations[i].getLength();
93     }
94     totalRecordLength += getRecord().getLength();
95
96     byte[] data = new byte[totalRecordLength];
97
98     // First the original data gets put in
99
int pos = 0;
100     System.arraycopy(getRecord().getData(), 0,
101                      data, 0, getRecord().getLength());
102     pos += getRecord().getLength();
103
104     // Now copy in everything else.
105
continuationBreaks = new int[continuations.length];
106     Record r = null;
107     for (int i = 0; i < continuations.length; i++)
108     {
109       r = continuations[i];
110       System.arraycopy(r.getData(), 0,
111                        data, pos,
112                        r.getLength());
113       continuationBreaks[i] = pos;
114       pos += r.getLength();
115     }
116
117     totalStrings = IntegerHelper.getInt(data[0], data[1],
118                                         data[2], data[3]);
119     uniqueStrings = IntegerHelper.getInt(data[4], data[5],
120                                          data[6], data[7]);
121
122     strings = new String JavaDoc[uniqueStrings];
123     readStrings(data, 8, ws);
124   }
125
126   /**
127    * Reads in all the strings from the raw data
128    *
129    * @param data the raw data
130    * @param offset the offset
131    * @param ws the workbook settings
132    */

133   private void readStrings(byte[] data, int offset, WorkbookSettings ws)
134   {
135     int pos = offset;
136     int numChars;
137     byte optionFlags;
138     String JavaDoc s = null;
139     boolean asciiEncoding = false;
140     boolean richString = false;
141     boolean extendedString = false;
142     int formattingRuns = 0;
143     int extendedRunLength = 0;
144
145     for (int i = 0; i < uniqueStrings; i++)
146     {
147       // Read in the number of characters
148
numChars = IntegerHelper.getInt(data[pos], data[pos + 1]);
149       pos += 2;
150       optionFlags = data[pos];
151       pos++;
152
153       // See if it is an extended string
154
extendedString = ((optionFlags & 0x04) != 0);
155
156       // See if string contains formatting information
157
richString = ((optionFlags & 0x08) != 0);
158
159       if (richString)
160       {
161         // Read in the crun
162
formattingRuns = IntegerHelper.getInt(data[pos], data[pos + 1]);
163         pos += 2;
164       }
165
166       if (extendedString)
167       {
168         // Read in cchExtRst
169
extendedRunLength = IntegerHelper.getInt
170           (data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
171         pos += 4;
172       }
173
174       // See if string is ASCII (compressed) or unicode
175
asciiEncoding = ((optionFlags & 0x01) == 0);
176
177       ByteArrayHolder bah = new ByteArrayHolder();
178       BooleanHolder bh = new BooleanHolder();
179       bh.value = asciiEncoding;
180       pos += getChars(data, bah, pos, bh, numChars);
181       asciiEncoding = bh.value;
182
183       if (asciiEncoding)
184       {
185         s = StringHelper.getString(bah.bytes, numChars, 0, ws);
186       }
187       else
188       {
189         s = StringHelper.getUnicodeString(bah.bytes, numChars, 0);
190       }
191
192       strings[i] = s;
193
194       // For rich strings, skip over the formatting runs
195
if (richString)
196       {
197         pos += 4 * formattingRuns;
198       }
199
200       // For extended strings, skip over the extended string data
201
if (extendedString)
202       {
203         pos += extendedRunLength;
204       }
205
206       if (pos > data.length)
207       {
208         Assert.verify(false, "pos exceeds record length");
209       }
210     }
211   }
212
213   /**
214    * Gets the chars in the ascii array, taking into account continuation
215    * breaks
216    *
217    * @param source the original source
218    * @param bah holder for the new byte array
219    * @param pos the current position in the source
220    * @param ascii holder for a return ascii flag
221    * @param numChars the number of chars in the string
222    * @return the number of bytes read from the source
223    */

224   private int getChars(byte[] source,
225                        ByteArrayHolder bah,
226                        int pos,
227                        BooleanHolder ascii,
228                        int numChars)
229   {
230     int i = 0;
231     boolean spansBreak = false;
232
233     if (ascii.value)
234     {
235       bah.bytes = new byte[numChars];
236     }
237     else
238     {
239       bah.bytes = new byte[numChars * 2];
240     }
241
242     while (i < continuationBreaks.length && !spansBreak)
243     {
244       spansBreak = pos <= continuationBreaks[i] &&
245                    (pos + bah.bytes.length > continuationBreaks[i]);
246
247       if (!spansBreak)
248       {
249         i++;
250       }
251     }
252
253     // If it doesn't span a break simply do an array copy into the
254
// destination array and finish
255
if (!spansBreak)
256     {
257       System.arraycopy(source, pos, bah.bytes, 0, bah.bytes.length);
258       return bah.bytes.length;
259     }
260
261     // Copy the portion before the break pos into the array
262
int breakpos = continuationBreaks[i];
263     System.arraycopy(source, pos, bah.bytes, 0, breakpos - pos);
264
265     int bytesRead = breakpos - pos;
266     int charsRead;
267     if (ascii.value)
268     {
269       charsRead = bytesRead;
270     }
271     else
272     {
273       charsRead = bytesRead / 2;
274     }
275
276     bytesRead += getContinuedString(source,
277                                     bah,
278                                     bytesRead,
279                                     i,
280                                     ascii,
281                                     numChars - charsRead);
282     return bytesRead;
283   }
284
285   /**
286    * Gets the rest of the string after a continuation break
287    *
288    * @param source the original bytes
289    * @param bah the holder for the new bytes
290    * @param destPos the des pos
291    * @param contBreakIndex the index of the continuation break
292    * @param ascii the ascii flag holder
293    * @param charsLeft the number of chars left in the array
294    * @return the number of bytes read in the continued string
295    */

296   private int getContinuedString(byte[] source,
297                                  ByteArrayHolder bah,
298                                  int destPos,
299                                  int contBreakIndex,
300                                  BooleanHolder ascii,
301                                  int charsLeft)
302   {
303     int breakpos = continuationBreaks[contBreakIndex];
304     int bytesRead = 0;
305
306     while (charsLeft > 0)
307     {
308       Assert.verify(contBreakIndex < continuationBreaks.length,
309                     "continuation break index");
310
311       if (ascii.value && source[breakpos] == 0)
312       {
313         // The string is consistently ascii throughout
314

315         int length = contBreakIndex == continuationBreaks.length - 1 ?
316           charsLeft :
317           Math.min
318             (charsLeft,
319              continuationBreaks[contBreakIndex + 1] - breakpos - 1);
320
321         System.arraycopy(source,
322                          breakpos + 1,
323                          bah.bytes,
324                          destPos,
325                          length);
326         destPos += length;
327         bytesRead += length + 1;
328         charsLeft -= length;
329         ascii.value = true;
330       }
331       else if (!ascii.value && source[breakpos] != 0)
332       {
333         // The string is Unicode throughout
334

335         int length = contBreakIndex == continuationBreaks.length - 1 ?
336           charsLeft * 2 :
337           Math.min
338             (charsLeft * 2,
339              continuationBreaks[contBreakIndex + 1] - breakpos - 1);
340
341         // It looks like the string continues as Unicode too. That's handy
342
System.arraycopy(source,
343                          breakpos + 1,
344                          bah.bytes,
345                          destPos,
346                          length);
347
348         destPos += length;
349         bytesRead += length + 1;
350         charsLeft -= length / 2;
351         ascii.value = false;
352       }
353       else if (!ascii.value && source[breakpos] == 0)
354       {
355         // Bummer - the string starts off as Unicode, but after the
356
// continuation it is in straightforward ASCII encoding
357
int chars = contBreakIndex == continuationBreaks.length - 1 ?
358           charsLeft:
359           Math.min
360             (charsLeft,
361              continuationBreaks[contBreakIndex + 1] - breakpos - 1);
362
363         for (int j = 0; j < chars; j++)
364         {
365           bah.bytes[destPos] = source[breakpos + j + 1];
366           destPos += 2;
367         }
368
369         bytesRead += chars + 1;
370         charsLeft -= chars;
371         ascii.value = false;
372       }
373       else
374       {
375         // Double Bummer - the string starts off as ASCII, but after the
376
// continuation it is in Unicode. This impacts the allocated array
377

378         // Reallocate what we have of the byte array so that it is all
379
// Unicode
380
byte[] oldBytes = bah.bytes;
381         bah.bytes = new byte[destPos * 2 + charsLeft * 2];
382         for (int j = 0; j < destPos; j++)
383         {
384           bah.bytes[j * 2] = oldBytes[j];
385         }
386
387         destPos = destPos * 2;
388
389         int length = contBreakIndex == continuationBreaks.length - 1 ?
390           charsLeft * 2 :
391           Math.min
392             (charsLeft * 2,
393              continuationBreaks[contBreakIndex + 1] - breakpos - 1);
394
395         System.arraycopy(source,
396                          breakpos + 1,
397                          bah.bytes,
398                          destPos,
399                          length);
400
401         destPos += length;
402         bytesRead += length + 1;
403         charsLeft -= length / 2;
404         ascii.value = false;
405       }
406
407       contBreakIndex++;
408
409       if (contBreakIndex < continuationBreaks.length)
410       {
411         breakpos = continuationBreaks[contBreakIndex];
412       }
413     }
414
415     return bytesRead;
416   }
417
418   /**
419    * Gets the string at the specified position
420    *
421    * @param index the index of the string to return
422    * @return the strings
423    */

424   public String JavaDoc getString(int index)
425   {
426     Assert.verify(index < uniqueStrings);
427     return strings[index];
428   }
429 }
430
431
432
Popular Tags