1/*
2 * Copyright (c) 2024-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <stdexcept>
17
18#include "signature_tools_log.h"
19#include "zip_entry.h"
20
21namespace OHOS {
22namespace SignatureTools {
23int ZipEntry::Alignment(int alignNum)
24{
25    /* if cd extra len bigger than entry extra len, make cd and entry extra length equals */
26    if (alignNum == 0) {
27        return -1;
28    }
29    uint16_t padding = 0;
30    if (!CalZeroPaddingLengthForEntryExtra(padding)) {
31        return -1;
32    }
33    uint32_t remainder = (m_zipEntryData->GetZipEntryHeader()->GetLength() +
34        m_fileEntryInCentralDirectory->GetOffset()) % alignNum;
35    if (remainder == 0) {
36        return padding;
37    }
38    int add = alignNum - remainder;
39    uint16_t newExtraLength = m_zipEntryData->GetZipEntryHeader()->GetExtraLength() + add;
40    static constexpr int MAX_UNSIGNED_SHORT_VALUE = 0xFFFF;
41    if (newExtraLength > MAX_UNSIGNED_SHORT_VALUE) {
42        SIGNATURE_TOOLS_LOGE("can not align %s", m_zipEntryData->GetZipEntryHeader()->GetFileName().c_str());
43        return -1;
44    }
45    SetEntryHeaderNewExtraLength(newExtraLength);
46    SetCenterDirectoryNewExtraLength(newExtraLength);
47
48    return add;
49}
50
51bool ZipEntry::CalZeroPaddingLengthForEntryExtra(uint16_t& padding)
52{
53    uint16_t entryExtraLen = m_zipEntryData->GetZipEntryHeader()->GetExtraLength();
54    uint16_t cdExtraLen = m_fileEntryInCentralDirectory->GetExtraLength();
55    if (cdExtraLen > entryExtraLen) {
56        if (!SetEntryHeaderNewExtraLength(cdExtraLen)) {
57            return false;
58        }
59        padding =  cdExtraLen - entryExtraLen;
60    }
61    if (cdExtraLen < entryExtraLen) {
62        if (!SetCenterDirectoryNewExtraLength(entryExtraLen)) {
63            return false;
64        }
65        padding =  entryExtraLen - cdExtraLen;
66    }
67    return true;
68}
69
70bool ZipEntry::SetCenterDirectoryNewExtraLength(uint16_t newLength)
71{
72    const std::string oldExtraData = m_fileEntryInCentralDirectory->GetExtraData();
73    std::string newCDExtra;
74    if (!GetAlignmentNewExtra(newLength, oldExtraData, newCDExtra)) {
75        return false;
76    }
77    m_fileEntryInCentralDirectory->SetExtraData(newCDExtra);
78    m_fileEntryInCentralDirectory->SetExtraLength(newLength);
79    m_fileEntryInCentralDirectory->SetLength(CentralDirectory::CD_LENGTH +
80        m_fileEntryInCentralDirectory->GetFileNameLength() +
81        m_fileEntryInCentralDirectory->GetExtraLength() +
82        m_fileEntryInCentralDirectory->GetCommentLength());
83    return true;
84}
85
86bool ZipEntry::SetEntryHeaderNewExtraLength(uint16_t newLength)
87{
88    ZipEntryHeader* zipEntryHeader = m_zipEntryData->GetZipEntryHeader();
89    const std::string oldExtraData = zipEntryHeader->GetExtraData();
90    std::string alignmentNewExtra;
91    if (!GetAlignmentNewExtra(newLength, oldExtraData, alignmentNewExtra)) {
92        return false;
93    }
94    zipEntryHeader->SetExtraData(alignmentNewExtra);
95    zipEntryHeader->SetExtraLength(newLength);
96    zipEntryHeader->SetLength(ZipEntryHeader::HEADER_LENGTH +
97        zipEntryHeader->GetExtraLength() + zipEntryHeader->GetFileNameLength());
98    m_zipEntryData->SetLength(zipEntryHeader->GetLength() +
99        m_zipEntryData->GetFileSize() +
100        (m_zipEntryData->GetDataDescriptor() == nullptr ? 0 : DataDescriptor::DES_LENGTH));
101    return true;
102}
103
104bool ZipEntry::GetAlignmentNewExtra(uint16_t newLength, const std::string& old, std::string& res)
105{
106    if (old.empty()) {
107        res = std::string(newLength, 0);
108        return true;
109    }
110    if (newLength < old.size()) {
111        SIGNATURE_TOOLS_LOGE("can not align %s", m_zipEntryData->GetZipEntryHeader()->GetFileName().c_str());
112        return false;
113    }
114
115    res = old;
116    res.resize(newLength);
117    return true;
118}
119
120ZipEntryData* ZipEntry::GetZipEntryData()
121{
122    return m_zipEntryData;
123}
124
125void ZipEntry::SetZipEntryData(ZipEntryData* zipEntryData)
126{
127    m_zipEntryData = zipEntryData;
128}
129
130CentralDirectory* ZipEntry::GetCentralDirectory()
131{
132    return m_fileEntryInCentralDirectory;
133}
134
135void ZipEntry::SetCentralDirectory(CentralDirectory* centralDirectory)
136{
137    m_fileEntryInCentralDirectory = centralDirectory;
138}
139} // namespace SignatureTools
140} // namespace OHOS
141