/* * Tencent is pleased to support the open source community by making * MMKV available. * * Copyright (C) 2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of * the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "MiniPBCoder.h" #ifdef MMKV_APPLE # include "CodedInputData.h" # include "CodedInputDataCrypt.h" # include "CodedOutputData.h" # include "MMBuffer.h" # include "PBEncodeItem.hpp" # include "PBUtility.h" # include # include # if __has_feature(objc_arc) # error This file must be compiled with MRC. Use -fno-objc-arc flag. # endif using namespace std; namespace mmkv { size_t MiniPBCoder::prepareObjectForEncode(__unsafe_unretained NSObject *obj) { if (!obj) { return m_encodeItems->size(); } m_encodeItems->push_back(PBEncodeItem()); PBEncodeItem *encodeItem = &(m_encodeItems->back()); size_t index = m_encodeItems->size() - 1; if ([obj isKindOfClass:[NSString class]]) { NSString *str = (NSString *) obj; encodeItem->type = PBEncodeItemType_NSString; NSData *buffer = [[str dataUsingEncoding:NSUTF8StringEncoding] retain]; encodeItem->value.tmpObjectValue = (__bridge void *) buffer; encodeItem->valueSize = static_cast(buffer.length); } else if ([obj isKindOfClass:[NSDate class]]) { NSDate *oDate = (NSDate *) obj; encodeItem->type = PBEncodeItemType_NSDate; encodeItem->value.objectValue = (__bridge void *) oDate; encodeItem->valueSize = pbDoubleSize(); encodeItem->compiledSize = encodeItem->valueSize; return index; // double has fixed compilesize } else if ([obj isKindOfClass:[NSData class]]) { NSData *oData = (NSData *) obj; encodeItem->type = PBEncodeItemType_NSData; encodeItem->value.objectValue = (__bridge void *) oData; encodeItem->valueSize = static_cast(oData.length); } else { m_encodeItems->pop_back(); MMKVError("%@ not recognized", NSStringFromClass(obj.class)); return m_encodeItems->size(); } encodeItem->compiledSize = pbRawVarint32Size(encodeItem->valueSize) + encodeItem->valueSize; return index; } void MiniPBCoder::decodeOneMap(MMKVMap &dic, size_t position, bool greedy) { auto block = [position, this](MMKVMap &dictionary) { if (position) { m_inputData->seek(position); } else { m_inputData->readInt32(); } while (!m_inputData->isAtEnd()) { KeyValueHolder kvHolder; const auto &key = m_inputData->readString(kvHolder); if (key.length > 0) { m_inputData->readData(kvHolder); auto itr = dictionary.find(key); if (itr != dictionary.end()) { if (kvHolder.valueSize > 0) { itr->second = std::move(kvHolder); } else { auto oldKey = itr->first; dictionary.erase(itr); [oldKey release]; } } else { if (kvHolder.valueSize > 0) { dictionary.emplace(key, std::move(kvHolder)); [key retain]; } } } } }; if (greedy) { try { block(dic); } catch (std::exception &exception) { MMKVError("%s", exception.what()); } } else { try { MMKVMap tmpDic; block(tmpDic); dic.swap(tmpDic); for (auto &pair : tmpDic) { [pair.first release]; } } catch (std::exception &exception) { MMKVError("%s", exception.what()); } } } # ifndef MMKV_DISABLE_CRYPT void MiniPBCoder::decodeOneMap(MMKVMapCrypt &dic, size_t position, bool greedy) { auto block = [position, this](MMKVMapCrypt &dictionary) { if (position) { m_inputDataDecrpt->seek(position); } else { m_inputDataDecrpt->readInt32(); } while (!m_inputDataDecrpt->isAtEnd()) { KeyValueHolderCrypt kvHolder; const auto &key = m_inputDataDecrpt->readString(kvHolder); if (key.length > 0) { m_inputDataDecrpt->readData(kvHolder); auto itr = dictionary.find(key); if (itr != dictionary.end()) { if (kvHolder.realValueSize() > 0) { itr->second = std::move(kvHolder); } else { auto oldKey = itr->first; dictionary.erase(itr); [oldKey release]; } } else { if (kvHolder.realValueSize() > 0) { dictionary.emplace(key, std::move(kvHolder)); [key retain]; } } } } }; if (greedy) { try { block(dic); } catch (std::exception &exception) { MMKVError("%s", exception.what()); } } else { try { MMKVMapCrypt tmpDic; block(tmpDic); dic.swap(tmpDic); for (auto &pair : tmpDic) { [pair.first release]; } } catch (std::exception &exception) { MMKVError("%s", exception.what()); } } } # endif // MMKV_DISABLE_CRYPT NSObject *MiniPBCoder::decodeObject(const MMBuffer &oData, Class cls) { if (!cls || oData.length() == 0) { return nil; } CodedInputData input(oData.getPtr(), oData.length()); if (cls == [NSString class]) { return input.readString(); } else if (cls == [NSMutableString class]) { return [NSMutableString stringWithString:input.readString()]; } else if (cls == [NSData class]) { return input.readNSData(); } else if (cls == [NSMutableData class]) { return [NSMutableData dataWithData:input.readNSData()]; } else if (cls == [NSDate class]) { return [NSDate dateWithTimeIntervalSince1970:input.readDouble()]; } else { MMKVError("%@ not recognized", NSStringFromClass(cls)); } return nil; } bool MiniPBCoder::isCompatibleClass(Class cls) { if (cls == [NSString class]) { return true; } if (cls == [NSMutableString class]) { return true; } if (cls == [NSData class]) { return true; } if (cls == [NSMutableData class]) { return true; } if (cls == [NSDate class]) { return true; } return false; } } // namespace mmkv #endif // MMKV_APPLE