void strcpy16_htod(uint16_t *dst, const char16_t *src) { while (*src) { uint16_t s = htods(static_cast<uint16_t>(*src)); *dst++ = s; src++; } *dst = 0; }
void strcpy16_htod(char16_t *dst, const char16_t *src) { while (*src) { char16_t s = htods(*src); *dst++ = s; src++; } *dst = 0; }
TEST(ResStringPool, AppendToEmptyTable) { const size_t header_size = sizeof(android::ResStringPool_header); android::ResStringPool_header header = { {htods(android::RES_STRING_POOL_TYPE), htods(header_size), htodl(header_size)}, 0, 0, htodl(android::ResStringPool_header::UTF8_FLAG | android::ResStringPool_header::SORTED_FLAG), 0, 0}; android::ResStringPool pool((void*)&header, header_size, false); pool.appendString(android::String8("Hello, world")); auto big_string = make_big_string(300); auto big_chars = big_string.c_str(); pool.appendString(android::String8(big_chars)); pool.appendString(android::String8("€666")); pool.appendString(android::String8("banana banana")); android::Vector<char> v; pool.serialize(v); auto data = (void*)v.array(); android::ResStringPool after(data, v.size(), false); // Ensure sort bit was cleared. auto flags = dtohl(((android::ResStringPool_header*)data)->flags); ASSERT_FALSE(flags & android::ResStringPool_header::SORTED_FLAG); size_t out_len; ASSERT_STREQ(after.string8At(0, &out_len), "Hello, world"); ASSERT_EQ(out_len, 12); ASSERT_STREQ(after.string8At(1, &out_len), big_chars); ASSERT_EQ(out_len, 300); ASSERT_STREQ(after.string8At(2, &out_len), "€666"); ASSERT_STREQ(after.string8At(3, &out_len), "banana banana"); }
void* ARSTREAM_Reader_RunAckThread (void *ARSTREAM_Reader_t_Param) { ARSTREAM_NetworkHeaders_AckPacket_t sendPacket = {0}; ARSTREAM_Reader_t *reader = (ARSTREAM_Reader_t *)ARSTREAM_Reader_t_Param; memset(&sendPacket, 0, sizeof(sendPacket)); ARSAL_PRINT (ARSAL_PRINT_DEBUG, ARSTREAM_READER_TAG, "Ack sender thread running"); reader->ackThreadStarted = 1; while (reader->threadsShouldStop == 0) { int isPeriodicAck = 0; ARSAL_Mutex_Lock (&(reader->ackSendMutex)); if (reader->maxAckInterval <= 0) { ARSAL_Cond_Wait (&(reader->ackSendCond), &(reader->ackSendMutex)); } else { int retval = ARSAL_Cond_Timedwait (&(reader->ackSendCond), &(reader->ackSendMutex), reader->maxAckInterval); if (retval == -1 && errno == ETIMEDOUT) { isPeriodicAck = 1; } } ARSAL_Mutex_Unlock (&(reader->ackSendMutex)); /* Only send an ACK if the maxAckInterval value allows it. */ if ((reader->maxAckInterval > 0) || ((reader->maxAckInterval == 0) && (isPeriodicAck == 0))) { ARSAL_Mutex_Lock (&(reader->ackPacketMutex)); sendPacket.frameNumber = htods (reader->ackPacket.frameNumber); sendPacket.highPacketsAck = htodll (reader->ackPacket.highPacketsAck); sendPacket.lowPacketsAck = htodll (reader->ackPacket.lowPacketsAck); ARSAL_Mutex_Unlock (&(reader->ackPacketMutex)); ARNETWORK_Manager_SendData (reader->manager, reader->ackBufferID, (uint8_t *)&sendPacket, sizeof (sendPacket), NULL, ARSTREAM_Reader_NetworkCallback, 1); } } ARSAL_PRINT (ARSAL_PRINT_DEBUG, ARSTREAM_READER_TAG, "Ack sender thread ended"); reader->ackThreadStarted = 0; return (void *)0; }
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; }
#if 0 // No longer compiles NOISY(printf("Found strings:\n"); const size_t N = strings.size(); for (size_t i=0; i<N; i++) { printf("%s\n", String8(strings.entryAt(i).string).string()); } ); #endif sp<AaptFile> stringPool = strings.createStringBlock(); NOISY(aout << "String pool:" << HexDump(stringPool->getData(), stringPool->getSize()) << endl); ResXMLTree_header header; memset(&header, 0, sizeof(header)); header.header.type = htods(RES_XML_TYPE); header.header.headerSize = htods(sizeof(header)); const size_t basePos = dest->getSize(); dest->writeData(&header, sizeof(header)); dest->writeData(stringPool->getData(), stringPool->getSize()); // If we have resource IDs, write them. if (resids.size() > 0) { const size_t resIdsPos = dest->getSize(); const size_t resIdsSize = sizeof(ResChunk_header)+(sizeof(uint32_t)*resids.size()); ResChunk_header* idsHeader = (ResChunk_header*) (((const uint8_t*)dest->editData(resIdsPos+resIdsSize))+resIdsPos); idsHeader->type = htods(RES_XML_RESOURCE_MAP_TYPE); idsHeader->headerSize = htods(sizeof(*idsHeader));
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); }
MFS_DIR_ENTRY_PTR MFS_Create_directory_entry ( MFS_DRIVE_STRUCT_PTR drive_ptr, /*[IN] the drive on which to operate */ char_ptr filename_ptr, /*[IN] pointer to the file's name */ char attribute, /*[IN] attribute to be assigned to the file */ uint_32_ptr dir_cluster_ptr, /*[IN/OUT] indicates cluster in which the entry was put.*/ uint_32_ptr dir_index_ptr, /*[IN/OUT] index of the location of new file within the directory */ uint_32_ptr error_ptr /*[IN/OUT] error_return_address */ ) { MFS_DIR_ENTRY_PTR dir_entry_ptr, dir_entry_ptr1; MFS_DIR_ENTRY_PTR temp_entry_ptr; TIME_STRUCT time; DATE_STRUCT clk_time; uint_32 dir_index, saved_index, temp_index; uint_32 entry_cluster, saved_cluster, temp_cluster; uint_32 needed_entries, i; int_32 length; boolean found_all = FALSE; char temp_name[SFILENAME_SIZE+1], short_name[SFILENAME_SIZE+1]; uchar checksum = 0; uint_32 prev_cluster= CLUSTER_INVALID, saved_prev_cluster, temp_prev_cluster; dir_entry_ptr = NULL; entry_cluster = *dir_cluster_ptr; dir_index = 0; /* ** Check for duplicate file */ if ( filename_ptr == NULL ) { *error_ptr = MFS_INVALID_PARAMETER; } else if ( *filename_ptr == '\0' ) { *error_ptr = MFS_FILE_NOT_FOUND; } #if MFSCFG_READ_ONLY_CHECK else if (MFS_is_read_only (NULL, drive_ptr)) { *error_ptr = MFS_DISK_IS_WRITE_PROTECTED; } #endif else if ( (dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, filename_ptr, &entry_cluster, &dir_index, &prev_cluster, MFS_ATTR_ANY, error_ptr)) != NULL ) { *error_ptr = MFS_FILE_EXISTS; } else { /* ** Search for an empty slot */ dir_index = 0; dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, attribute, error_ptr); if ( MFS_Dirname_valid(filename_ptr) ) { found_all = TRUE; } if ( dir_entry_ptr == NULL && !*error_ptr ) { found_all = TRUE; } /* ** Save it now because we might not go into the while loop ** If we don't go into while, we lose original values when these ** variables are restored after the while loop */ saved_cluster = entry_cluster; saved_index = dir_index; while ( !found_all ) { /* Calculate the amount of extra entries needed for LFN's */ saved_cluster = entry_cluster; saved_index = dir_index; for ( needed_entries = (strlen(filename_ptr) + 12) / 13; needed_entries >= 1 && !found_all; needed_entries-- ) { *error_ptr = MFS_Increment_dir_index(drive_ptr, &entry_cluster, &dir_index, NULL); if ( entry_cluster == CLUSTER_EOF && !*error_ptr ) { /* This means the LFN will span a cluster. */ found_all = TRUE; break; } temp_index = dir_index; temp_cluster = entry_cluster; temp_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, MFS_ATTR_ANY,error_ptr); if ( *error_ptr ) { return NULL; } if ( !temp_entry_ptr ) { found_all = TRUE; dir_entry_ptr = NULL; break; } else if ( dir_index == temp_index && temp_cluster == entry_cluster ) { continue; } else { break; } } if ( needed_entries == 0 ) { found_all = TRUE; } if ( found_all ) { dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &saved_cluster, &saved_index, &saved_prev_cluster, MFS_ATTR_ANY,error_ptr); } } entry_cluster = saved_cluster; dir_index = saved_index; if ( dir_entry_ptr == NULL && !*error_ptr ) { /* ** Empty spot not found... get a new cluster and use the first entry. */ dir_index = 0; if ( entry_cluster == 0 ) { *error_ptr = MFS_ROOT_DIR_FULL; return(NULL); } else { *error_ptr = MFS_Add_cluster_to_chain(drive_ptr, entry_cluster, &entry_cluster); if ( *error_ptr == MFS_NO_ERROR ) { *error_ptr = MFS_Clear_cluster(drive_ptr, entry_cluster); if ( *error_ptr ) { return(NULL); } dir_entry_ptr = (pointer) drive_ptr->DIR_SECTOR_PTR; *error_ptr = MFS_Write_back_fat(drive_ptr); if ( *error_ptr ) { return(NULL); } } } } } if ( *error_ptr == MFS_NO_ERROR ) { /* At this point we have one of the following cases ** ** 1. We have a normal 8.3 filename and an empty slot for it ** 2. We have a LFN, and a slot which has enough consecutive free slots ** to store the LFN, followed by the actual entry */ /* If the file is a normal 8.3 file */ if ( MFS_Dirname_valid(filename_ptr) ) { _mem_zero(dir_entry_ptr, sizeof (MFS_DIR_ENTRY)); htodc(dir_entry_ptr->ATTRIBUTE, attribute); MFS_Expand_dotfile(filename_ptr, dir_entry_ptr->NAME); _time_get(&time); _time_to_date(&time, &clk_time); NORMALIZE_DATE(&clk_time); htods(dir_entry_ptr->TIME, PACK_TIME(clk_time)); htods(dir_entry_ptr->DATE, PACK_DATE(clk_time)); drive_ptr->DIR_SECTOR_DIRTY = TRUE; } else { /* Case where the file is a LFN */ length = strlen(filename_ptr); /* Get the 8.3 name and calculate the checksum */ temp_index = 0; temp_cluster = *dir_cluster_ptr; *error_ptr = MFS_lfn_to_sfn(filename_ptr, temp_name); if ( !*error_ptr ) { do { dir_entry_ptr1 = MFS_Find_directory_entry(drive_ptr, temp_name, &temp_cluster, &temp_index, &temp_prev_cluster, MFS_ATTR_ANY, error_ptr); if ( !*error_ptr && dir_entry_ptr1 != NULL ) { MFS_increment_lfn(temp_name); temp_index = 0; } } while ( !*error_ptr && dir_entry_ptr1 != NULL ); dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, attribute, error_ptr); /* ** The memory should be cleared after finding the directory entry. */ _mem_zero(dir_entry_ptr, sizeof (MFS_DIR_ENTRY)); /* Setup the final slot */ ((MFS_LNAME_ENTRY_PTR) dir_entry_ptr)->ID |= MFS_LFN_END; drive_ptr->DIR_SECTOR_DIRTY = TRUE; MFS_Expand_dotfile(temp_name,short_name); checksum = MFS_lfn_checksum(short_name); } while ( length && !*error_ptr ) { i = length - ((length -1) % 13 + 1); *error_ptr = MFS_lfn_name_to_entry(filename_ptr + i, (MFS_LNAME_ENTRY_PTR) dir_entry_ptr); /* Set the entry number, the checksum value and the attribute */ ((MFS_LNAME_ENTRY_PTR) dir_entry_ptr)->ID |= (length + 12) / 13; ((MFS_LNAME_ENTRY_PTR) dir_entry_ptr)->ALIAS_CHECKSUM= checksum; ((MFS_LNAME_ENTRY_PTR) dir_entry_ptr)->ATTR = MFS_ATTR_LFN; drive_ptr->DIR_SECTOR_DIRTY = TRUE; length -= (length - i); if ( length < 0 ) { length = 0; } if ( length && !*error_ptr ) { dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, attribute, error_ptr); if ( dir_entry_ptr == NULL && !*error_ptr ) { /* No empty spots... We need to get a new cluster */ dir_index = 0; if ( entry_cluster == 0 ) { *error_ptr = MFS_ROOT_DIR_FULL; return(NULL); } else { *error_ptr = MFS_Add_cluster_to_chain( drive_ptr, entry_cluster, &entry_cluster); if ( *error_ptr == MFS_NO_ERROR ) { *error_ptr = MFS_Clear_cluster(drive_ptr, entry_cluster); if ( *error_ptr ) { return(NULL); } dir_entry_ptr = (pointer) drive_ptr->DIR_SECTOR_PTR; *error_ptr = MFS_Write_back_fat(drive_ptr); if ( *error_ptr ) { return(NULL); } } } } _mem_zero(dir_entry_ptr, sizeof (MFS_DIR_ENTRY)); drive_ptr->DIR_SECTOR_DIRTY = TRUE; } } /* LFN is written, so write the actual entry */ if ( !*error_ptr ) { dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, attribute, error_ptr); if ( dir_entry_ptr == NULL && !*error_ptr ) { dir_index = 0; if ( entry_cluster == 0 ) { *error_ptr = MFS_ROOT_DIR_FULL; return(NULL); } else { *error_ptr = MFS_Add_cluster_to_chain( drive_ptr, entry_cluster, &entry_cluster); if ( *error_ptr == MFS_NO_ERROR ) { *error_ptr = MFS_Clear_cluster(drive_ptr, entry_cluster); if ( *error_ptr ) { return(NULL); } dir_entry_ptr = (pointer) drive_ptr->DIR_SECTOR_PTR; *error_ptr = MFS_Write_back_fat(drive_ptr); if ( *error_ptr ) { return(NULL); } } } } _mem_zero(dir_entry_ptr, sizeof (MFS_DIR_ENTRY)); htodc(dir_entry_ptr->ATTRIBUTE, attribute); MFS_Expand_dotfile(temp_name, dir_entry_ptr->NAME); _time_get(&time); _time_to_date(&time, &clk_time); NORMALIZE_DATE(&clk_time); htods(dir_entry_ptr->TIME, PACK_TIME(clk_time)); htods(dir_entry_ptr->DATE, PACK_DATE(clk_time)); drive_ptr->DIR_SECTOR_DIRTY = TRUE; } } if ( *error_ptr ) { return(NULL); } } *dir_cluster_ptr = entry_cluster; *dir_index_ptr = dir_index; return(dir_entry_ptr); }