static orxSTATUS orxFASTCALL ParseTextFile(const orxSTRING _zFileName) { orxFILE *pstFile; orxSTATUS eResult; // Opens file pstFile = orxFile_Open(_zFileName, orxFILE_KU32_FLAG_OPEN_READ | orxFILE_KU32_FLAG_OPEN_BINARY); // Success? if(pstFile) { orxCHAR acBuffer[orxFONTGEN_KU32_BUFFER_SIZE]; orxU32 u32Size, u32Offset, u32Counter; orxBOOL bFirst; // While file isn't empty for(u32Size = (orxU32)orxFile_Read(acBuffer, sizeof(orxCHAR), orxFONTGEN_KU32_BUFFER_SIZE, pstFile), u32Offset = 0, u32Counter = 0, bFirst = orxTRUE; u32Size > 0; u32Size = (orxU32)orxFile_Read(acBuffer + u32Offset, sizeof(orxCHAR), orxFONTGEN_KU32_BUFFER_SIZE - u32Offset, pstFile) + u32Offset, bFirst = orxFALSE) { orxCHAR *pc, *pcNext; // Has UTF-8 BOM? if((bFirst != orxFALSE) && (orxString_NCompare(acBuffer, orxFONTGEN_KZ_UTF8_BOM, orxFONTGEN_KU32_UTF8_BOM_LENGTH) == 0)) { // Skips it pc = acBuffer + orxFONTGEN_KU32_UTF8_BOM_LENGTH; } else { // Starts at the beginning of the buffer pc = acBuffer; } // For all characters for(pcNext = orxNULL; pc < acBuffer + u32Size; pc = pcNext) { orxU32 u32CharacterCodePoint; // Reads it u32CharacterCodePoint = orxString_GetFirstCharacterCodePoint(pc, (const orxSTRING *)&pcNext); // Non EOL? if((u32CharacterCodePoint != orxCHAR_CR) && (u32CharacterCodePoint != orxCHAR_LF)) { // Valid? if(u32CharacterCodePoint != orxU32_UNDEFINED) { // Not already in table? if(orxHashTable_Get(sstFontGen.pstCharacterTable, u32CharacterCodePoint) == orxNULL) { orxU32 u32GlyphIndex; // Gets character's glyph index u32GlyphIndex = (orxU32)FT_Get_Char_Index(sstFontGen.pstFontFace, (FT_ULong)u32CharacterCodePoint); // Valid? if(u32GlyphIndex) { orxFONTGEN_GLYPH *pstGlyph; // Allocates glyph pstGlyph = (orxFONTGEN_GLYPH *)orxBank_Allocate(sstFontGen.pstGlyphBank); // Checks orxASSERT(pstGlyph); // Inits it pstGlyph->u32Index = u32GlyphIndex; pstGlyph->u32CodePoint = u32CharacterCodePoint; // Adds it if(orxHashTable_Add(sstFontGen.pstCharacterTable, u32CharacterCodePoint, (void *)pstGlyph) != orxSTATUS_FAILURE) { orxFONTGEN_GLYPH *pstSearchGlyph; // Finds position for(pstSearchGlyph = (orxFONTGEN_GLYPH *)orxLinkList_GetFirst(&sstFontGen.stGlyphList); pstSearchGlyph && (u32CharacterCodePoint > pstSearchGlyph->u32CodePoint); pstSearchGlyph = (orxFONTGEN_GLYPH *)orxLinkList_GetNext(&pstSearchGlyph->stNode)); // Valid? if(pstSearchGlyph) { // Adds it before orxLinkList_AddBefore(&pstSearchGlyph->stNode, &pstGlyph->stNode); } else { // Adds it at the end orxLinkList_AddEnd(&sstFontGen.stGlyphList, &pstGlyph->stNode); } // Updates counter u32Counter++; } else { // Logs message orxFONTGEN_LOG(LOAD, "Character '0x%X': couldn't add to table, skipping.", u32CharacterCodePoint); } } else { // Adds it orxHashTable_Add(sstFontGen.pstCharacterTable, u32CharacterCodePoint, (void *)sstFontGen.pstCharacterTable); // Logs message orxFONTGEN_LOG(LOAD, "Character '0x%X': glyph not found in font, skipping.", u32CharacterCodePoint); } } } else { // End of buffer? if(pcNext >= acBuffer + u32Size) { // Stops break; } else { // Logs message orxFONTGEN_LOG(LOAD, "Invalid character code point '0x%X', skipping.", u32CharacterCodePoint); } } } } // Has remaining buffer? if((pc != acBuffer) && (pcNext > pc)) { // Updates offset u32Offset = (orxU32)(orxMIN(pcNext, acBuffer + u32Size) - pc); // Copies it at the beginning of the buffer orxMemory_Copy(acBuffer, pc, u32Offset); } else { // Clears offset u32Offset = 0; } } // Logs message orxFONTGEN_LOG(LOAD, "'%s': added %d characters.", _zFileName, u32Counter); // Updates result eResult = orxSTATUS_SUCCESS; } else { // Updates result eResult = orxSTATUS_FAILURE; } // Done! return eResult; }
/** Optimizes a hashtable for read accesses (minimizes number of cache misses upon collisions) * @param[in] _pstHashTable HashTable to optimize * @return orxSTATUS_SUCESS / orxSTATUS_FAILURE */ orxSTATUS orxFASTCALL orxHashTable_Optimize(orxHASHTABLE *_pstHashTable) { orxSTATUS eResult = orxSTATUS_SUCCESS; /* Checks */ orxASSERT(_pstHashTable != orxNULL); /* Has elements? */ if(_pstHashTable->u32Counter > 0) { orxHASHTABLE_CELL *astWorkBuffer; /* Allocates work buffer */ astWorkBuffer = (orxHASHTABLE_CELL *)orxMemory_Allocate(_pstHashTable->u32Counter * sizeof(orxHASHTABLE_CELL), orxMEMORY_TYPE_TEMP); /* Valid? */ if(astWorkBuffer != orxNULL) { orxU64 u64KeyIndex; orxU32 u32BufferIndex, i; orxHASHTABLE_CELL *pstCell; /* For all cells */ for(i = 0, u64KeyIndex = 0, u32BufferIndex = 0, pstCell = orxNULL; i < _pstHashTable->u32Counter; i++, u32BufferIndex++) { /* Linked cell? */ if((pstCell != orxNULL) && (pstCell->pstNext != orxNULL)) { /* Gets next in line */ pstCell = pstCell->pstNext; } else { /* Finds next head cell */ do{pstCell = _pstHashTable->apstCell[u64KeyIndex++];} while(pstCell == orxNULL); } /* Stores it */ orxMemory_Copy(&astWorkBuffer[u32BufferIndex], pstCell, sizeof(orxHASHTABLE_CELL)); } /* Clears bank */ orxBank_Clear(_pstHashTable->pstBank); /* For all ordered cells */ for(i = 0, pstCell = orxNULL; i < _pstHashTable->u32Counter; i++) { orxHASHTABLE_CELL *pstPreviousCell; /* Allocates new cell */ pstPreviousCell = pstCell; pstCell = (orxHASHTABLE_CELL *)orxBank_Allocate(_pstHashTable->pstBank); /* Checks */ orxASSERT(pstCell != orxNULL); /* Stores its data */ orxMemory_Copy(pstCell, &astWorkBuffer[i], sizeof(orxHASHTABLE_CELL)); /* Chained? */ if((pstPreviousCell != orxNULL) && (pstPreviousCell->pstNext != orxNULL)) { /* Updates chaining */ pstPreviousCell->pstNext = pstCell; } else { /* Updates head pointer */ _pstHashTable->apstCell[orxHashTable_FindIndex(_pstHashTable, pstCell->u64Key)] = pstCell; } } /* Clears work buffer */ orxMemory_Free(astWorkBuffer); } else { /* Updates result */ eResult = orxSTATUS_FAILURE; } } /* Done! */ return eResult; }