status_t StringPool::writeStringBlock(const sp<AaptFile>& pool) { // Allow appending. Sorry this is a little wacky. if (pool->getSize() > 0) { sp<AaptFile> block = createStringBlock(); if (block == NULL) { return UNKNOWN_ERROR; } ssize_t res = pool->writeData(block->getData(), block->getSize()); return (res >= 0) ? (status_t)NO_ERROR : res; } // First we need to add all style span names to the string pool. // We do this now (instead of when the span is added) so that these // will appear at the end of the pool, not disrupting the order // our client placed their own strings in it. const size_t STYLES = mEntryStyleArray.size(); size_t i; for (i=0; i<STYLES; i++) { entry_style& style = mEntryStyleArray.editItemAt(i); const size_t N = style.spans.size(); for (size_t i=0; i<N; i++) { entry_style_span& span = style.spans.editItemAt(i); ssize_t idx = add(span.name, true); if (idx < 0) { fprintf(stderr, "Error adding span for style tag '%s'\n", String8(span.name).string()); return idx; } span.span.name.index = (uint32_t)idx; } } const size_t ENTRIES = mEntryArray.size(); // Now build the pool of unique strings. const size_t STRINGS = mEntries.size(); const size_t preSize = sizeof(ResStringPool_header) + (sizeof(uint32_t)*ENTRIES) + (sizeof(uint32_t)*STYLES); if (pool->editData(preSize) == NULL) { fprintf(stderr, "ERROR: Out of memory for string pool\n"); return NO_MEMORY; } const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(uint16_t); size_t strPos = 0; for (i=0; i<STRINGS; i++) { entry& ent = mEntries.editItemAt(i); const size_t strSize = (ent.value.size()); const size_t lenSize = strSize > (size_t)(1<<((charSize*8)-1))-1 ? charSize*2 : charSize; String8 encStr; if (mUTF8) { encStr = String8(ent.value); } const size_t encSize = mUTF8 ? encStr.size() : 0; const size_t encLenSize = mUTF8 ? (encSize > (size_t)(1<<((charSize*8)-1))-1 ? charSize*2 : charSize) : 0; ent.offset = strPos; const size_t totalSize = lenSize + encLenSize + ((mUTF8 ? encSize : strSize)+1)*charSize; void* dat = (void*)pool->editData(preSize + strPos + totalSize); if (dat == NULL) { fprintf(stderr, "ERROR: Out of memory for string pool\n"); return NO_MEMORY; } dat = (uint8_t*)dat + preSize + strPos; if (mUTF8) { uint8_t* strings = (uint8_t*)dat; ENCODE_LENGTH(strings, sizeof(uint8_t), strSize) ENCODE_LENGTH(strings, sizeof(uint8_t), encSize) strncpy((char*)strings, encStr, encSize+1); } else { uint16_t* strings = (uint16_t*)dat; ENCODE_LENGTH(strings, sizeof(uint16_t), strSize) strcpy16_htod(strings, ent.value); } strPos += totalSize; } // Pad ending string position up to a uint32_t boundary. if (strPos&0x3) { size_t padPos = ((strPos+3)&~0x3); uint8_t* dat = (uint8_t*)pool->editData(preSize + padPos); if (dat == NULL) { fprintf(stderr, "ERROR: Out of memory padding string pool\n"); return NO_MEMORY; } memset(dat+preSize+strPos, 0, padPos-strPos); strPos = padPos; } // Build the pool of style spans. size_t styPos = strPos; for (i=0; i<STYLES; i++) { entry_style& ent = mEntryStyleArray.editItemAt(i); const size_t N = ent.spans.size(); const size_t totalSize = (N*sizeof(ResStringPool_span)) + sizeof(ResStringPool_ref); ent.offset = styPos-strPos; uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + totalSize); if (dat == NULL) { fprintf(stderr, "ERROR: Out of memory for string styles\n"); return NO_MEMORY; } ResStringPool_span* span = (ResStringPool_span*)(dat+preSize+styPos); for (size_t i=0; i<N; i++) { span->name.index = htodl(ent.spans[i].span.name.index); span->firstChar = htodl(ent.spans[i].span.firstChar); span->lastChar = htodl(ent.spans[i].span.lastChar); span++; } span->name.index = htodl(ResStringPool_span::END); styPos += totalSize; } if (STYLES > 0) { // Add full terminator at the end (when reading we validate that // the end of the pool is fully terminated to simplify error // checking). size_t extra = sizeof(ResStringPool_span)-sizeof(ResStringPool_ref); uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + extra); if (dat == NULL) { fprintf(stderr, "ERROR: Out of memory for string styles\n"); return NO_MEMORY; } uint32_t* p = (uint32_t*)(dat+preSize+styPos); while (extra > 0) { *p++ = htodl(ResStringPool_span::END); extra -= sizeof(uint32_t); } styPos += extra; } // Write header. ResStringPool_header* header = (ResStringPool_header*)pool->padData(sizeof(uint32_t)); if (header == NULL) { fprintf(stderr, "ERROR: Out of memory for string pool\n"); return NO_MEMORY; } memset(header, 0, sizeof(*header)); header->header.type = htods(RES_STRING_POOL_TYPE); header->header.headerSize = htods(sizeof(*header)); header->header.size = htodl(pool->getSize()); header->stringCount = htodl(ENTRIES); header->styleCount = htodl(STYLES); if (mUTF8) { header->flags |= htodl(ResStringPool_header::UTF8_FLAG); } header->stringsStart = htodl(preSize); header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0); // Write string index array. uint32_t* index = (uint32_t*)(header+1); for (i=0; i<ENTRIES; i++) { entry& ent = mEntries.editItemAt(mEntryArray[i]); *index++ = htodl(ent.offset); NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i, String8(ent.value).string(), mEntryArray[i], ent.offset)); } // Write style index array. for (i=0; i<STYLES; i++) { *index++ = htodl(mEntryStyleArray[i].offset); } return NO_ERROR; }
status_t StringPool::writeStringBlock(const sp<AaptFile>& pool) { // Allow appending. Sorry this is a little wacky. if (pool->getSize() > 0) { sp<AaptFile> block = createStringBlock(); if (block == NULL) { return UNKNOWN_ERROR; } ssize_t res = pool->writeData(block->getData(), block->getSize()); return (res >= 0) ? (status_t)NO_ERROR : res; } // First we need to add all style span names to the string pool. // We do this now (instead of when the span is added) so that these // will appear at the end of the pool, not disrupting the order // our client placed their own strings in it. const size_t STYLES = mEntryStyleArray.size(); size_t i; for (i=0; i<STYLES; i++) { entry_style& style = mEntryStyleArray.editItemAt(i); const size_t N = style.spans.size(); for (size_t i=0; i<N; i++) { entry_style_span& span = style.spans.editItemAt(i); ssize_t idx = add(span.name, true); if (idx < 0) { fprintf(stderr, "Error adding span for style tag '%s'\n", String8(span.name).string()); return idx; } span.span.name.index = (uint32_t)idx; } } const size_t ENTRIES = size(); // Now build the pool of unique strings. const size_t STRINGS = mEntries.size(); const size_t preSize = sizeof(ResStringPool_header) + (sizeof(uint32_t)*ENTRIES) + (sizeof(uint32_t)*STYLES); if (pool->editData(preSize) == NULL) { fprintf(stderr, "ERROR: Out of memory for string pool\n"); return NO_MEMORY; } size_t strPos = 0; for (i=0; i<STRINGS; i++) { entry& ent = mEntries.editItemAt(i); const size_t strSize = (ent.value.size()); const size_t lenSize = strSize > 0x7fff ? sizeof(uint32_t) : sizeof(uint16_t); const size_t totalSize = lenSize + ((strSize+1)*sizeof(uint16_t)); ent.offset = strPos; uint16_t* dat = (uint16_t*)pool->editData(preSize + strPos + totalSize); if (dat == NULL) { fprintf(stderr, "ERROR: Out of memory for string pool\n"); return NO_MEMORY; } dat += (preSize+strPos)/sizeof(uint16_t); if (lenSize > sizeof(uint16_t)) { *dat = htods(0x8000 | ((strSize>>16)&0x7fff)); dat++; } *dat++ = htods(strSize); strcpy16_htod(dat, ent.value); strPos += lenSize + (strSize+1)*sizeof(uint16_t); }