NPK_RESULT npk_package_add_file( NPK_PACKAGE package, NPK_CSTR filename, NPK_CSTR entityname, NPK_ENTITY* lpEntity ) { NPK_ENTITYBODY* eb; NPK_CSTR __entityname; NPK_RESULT res; NPK_CHAR namebuf[512]; if( ( res = npk_entity_alloc( (NPK_ENTITY*)&eb ) ) != NPK_SUCCESS ) return res; if( entityname == NULL ) { __entityname = NULL; if( ( entityname = strrchr( filename, '\\' ) ) == NULL ) if( ( entityname = strrchr( filename, '/' ) ) == NULL ) __entityname = filename; if( __entityname == NULL ) __entityname = entityname + sizeof(NPK_CHAR); } else __entityname = entityname; if( ( res = npk_prepare_entityname( __entityname, namebuf, 512) ) != NPK_SUCCESS ) goto npk_package_add_file_return_with_error; if( ( res = npk_get_filetime( filename, &eb->info_.modified_ ) ) != NPK_SUCCESS ) goto npk_package_add_file_return_with_error; if( ( res = npk_alloc_copy_string( &eb->localname_, filename ) ) != NPK_SUCCESS ) goto npk_package_add_file_return_with_error; if( ( res = npk_alloc_copy_string( &eb->name_, namebuf ) ) != NPK_SUCCESS ) goto npk_package_add_file_return_with_error; eb->info_.nameLength_ = (NPK_SIZE)strlen( eb->name_ ); if( ( res = npk_package_add_entity( package, eb ) ) != NPK_SUCCESS ) goto npk_package_add_file_return_with_error; if( lpEntity ) *lpEntity = eb; return NPK_SUCCESS; npk_package_add_file_return_with_error: NPK_SAFE_FREE( eb ); return res; }
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_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; }