]>
git.saurik.com Git - android/aapt.git/blob - StringPool.cpp
2 // Copyright 2006 The Android Open Source Project
4 // Build resource files from raw assets.
7 #include "StringPool.h"
9 #include <utils/ByteOrder.h>
13 # define ZD_TYPE ssize_t
21 void strcpy16_htod(uint16_t* dst
, const uint16_t* src
)
24 char16_t s
= htods(*src
);
31 void printStringPool(const ResStringPool
* pool
)
33 const size_t NS
= pool
->size();
34 for (size_t s
=0; s
<NS
; s
++) {
36 const char *str
= (const char*)pool
->string8At(s
, &len
);
38 str
= String8(pool
->stringAt(s
, &len
)).string();
41 printf("String #" ZD
": %s\n", (ZD_TYPE
) s
, str
);
45 StringPool::StringPool(bool sorted
, bool utf8
)
46 : mSorted(sorted
), mUTF8(utf8
), mValues(-1), mIdents(-1)
50 ssize_t
StringPool::add(const String16
& value
, bool mergeDuplicates
)
52 return add(String16(), value
, mergeDuplicates
);
55 ssize_t
StringPool::add(const String16
& value
, const Vector
<entry_style_span
>& spans
)
57 ssize_t res
= add(String16(), value
, false);
59 addStyleSpans(res
, spans
);
64 ssize_t
StringPool::add(const String16
& ident
, const String16
& value
,
67 if (ident
.size() > 0) {
68 ssize_t idx
= mIdents
.valueFor(ident
);
70 fprintf(stderr
, "ERROR: Duplicate string identifier %s\n",
71 String8(mEntries
[idx
].value
).string());
76 ssize_t vidx
= mValues
.indexOfKey(value
);
77 ssize_t pos
= vidx
>= 0 ? mValues
.valueAt(vidx
) : -1;
78 ssize_t eidx
= pos
>= 0 ? mEntryArray
.itemAt(pos
) : -1;
80 eidx
= mEntries
.add(entry(value
));
82 fprintf(stderr
, "Failure adding string %s\n", String8(value
).string());
87 const bool first
= vidx
< 0;
88 if (first
|| !mergeDuplicates
) {
89 pos
= mEntryArray
.add(eidx
);
91 vidx
= mValues
.add(value
, pos
);
92 const size_t N
= mEntryArrayToValues
.size();
93 for (size_t i
=0; i
<N
; i
++) {
94 size_t& e
= mEntryArrayToValues
.editItemAt(i
);
95 if ((ssize_t
)e
>= vidx
) {
100 mEntryArrayToValues
.add(vidx
);
102 entry
& ent
= mEntries
.editItemAt(eidx
);
103 ent
.indices
.add(pos
);
107 if (ident
.size() > 0) {
108 mIdents
.add(ident
, vidx
);
111 NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n",
112 String8(value
).string(), pos
, eidx
, vidx
));
117 status_t
StringPool::addStyleSpan(size_t idx
, const String16
& name
,
118 uint32_t start
, uint32_t end
)
120 entry_style_span span
;
122 span
.span
.firstChar
= start
;
123 span
.span
.lastChar
= end
;
124 return addStyleSpan(idx
, span
);
127 status_t
StringPool::addStyleSpans(size_t idx
, const Vector
<entry_style_span
>& spans
)
129 const size_t N
=spans
.size();
130 for (size_t i
=0; i
<N
; i
++) {
131 status_t err
= addStyleSpan(idx
, spans
[i
]);
132 if (err
!= NO_ERROR
) {
139 status_t
StringPool::addStyleSpan(size_t idx
, const entry_style_span
& span
)
141 LOG_ALWAYS_FATAL_IF(mSorted
, "Can't use styles with sorted string pools.");
143 // Place blank entries in the span array up to this index.
144 while (mEntryStyleArray
.size() <= idx
) {
145 mEntryStyleArray
.add();
148 entry_style
& style
= mEntryStyleArray
.editItemAt(idx
);
149 style
.spans
.add(span
);
153 size_t StringPool::size() const
155 return mSorted
? mValues
.size() : mEntryArray
.size();
158 const StringPool::entry
& StringPool::entryAt(size_t idx
) const
161 return mEntries
[mEntryArray
[idx
]];
163 return mEntries
[mEntryArray
[mValues
.valueAt(idx
)]];
167 size_t StringPool::countIdentifiers() const
169 return mIdents
.size();
172 sp
<AaptFile
> StringPool::createStringBlock()
174 sp
<AaptFile
> pool
= new AaptFile(String8(), AaptGroupEntry(),
176 status_t err
= writeStringBlock(pool
);
177 return err
== NO_ERROR
? pool
: NULL
;
180 #define ENCODE_LENGTH(str, chrsz, strSize) \
182 size_t maxMask = 1 << ((chrsz*8)-1); \
183 size_t maxSize = maxMask-1; \
184 if (strSize > maxSize) { \
185 *str++ = maxMask | ((strSize>>(chrsz*8))&maxSize); \
190 status_t
StringPool::writeStringBlock(const sp
<AaptFile
>& pool
)
192 // Allow appending. Sorry this is a little wacky.
193 if (pool
->getSize() > 0) {
194 sp
<AaptFile
> block
= createStringBlock();
196 return UNKNOWN_ERROR
;
198 ssize_t res
= pool
->writeData(block
->getData(), block
->getSize());
199 return (res
>= 0) ? (status_t
)NO_ERROR
: res
;
202 // First we need to add all style span names to the string pool.
203 // We do this now (instead of when the span is added) so that these
204 // will appear at the end of the pool, not disrupting the order
205 // our client placed their own strings in it.
207 const size_t STYLES
= mEntryStyleArray
.size();
210 for (i
=0; i
<STYLES
; i
++) {
211 entry_style
& style
= mEntryStyleArray
.editItemAt(i
);
212 const size_t N
= style
.spans
.size();
213 for (size_t i
=0; i
<N
; i
++) {
214 entry_style_span
& span
= style
.spans
.editItemAt(i
);
215 ssize_t idx
= add(span
.name
, true);
217 fprintf(stderr
, "Error adding span for style tag '%s'\n",
218 String8(span
.name
).string());
221 span
.span
.name
.index
= (uint32_t)idx
;
225 const size_t ENTRIES
= size();
227 // Now build the pool of unique strings.
229 const size_t STRINGS
= mEntries
.size();
230 const size_t preSize
= sizeof(ResStringPool_header
)
231 + (sizeof(uint32_t)*ENTRIES
)
232 + (sizeof(uint32_t)*STYLES
);
233 if (pool
->editData(preSize
) == NULL
) {
234 fprintf(stderr
, "ERROR: Out of memory for string pool\n");
238 const size_t charSize
= mUTF8
? sizeof(uint8_t) : sizeof(char16_t);
241 for (i
=0; i
<STRINGS
; i
++) {
242 entry
& ent
= mEntries
.editItemAt(i
);
243 const size_t strSize
= (ent
.value
.size());
244 const size_t lenSize
= strSize
> (size_t)(1<<((charSize
*8)-1))-1 ?
245 charSize
*2 : charSize
;
249 encStr
= String8(ent
.value
);
252 const size_t encSize
= mUTF8
? encStr
.size() : 0;
253 const size_t encLenSize
= mUTF8
?
254 (encSize
> (size_t)(1<<((charSize
*8)-1))-1 ?
255 charSize
*2 : charSize
) : 0;
259 const size_t totalSize
= lenSize
+ encLenSize
+
260 ((mUTF8
? encSize
: strSize
)+1)*charSize
;
262 void* dat
= (void*)pool
->editData(preSize
+ strPos
+ totalSize
);
264 fprintf(stderr
, "ERROR: Out of memory for string pool\n");
267 dat
= (uint8_t*)dat
+ preSize
+ strPos
;
269 uint8_t* strings
= (uint8_t*)dat
;
271 ENCODE_LENGTH(strings
, sizeof(uint8_t), strSize
)
273 ENCODE_LENGTH(strings
, sizeof(uint8_t), encSize
)
275 strncpy((char*)strings
, encStr
, encSize
+1);
277 uint16_t* strings
= (uint16_t*)dat
;
279 ENCODE_LENGTH(strings
, sizeof(uint16_t), strSize
)
281 strcpy16_htod(strings
, ent
.value
);
287 // Pad ending string position up to a uint32_t boundary.
290 size_t padPos
= ((strPos
+3)&~0x3);
291 uint8_t* dat
= (uint8_t*)pool
->editData(preSize
+ padPos
);
293 fprintf(stderr
, "ERROR: Out of memory padding string pool\n");
296 memset(dat
+preSize
+strPos
, 0, padPos
-strPos
);
300 // Build the pool of style spans.
302 size_t styPos
= strPos
;
303 for (i
=0; i
<STYLES
; i
++) {
304 entry_style
& ent
= mEntryStyleArray
.editItemAt(i
);
305 const size_t N
= ent
.spans
.size();
306 const size_t totalSize
= (N
*sizeof(ResStringPool_span
))
307 + sizeof(ResStringPool_ref
);
309 ent
.offset
= styPos
-strPos
;
310 uint8_t* dat
= (uint8_t*)pool
->editData(preSize
+ styPos
+ totalSize
);
312 fprintf(stderr
, "ERROR: Out of memory for string styles\n");
315 ResStringPool_span
* span
= (ResStringPool_span
*)(dat
+preSize
+styPos
);
316 for (size_t i
=0; i
<N
; i
++) {
317 span
->name
.index
= htodl(ent
.spans
[i
].span
.name
.index
);
318 span
->firstChar
= htodl(ent
.spans
[i
].span
.firstChar
);
319 span
->lastChar
= htodl(ent
.spans
[i
].span
.lastChar
);
322 span
->name
.index
= htodl(ResStringPool_span::END
);
328 // Add full terminator at the end (when reading we validate that
329 // the end of the pool is fully terminated to simplify error
331 size_t extra
= sizeof(ResStringPool_span
)-sizeof(ResStringPool_ref
);
332 uint8_t* dat
= (uint8_t*)pool
->editData(preSize
+ styPos
+ extra
);
334 fprintf(stderr
, "ERROR: Out of memory for string styles\n");
337 uint32_t* p
= (uint32_t*)(dat
+preSize
+styPos
);
339 *p
++ = htodl(ResStringPool_span::END
);
340 extra
-= sizeof(uint32_t);
347 ResStringPool_header
* header
=
348 (ResStringPool_header
*)pool
->padData(sizeof(uint32_t));
349 if (header
== NULL
) {
350 fprintf(stderr
, "ERROR: Out of memory for string pool\n");
353 memset(header
, 0, sizeof(*header
));
354 header
->header
.type
= htods(RES_STRING_POOL_TYPE
);
355 header
->header
.headerSize
= htods(sizeof(*header
));
356 header
->header
.size
= htodl(pool
->getSize());
357 header
->stringCount
= htodl(ENTRIES
);
358 header
->styleCount
= htodl(STYLES
);
360 header
->flags
|= htodl(ResStringPool_header::SORTED_FLAG
);
363 header
->flags
|= htodl(ResStringPool_header::UTF8_FLAG
);
365 header
->stringsStart
= htodl(preSize
);
366 header
->stylesStart
= htodl(STYLES
> 0 ? (preSize
+strPos
) : 0);
368 // Write string index array.
370 uint32_t* index
= (uint32_t*)(header
+1);
372 for (i
=0; i
<ENTRIES
; i
++) {
373 entry
& ent
= const_cast<entry
&>(entryAt(i
));
376 *index
++ = htodl(ent
.offset
);
379 for (i
=0; i
<ENTRIES
; i
++) {
380 entry
& ent
= mEntries
.editItemAt(mEntryArray
[i
]);
381 *index
++ = htodl(ent
.offset
);
382 NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i
,
383 String8(ent
.value
).string(),
384 mEntryArray
[i
], ent
.offset
));
388 // Write style index array.
391 for (i
=0; i
<STYLES
; i
++) {
392 LOG_ALWAYS_FATAL("Shouldn't be here!");
395 for (i
=0; i
<STYLES
; i
++) {
396 *index
++ = htodl(mEntryStyleArray
[i
].offset
);
403 ssize_t
StringPool::offsetForString(const String16
& val
) const
405 const Vector
<size_t>* indices
= offsetsForString(val
);
406 ssize_t res
= indices
!= NULL
&& indices
->size() > 0 ? indices
->itemAt(0) : -1;
407 NOISY(printf("Offset for string %s: %d (%s)\n", String8(val
).string(), res
,
408 res
>= 0 ? String8(mEntries
[mEntryArray
[res
]].value
).string() : String8()));
412 const Vector
<size_t>* StringPool::offsetsForString(const String16
& val
) const
414 ssize_t pos
= mValues
.valueFor(val
);
418 return &mEntries
[mEntryArray
[pos
]].indices
;