NPK_RESULT npk_package_remove_entity( NPK_PACKAGE package, NPK_ENTITY entity ) { NPK_ENTITYBODY* eb = entity; NPK_PACKAGEBODY* pb = package; if( !entity ) return npk_error( NPK_ERROR_EntityIsNull ); if( !package ) return npk_error( NPK_ERROR_PackageIsNull ); if( eb->owner_ != package ) return npk_error( NPK_ERROR_EntityIsNotInThePackage ); if( eb->prev_ ) eb->prev_->next_ = eb->next_; if( eb->next_ ) eb->next_->prev_ = eb->prev_; if( eb == pb->pEntityHead_ ) pb->pEntityHead_ = eb->next_; if( eb == pb->pEntityTail_ ) pb->pEntityTail_ = eb->prev_; pb->pEntityLatest_ = eb->next_; --pb->info_.entityCount_; NPK_SAFE_FREE( eb->name_ ); NPK_SAFE_FREE( eb->localname_ ); NPK_SAFE_FREE( eb ); return NPK_SUCCESS; }
NPK_ENTITY npk_package_get_entity( NPK_PACKAGE package, NPK_CSTR entityname ) { NPK_ENTITYBODY* eb = NULL; NPK_PACKAGEBODY* pb = package; NPK_BUCKET* bucket = NULL; NPK_CHAR buf[512]; if( !package ) { npk_error( NPK_ERROR_PackageIsNull ); return NULL; } if( NPK_SUCCESS != npk_prepare_entityname( entityname, buf, 512 ) ) return NULL; if( pb->usingHashmap_ ) { bucket = pb->bucket_[npk_get_bucket(buf)]; if( bucket != NULL ) { eb = bucket->pEntityHead_; while( eb != NULL ) { #ifdef NPK_CASESENSITIVE if( strcmp( eb->name_, buf ) == 0 ) #else if( stricmp( eb->name_, buf ) == 0 ) #endif { pb->pEntityLatest_ = eb; return eb; } eb = eb->nextInBucket_; } } } else /* not usingHashmap_ */ { eb = pb->pEntityHead_; while( eb != NULL ) { #ifdef NPK_CASESENSITIVE if( strcmp( eb->name_, buf ) == 0 ) #else if( stricmp( eb->name_, buf ) == 0 ) #endif { pb->pEntityLatest_ = eb; return eb; } eb = eb->next_; } } npk_error( NPK_ERROR_CannotFindEntity ); return NULL; }
bool npk_entity_read_partial( NPK_ENTITY entity, void* buf, NPK_SIZE offset, NPK_SIZE size ) { NPK_ENTITYBODY* eb = entity; NPK_PACKAGEBODY* pb = NULL; NPK_RESULT res; if( !entity ) { npk_error( NPK_ERROR_EntityIsNull ); return false; } if( eb->info_.flag_ & ( NPK_ENTITY_COMPRESS_ZLIB | NPK_ENTITY_COMPRESS_BZIP2 ) ) { npk_error( NPK_ERROR_CantReadCompressedEntityByPartial ); return false; } if( eb->info_.flag_ & ( NPK_ENTITY_ENCRYPT_TEA | NPK_ENTITY_ENCRYPT_XXTEA ) ) { if( ( offset % 8 != 0 ) || ( ( size % 8 != 0 ) && ( offset + size != eb->info_.size_ ) ) ) { npk_error( NPK_ERROR_ReadingEncryptedEntityByPartialShouldBeAligned ); return false; } } pb = eb->owner_; #ifdef NPK_PLATFORM_WINDOWS if( g_useCriticalSection ) EnterCriticalSection( &pb->cs_ ); #endif npk_seek( pb->handle_, (long)(eb->info_.offset_ + offset)+pb->offsetJump_, SEEK_SET ); res = npk_read( pb->handle_, buf, size, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ); if( eb->info_.flag_ & NPK_ENTITY_ENCRYPT_TEA ) tea_decode_buffer(buf, size, pb->teakey_, (pb->info_.version_ >= NPK_VERSION_ENCRYPTREMAINS)); if( eb->info_.flag_ & NPK_ENTITY_ENCRYPT_XXTEA ) xxtea_decode_buffer(buf, size, pb->teakey_, (pb->info_.version_ >= NPK_VERSION_ENCRYPTREMAINS)); #ifdef NPK_PLATFORM_WINDOWS if( g_useCriticalSection ) LeaveCriticalSection( &pb->cs_ ); #endif if( res != NPK_SUCCESS ) return false; return true; }
bool npk_package_close( NPK_PACKAGE package ) { NPK_PACKAGEBODY* pb = (NPK_PACKAGEBODY*)package; NPK_RESULT res; int i; if( !package ) { npk_error( NPK_ERROR_PackageIsNull ); return false; } res = npk_package_remove_all_entity( pb ); if( NPK_SUCCESS != res ) return res; #ifdef NPK_PLATFORM_WINDOWS DeleteCriticalSection( &pb->cs_ ); #endif if( false == pb->usingFdopen_ ) npk_close( pb->handle_ ); for( i = 0; i < NPK_HASH_BUCKETS; ++i ) NPK_SAFE_FREE( pb->bucket_[i] ); NPK_SAFE_FREE( pb ); return true; }
NPK_RESULT npk_write( NPK_HANDLE handle, const void* buf, NPK_SIZE size, NPK_CALLBACK cb, int cbprocesstype, NPK_SIZE cbsize, NPK_CSTR cbidentifier ) { NPK_SIZE currentwritten; NPK_SIZE totalwritten = 0; NPK_SIZE unit = cbsize; if( cb ) { if( unit <= 0 ) unit = size; do { if( (cb)( NPK_ACCESSTYPE_WRITE, cbprocesstype, cbidentifier, totalwritten, size ) == false ) return( npk_error( NPK_ERROR_CancelByCallback ) ); if( (int)( size - totalwritten ) < unit ) unit = size - totalwritten; currentwritten = write( handle, (NPK_STR)buf + totalwritten, (unsigned int)unit ); if( currentwritten < unit ) { if( errno == EACCES ) return( npk_error( NPK_ERROR_PermissionDenied ) ); else if( errno == ENOSPC ) return( npk_error( NPK_ERROR_NotEnoughDiscSpace ) ); else return( npk_error( NPK_ERROR_FileSaveError ) ); } totalwritten += currentwritten; } while( totalwritten < size ); if( (cb)( NPK_ACCESSTYPE_WRITE, cbprocesstype, cbidentifier, totalwritten, size ) == false ) return( npk_error( NPK_ERROR_CancelByCallback ) ); } else { currentwritten = write( handle, (NPK_STR)buf, size ); if( currentwritten < size ) { if( errno == EACCES ) return( npk_error( NPK_ERROR_PermissionDenied ) ); else if( errno == ENOSPC ) return( npk_error( NPK_ERROR_NotEnoughDiscSpace ) ); else return( npk_error( NPK_ERROR_FileSaveError ) ); } } return NPK_SUCCESS; }
NPK_RESULT npk_entity_sub_flag( NPK_ENTITY entity, NPK_FLAG flag ) { NPK_ENTITYBODY* eb = entity; if( !eb ) return npk_error( NPK_ERROR_EntityIsNull ); eb->newflag_ &= ~flag; return NPK_SUCCESS; }
NPK_RESULT npk_entity_get_new_flag( NPK_ENTITY entity, NPK_FLAG* flag ) { NPK_ENTITYBODY* eb = entity; if( !eb ) return npk_error( NPK_ERROR_EntityIsNull ); *flag = eb->newflag_; return NPK_SUCCESS; }
NPK_SIZE npk_entity_get_packed_size( NPK_ENTITY entity ) { NPK_ENTITYBODY* eb = entity; if( !entity ) { npk_error( NPK_ERROR_EntityIsNull ); return 0; } return eb->info_.size_; }
NPK_SIZE npk_entity_get_offset( NPK_ENTITY entity ) { NPK_ENTITYBODY* eb = entity; if( !entity ) { npk_error( NPK_ERROR_EntityIsNull ); return 0; } return eb->info_.offset_; }
NPK_RESULT npk_entity_export( NPK_ENTITY entity, NPK_CSTR filename, bool forceoverwrite ) { void* buf; NPK_HANDLE handle; NPK_ENTITYBODY* eb = entity; NPK_RESULT res; if( !entity ) return npk_error( NPK_ERROR_EntityIsNull ); buf = malloc( eb->info_.originalSize_ ); if( !buf ) return npk_error( NPK_ERROR_NotEnoughMemory ); if( !( res = npk_entity_read( eb, buf ) ) ) return res; if( ( res = npk_open( &handle, filename, true, true ) ) != NPK_SUCCESS ) { if( !forceoverwrite ) return res; if( ( res = npk_open( &handle, filename, true, false ) ) != NPK_SUCCESS ) return res; } if( ( res = npk_write( handle, buf, eb->info_.originalSize_, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ) ) != NPK_SUCCESS ) return res; if( ( res = npk_close( handle ) ) != NPK_SUCCESS ) return res; npk_set_filetime( filename, eb->info_.modified_ ); free( buf ); return NPK_SUCCESS; }
NPK_CSTR npk_entity_get_name( NPK_ENTITY entity ) { NPK_ENTITYBODY* eb = entity; if( !entity ) { npk_error( NPK_ERROR_EntityIsNull ); return 0; } return eb->name_; }
NPK_ENTITY npk_entity_next( NPK_ENTITY entity ) { NPK_ENTITYBODY* eb = entity; if( !entity ) { npk_error( NPK_ERROR_EntityIsNull ); return NULL; } return eb->next_; }
NPK_RESULT npk_alloc_copy_string( NPK_STR* dst, NPK_CSTR src ) { NPK_SIZE len = (NPK_SIZE)strlen(src); if( src == NULL ) return( npk_error( NPK_ERROR_SourceStringisNull ) ); if( *dst == src ) return( npk_error( NPK_ERROR_CannotCopyToItself ) ); if( *dst ) free( *dst ); *dst = malloc( sizeof(NPK_CHAR)*(len+1) ); if( *dst == NULL ) return( npk_error( NPK_ERROR_NotEnoughMemory ) ); strncpy( *dst, src, len ); (*dst)[len] = '\0'; return NPK_SUCCESS; }
NPK_ENTITY npk_package_get_first_entity( NPK_PACKAGE package ) { NPK_PACKAGEBODY* pb = package; if( !package ) { npk_error( NPK_ERROR_PackageIsNull ); return NULL; } return pb->pEntityHead_; }
NPK_RESULT npk_set_filetime( NPK_CSTR filename, const NPK_TIME pft ) { struct stat __sbuf; struct utimbuf __ubuf; int result; result = stat( filename, &__sbuf ); if( result != 0 ) { switch( errno ) { case ENOENT: return( npk_error( NPK_ERROR_FileNotFound ) ); } return( npk_error( NPK_ERROR_FailToGetFiletime ) ); } __ubuf.actime = __sbuf.st_atime; __ubuf.modtime = pft; utime( filename, &__ubuf ); return NPK_SUCCESS; }
NPK_RESULT npk_package_clear( NPK_PACKAGE package ) { NPK_RESULT res; if( !package ) return npk_error( NPK_ERROR_PackageIsNull ); if( ( res = npk_package_remove_all_entity( package ) ) != NPK_SUCCESS ) return res; if( ( res = npk_package_init( package ) ) != NPK_SUCCESS ) return res; return NPK_SUCCESS; }
NPK_RESULT npk_get_filetime( NPK_CSTR filename, NPK_TIME* pft ) { struct stat __sbuf; int result; if( g_use_gluetime ) *pft = g_gluetime; else { result = stat( filename, &__sbuf ); if( result != 0 ) { switch( errno ) { case ENOENT: return( npk_error( NPK_ERROR_FileNotFound ) ); } return( npk_error( NPK_ERROR_FailToGetFiletime ) ); } *pft = (NPK_TIME)__sbuf.st_mtime; } return NPK_SUCCESS; }
NPK_RESULT npk_write_encrypt( NPK_TEAKEY* key, NPK_HANDLE handle, const void* buf, NPK_SIZE size, NPK_CALLBACK cb, int cbprocesstype, NPK_SIZE cbsize, NPK_CSTR cbidentifier ) { NPK_RESULT res; void* bufferforencode = malloc( sizeof(char) * size ); if( !bufferforencode ) return npk_error( NPK_ERROR_NotEnoughMemory ); memcpy( bufferforencode, buf, sizeof(char) * size ); tea_encode_buffer( (NPK_STR)bufferforencode, size, key ); res = npk_write( handle, bufferforencode, size, cb, cbprocesstype, cbsize, cbidentifier ); free( bufferforencode ); return res; }
bool npk_entity_is_ready( NPK_ENTITY entity ) { NPK_ENTITYBODY* eb = entity; NPK_PACKAGEBODY* pb = NULL; int res; struct stat buf; if( !entity ) { npk_error( NPK_ERROR_EntityIsNull ); return false; } pb = eb->owner_; res = fstat( pb->handle_, &buf ); if( (long)( pb->offsetJump_ + eb->info_.offset_ + eb->info_.size_ ) <= buf.st_size ) return true; return false; }
bool npk_entity_read( NPK_ENTITY entity, void* buf ) { NPK_ENTITYBODY* eb = entity; NPK_PACKAGEBODY* pb = NULL; void** lplpTarget = &buf; void* lpDecompressBuffer = NULL; //NPK_SIZE uncompLen = 0; unsigned long uncompLen = 0; NPK_RESULT res; if( !entity ) { npk_error( NPK_ERROR_EntityIsNull ); return false; } if( eb->info_.flag_ & ( NPK_ENTITY_COMPRESS_ZLIB | NPK_ENTITY_COMPRESS_BZIP2 ) ) { lpDecompressBuffer = malloc( sizeof(char) * eb->info_.size_ ); lplpTarget = &lpDecompressBuffer; } pb = eb->owner_; #ifdef NPK_PLATFORM_WINDOWS if( g_useCriticalSection ) EnterCriticalSection( &pb->cs_ ); #endif npk_seek( pb->handle_, (long)eb->info_.offset_+pb->offsetJump_, SEEK_SET ); res = npk_read( pb->handle_, (*lplpTarget), eb->info_.size_, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ); #ifdef NPK_PLATFORM_WINDOWS if( g_useCriticalSection ) LeaveCriticalSection( &pb->cs_ ); #endif if( res != NPK_SUCCESS ) goto npk_entity_read_return_null_with_free; // Decode before uncompress, after v21 if( ( eb->info_.flag_ & NPK_ENTITY_ENCRYPT_TEA ) && ( eb->info_.flag_ & NPK_ENTITY_REVERSE ) ) tea_decode_buffer((char*)(*lplpTarget), eb->info_.size_, pb->teakey_, (pb->info_.version_ >= NPK_VERSION_ENCRYPTREMAINS)); if( eb->info_.flag_ & NPK_ENTITY_ENCRYPT_XXTEA ) xxtea_decode_buffer((char*)(*lplpTarget), eb->info_.size_, pb->teakey_, (pb->info_.version_ >= NPK_VERSION_ENCRYPTREMAINS)); if( eb->info_.flag_ & NPK_ENTITY_COMPRESS_ZLIB ) { uncompLen = eb->info_.originalSize_; if( uncompLen >= NPK_MIN_SIZE_ZIPABLE ) { #ifdef Z_PREFIX if( Z_OK != z_uncompress((Bytef*)(buf), (z_uLong*)&uncompLen, (const Bytef*)lpDecompressBuffer, (z_uLong)eb->info_.size_ ) ) #else if( Z_OK != uncompress((Bytef*)(buf), (uLong*)&uncompLen, (const Bytef*)lpDecompressBuffer, (uLong)eb->info_.size_ ) ) #endif { npk_error( NPK_ERROR_FailToDecompress ); goto npk_entity_read_return_null_with_free; } if( eb->info_.originalSize_ != uncompLen ) { npk_error( NPK_ERROR_FailToDecompress ); goto npk_entity_read_return_null_with_free; } } else memcpy( buf, lpDecompressBuffer, eb->info_.size_ ); NPK_SAFE_FREE( lpDecompressBuffer ); lplpTarget = &buf; } // Decode after uncompress, before v21 if( ( eb->info_.flag_ & NPK_ENTITY_ENCRYPT_TEA ) && !( eb->info_.flag_ & NPK_ENTITY_REVERSE ) ) tea_decode_buffer((char*)(*lplpTarget), eb->info_.originalSize_, pb->teakey_, false); return true; npk_entity_read_return_null_with_free: NPK_SAFE_FREE( lpDecompressBuffer ); return false; }
NPK_RESULT npk_entity_write( NPK_ENTITY entity, NPK_HANDLE handle ) { NPK_PACKAGEBODY* pb; NPK_ENTITYBODY* eb = entity; NPK_RESULT res; bool skipProcessing; void* buf = NULL; void* buf_for_zlib = NULL; NPK_SIZE size, endpos, startpos; int filehandle; int z_res; if( !eb ) return npk_error( NPK_ERROR_EntityIsNull ); pb = eb->owner_; skipProcessing = false; if( eb->localname_ != NULL ) { // read native file and write if( ( res = npk_open( &filehandle, eb->localname_, false, false ) ) != NPK_SUCCESS ) return res; endpos = npk_seek( filehandle, 0, SEEK_END ); startpos = npk_seek( filehandle, 0, SEEK_SET ); size = endpos - startpos; if( size == 0 ) return npk_error( NPK_ERROR_ZeroFileSize ); eb->info_.originalSize_ = size; buf = malloc( size ); if( ( res = npk_read( filehandle, buf, size, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ) ) != NPK_SUCCESS ) goto npk_entity_write_return_with_free; npk_close( filehandle ); npk_get_filetime( eb->localname_, &eb->info_.modified_ ); NPK_SAFE_FREE( eb->localname_ ); } else { if( eb->newflag_ != eb->info_.flag_ ) { // read entity and write size = eb->info_.originalSize_; buf = malloc( size ); npk_entity_read( eb, buf ); } else { // just copy size = eb->info_.size_; buf = malloc( size ); npk_seek( pb->handle_, (long)eb->info_.offset_+pb->offsetJump_, SEEK_SET ); if( ( res = npk_read( pb->handle_, buf, size, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ) ) != NPK_SUCCESS ) goto npk_entity_write_return_with_free; skipProcessing = true; } } if( !skipProcessing ) { // Encode before compress, before v21 if( ( eb->newflag_ & NPK_ENTITY_ENCRYPT ) && !( eb->newflag_ & NPK_ENTITY_REVERSE ) ) tea_encode_buffer((char*)buf, (int)size, pb->teakey_ ); if( eb->newflag_ & NPK_ENTITY_COMPRESS ) { if( size >= NPK_MIN_SIZE_ZIPABLE ) { unsigned long compressedSize = (unsigned long)(sizeof(char) * size * 1.1 + 12); // margin rules from zlib/compress.c buf_for_zlib = malloc( compressedSize ); #ifdef Z_PREFIX z_res = z_compress( (Bytef*)buf_for_zlib, (z_uLong*)&compressedSize, (const Bytef*)buf, (z_uLong)size ); #else z_res = compress( (Bytef*)buf_for_zlib, (uLong*)&compressedSize, (const Bytef*)buf, (uLong)size ); #endif if( ( z_res == Z_OK ) && ( compressedSize < size ) ) { free( buf ); buf = buf_for_zlib; buf_for_zlib = NULL; size = compressedSize; } else // not suitable to compress { free( buf_for_zlib ); eb->newflag_ &= !NPK_ENTITY_COMPRESS; } } } // Encode after compress, after v21 if( ( eb->newflag_ & NPK_ENTITY_ENCRYPT ) && ( eb->newflag_ & NPK_ENTITY_REVERSE ) ) tea_encode_buffer((char*)buf, (int)size, pb->teakey_ ); } eb->info_.size_ = size; eb->info_.offset_ = npk_tell( handle ); if( ( res = npk_write( handle, buf, size, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ) ) != NPK_SUCCESS ) goto npk_entity_write_return_with_free; free( buf ); eb->info_.flag_ = eb->newflag_; return NPK_SUCCESS; npk_entity_write_return_with_free: NPK_SAFE_FREE( buf ); NPK_SAFE_FREE( buf_for_zlib ); return res; }
NPK_RESULT npk_package_save( NPK_PACKAGE package, NPK_CSTR filename, bool forceoverwrite ) { NPK_PACKAGEBODY* pb = package; NPK_ENTITYBODY* eb = NULL; NPK_RESULT res; bool bUseTemporaryFile = false; NPK_SIZE len; int savecount = 0; NPK_STR savefilename = NULL; int savefilehandle; NPK_CHAR* buf; NPK_CHAR* buf_pos; NPK_PACKAGEINFO_V23 header_v23; if( !package ) return npk_error( NPK_ERROR_PackageIsNull ); if( !filename ) return npk_error( NPK_ERROR_PackageHasNoName ); if( ( res = npk_open( &savefilehandle, filename, true, true ) ) == NPK_SUCCESS ) { npk_alloc_copy_string( &savefilename, filename ); } else { if( res != NPK_ERROR_FileAlreadyExists ) return res; if( !forceoverwrite ) return res; len = (NPK_SIZE)strlen( filename ); savefilename = malloc( sizeof(NPK_CHAR)*(len+2) ); if( savefilename == NULL ) return( npk_error( NPK_ERROR_NotEnoughMemory ) ); strncpy( savefilename, filename, len ); savefilename[len+0] = '_'; savefilename[len+1] = '\0'; bUseTemporaryFile = true; if( ( res = npk_open( &savefilehandle, savefilename, true, false ) ) != NPK_SUCCESS ) return res; } strncpy( pb->info_.signature_, NPK_SIGNATURE, sizeof(NPK_CHAR)*4 ); pb->info_.version_ = NPK_VERSION_CURRENT; pb->info_.entityDataOffset_ = sizeof(NPK_PACKAGEINFO) + sizeof(NPK_PACKAGEINFO_V23); npk_seek( savefilehandle, (long)pb->info_.entityDataOffset_, SEEK_SET ); eb = pb->pEntityHead_; while( eb != NULL ) { if( g_callbackfp ) if( (g_callbackfp)( NPK_ACCESSTYPE_WRITE, NPK_PROCESSTYPE_PACKAGE, filename, savecount, pb->info_.entityCount_ ) == false ) return( npk_error( NPK_ERROR_CancelByCallback ) ); npk_entity_write( eb, savefilehandle ); ++savecount; eb = eb->next_; } pb->info_.entityInfoOffset_ = npk_tell( savefilehandle ); pb->info_.entityCount_ = savecount; eb = pb->pEntityHead_; // version 24, Take single encryption to whole entity headers buf = malloc( (sizeof(NPK_ENTITYINFO)+260)*savecount ); // 260 = MAX_PATH on windows, isn't it enough? if( !buf ) return( npk_error( NPK_ERROR_NotEnoughMemory ) ); buf_pos = buf; while( eb != NULL ) { memcpy( buf_pos, &eb->info_, sizeof(NPK_ENTITYINFO) ); buf_pos += sizeof(NPK_ENTITYINFO); memcpy( buf_pos, eb->name_, sizeof(NPK_CHAR)*eb->info_.nameLength_ ); buf_pos += sizeof(NPK_CHAR)*eb->info_.nameLength_; eb = eb->next_; } if( ( res = npk_write_encrypt( pb->teakey_, savefilehandle, buf, buf_pos - buf, g_callbackfp, NPK_PROCESSTYPE_ENTITYHEADER, g_callbackSize, savefilename ) ) != NPK_SUCCESS ) return res; NPK_SAFE_FREE( buf ); npk_seek( savefilehandle, 0, SEEK_SET ); if( ( res = npk_write( savefilehandle, &pb->info_, sizeof(NPK_PACKAGEINFO), g_callbackfp, NPK_PROCESSTYPE_PACKAGEHEADER, g_callbackSize, savefilename ) ) != NPK_SUCCESS ) return res; // version 23, Write the package timestamp for other applications // TODO:reveal the return type of 'time' function on 64bit mac os time( (time_t*)&header_v23.modified_ ); if( ( res = npk_write( savefilehandle, &header_v23, sizeof(NPK_PACKAGEINFO_V23), g_callbackfp, NPK_PROCESSTYPE_PACKAGEHEADER, g_callbackSize, savefilename ) ) != NPK_SUCCESS ) return res; npk_flush( savefilehandle ); npk_close( pb->handle_ ); if( bUseTemporaryFile ) { npk_close( savefilehandle ); remove( filename ); rename( savefilename, filename ); if( (res = npk_open( &pb->handle_, filename, false, false ) ) != NPK_SUCCESS ) return res; } else { pb->handle_ = savefilehandle; } NPK_SAFE_FREE( savefilename ); return NPK_SUCCESS; }
NPK_RESULT __npk_package_open( NPK_PACKAGEBODY* pb, const NPK_CHAR* filename, long filesize, NPK_TEAKEY teakey[4] ) { NPK_CHAR buf[512]; NPK_ENTITYBODY* eb = NULL; NPK_ENTITYINFO_V21 oldinfo; NPK_SIZE entityCount = 0; NPK_CHAR* entityheaderbuf; NPK_CHAR* pos; long entityheadersize = 0; NPK_RESULT res; if( filesize == 0 ) { filesize = npk_seek( pb->handle_, 0, SEEK_END ); npk_seek( pb->handle_, 0, SEEK_SET ); } if( filesize < sizeof(NPK_PACKAGEINFO) ) return( npk_error( NPK_ERROR_PackageIsNotReady ) ); // Read common header res = npk_read( pb->handle_, (void*)&pb->info_, sizeof(NPK_PACKAGEINFO), g_callbackfp, NPK_PROCESSTYPE_PACKAGEHEADER, g_callbackSize, filename ); if( res != NPK_SUCCESS ) return res; if( strncmp( pb->info_.signature_, NPK_SIGNATURE, 4 ) != 0 ) if( strncmp( pb->info_.signature_, NPK_OLD_SIGNATURE, 4 ) != 0 ) return( npk_error( NPK_ERROR_NotValidPackage ) ); // version 18 / read own tea key if( pb->info_.version_ < NPK_VERSION_REFACTORING ) { return ( npk_error( NPK_ERROR_NotSupportedVersion ) ); } else { if( teakey == NULL ) { return ( npk_error( NPK_ERROR_NeedSpecifiedTeaKey ) ); } memcpy( pb->teakey_, teakey, sizeof(NPK_TEAKEY) * 4 ); } // version 23 / package timestamp if( pb->info_.version_ >= NPK_VERSION_PACKAGETIMESTAMP ) { res = npk_read( pb->handle_, (void*)&pb->modified_, sizeof(NPK_TIME), g_callbackfp, NPK_PROCESSTYPE_PACKAGEHEADER, g_callbackSize, filename ); if( res != NPK_SUCCESS ) return res; } entityCount = pb->info_.entityCount_; pb->info_.entityCount_ = 0; if( pb->info_.version_ >= NPK_VERSION_SINGLEPACKHEADER ) { if( pb->info_.version_ >= NPK_VERSION_STREAMABLE ) { if( filesize < (long)pb->info_.entityDataOffset_ ) return( npk_error( NPK_ERROR_PackageIsNotReady ) ); entityheadersize = (long)pb->info_.entityDataOffset_ - (long)pb->info_.entityInfoOffset_; } else { entityheadersize = filesize - (long)pb->info_.entityInfoOffset_; npk_seek( pb->handle_, (long)pb->info_.entityInfoOffset_+pb->offsetJump_, SEEK_SET ); } entityheaderbuf = malloc( entityheadersize ); if( !entityheaderbuf ) return( npk_error( NPK_ERROR_NotEnoughMemory ) ); res = npk_read_encrypt( teakey, pb->handle_, (void*)entityheaderbuf, entityheadersize, g_callbackfp, NPK_PROCESSTYPE_ENTITYHEADER, g_callbackSize, filename, pb->info_.version_ >= NPK_VERSION_ENCRYPTREMAINS, pb->info_.version_ >= NPK_VERSION_USEXXTEAONHEADER ); if( res != NPK_SUCCESS ) return res; pos = entityheaderbuf; while( entityCount > 0 ) { --entityCount; res = npk_entity_alloc( (NPK_ENTITY*)&eb ); if( res != NPK_SUCCESS ) goto __npk_package_open_return_res_with_free; eb->owner_ = pb; memcpy( &eb->info_, pos, sizeof(NPK_ENTITYINFO) ); pos += sizeof(NPK_ENTITYINFO); if( pb->info_.version_ < NPK_VERSION_STREAMABLE ) if( eb->info_.offset_ >= pb->info_.entityInfoOffset_ ) { res = npk_error( NPK_ERROR_InvalidTeaKey ); goto __npk_package_open_return_res_with_free; } eb->newflag_ = eb->info_.flag_; eb->name_ = malloc( sizeof(NPK_CHAR)*(eb->info_.nameLength_+1) ); if( !eb->name_ ) { res = npk_error( NPK_ERROR_NotEnoughMemory ); goto __npk_package_open_return_res_with_free; } eb->name_[eb->info_.nameLength_] = '\0'; memcpy( eb->name_, pos, eb->info_.nameLength_ ); pos += eb->info_.nameLength_; __npk_package_add_entity( pb, eb, false ); } NPK_SAFE_FREE( entityheaderbuf ); } else // old style entity header { npk_seek( pb->handle_, (long)pb->info_.entityInfoOffset_+pb->offsetJump_, SEEK_SET ); while( entityCount > 0 ) { --entityCount; res = npk_entity_alloc( (NPK_ENTITY*)&eb ); if( res != NPK_SUCCESS ) goto __npk_package_open_return_res_with_free; eb->owner_ = pb; // read entity info if( pb->info_.version_ < NPK_VERSION_UNIXTIMESUPPORT ) { res = npk_read_encrypt( teakey, pb->handle_, (void*)&oldinfo, sizeof(NPK_ENTITYINFO), g_callbackfp, NPK_PROCESSTYPE_ENTITYHEADER, g_callbackSize, filename, false, false ); if( res != NPK_SUCCESS ) goto __npk_package_open_return_res_with_free; eb->info_.offset_ = oldinfo.offset_; eb->info_.size_ = oldinfo.size_; eb->info_.originalSize_ = oldinfo.originalSize_; eb->info_.flag_ = oldinfo.flag_; npk_filetime_to_unixtime( &oldinfo.modified_, &eb->info_.modified_ ); eb->info_.nameLength_ = oldinfo.nameLength_; } else { res = npk_read_encrypt( teakey, pb->handle_, (void*)&eb->info_, sizeof(NPK_ENTITYINFO), g_callbackfp, NPK_PROCESSTYPE_ENTITYHEADER, g_callbackSize, filename, false, false ); if( res != NPK_SUCCESS ) goto __npk_package_open_return_res_with_free; } if( eb->info_.offset_ >= pb->info_.entityInfoOffset_ ) { res = npk_error( NPK_ERROR_InvalidTeaKey ); goto __npk_package_open_return_res_with_free; } res = npk_read_encrypt( teakey, pb->handle_, (void*)buf, sizeof(char) * eb->info_.nameLength_, g_callbackfp, NPK_PROCESSTYPE_ENTITYHEADER, g_callbackSize, filename, false, false ); if( res != NPK_SUCCESS ) goto __npk_package_open_return_res_with_free; eb->newflag_ = eb->info_.flag_; // copy name into entity body buf[eb->info_.nameLength_] = '\0'; res = npk_alloc_copy_string( &eb->name_, buf ); if( res != NPK_SUCCESS ) goto __npk_package_open_return_res_with_free; __npk_package_add_entity( pb, eb, false ); } } return NPK_SUCCESS; __npk_package_open_return_res_with_free: NPK_SAFE_FREE( eb ); return res; }
NPK_RESULT npk_open( NPK_HANDLE* handle, NPK_CSTR fileName, bool createfile, bool bcheckexist ) { if(!__use_open) { if( createfile ) { #ifdef NPK_PLATFORM_WINDOWS if( bcheckexist ) { *handle = open( fileName, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IREAD | S_IWRITE ); } else { *handle = creat( fileName, S_IREAD | S_IWRITE ); if( errno == EACCES ) return( npk_error( NPK_ERROR_ReadOnlyFile ) ); close( *handle ); *handle = open( fileName, O_CREAT | O_RDWR | O_BINARY, S_IREAD | S_IWRITE ); } #else mode_t mask = umask(0); if( bcheckexist ) { *handle = open( fileName, O_CREAT | O_EXCL | O_RDWR | O_BINARY, 0666 ); if( *handle != -1 ) fchmod( *handle, 0666&~mask ); } else { *handle = creat( fileName, S_IREAD | S_IWRITE ); if( errno == EACCES ) return( npk_error( NPK_ERROR_ReadOnlyFile ) ); close( *handle ); *handle = open( fileName, O_CREAT | O_RDWR | O_BINARY, 0666 ); if( *handle != -1 ) fchmod( *handle, 0666&~mask ); } umask( mask ); #endif } else *handle = open( fileName, O_BINARY | O_RDONLY ); if( *handle == -1 ) { if( errno == ENOENT ) return( npk_error( NPK_ERROR_FileNotFound ) ); else if( errno == EEXIST ) return( npk_error( NPK_ERROR_FileAlreadyExists ) ); else return( npk_error( NPK_ERROR_FileOpenError ) ); } } else { if( createfile ) *handle = (NPK_HANDLE)__open( fileName, "wb+" ); else *handle = (NPK_HANDLE)__open( fileName, "rb+" ); if( *handle == -1 ) { if( errno == ENOENT ) return( npk_error( NPK_ERROR_FileNotFound ) ); else if( errno == EEXIST ) return( npk_error( NPK_ERROR_FileAlreadyExists ) ); else return( npk_error( NPK_ERROR_FileOpenError ) ); } } return NPK_SUCCESS; }