14d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// Copyright 2016 PDFium Authors. All rights reserved.
24d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// Use of this source code is governed by a BSD-style license that can be
34d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// found in the LICENSE file.
44d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
54d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
64d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
74d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fpdfdoc/cpdf_filespec.h"
84d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
9d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <vector>
10d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fpdfapi/parser/cpdf_dictionary.h"
124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fpdfapi/parser/cpdf_name.h"
134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fpdfapi/parser/cpdf_object.h"
14d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "core/fpdfapi/parser/cpdf_stream.h"
154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fpdfapi/parser/cpdf_string.h"
164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fpdfapi/parser/fpdf_parser_decode.h"
174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fxcrt/fx_system.h"
184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannnamespace {
204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
21d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_ || \
22d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
23d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannWideString ChangeSlashToPlatform(const wchar_t* str) {
24d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  WideString result;
254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  while (*str) {
264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (*str == '/') {
27d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
28d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      result += L':';
294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#else
30d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      result += L'\\';
314d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else {
334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      result += *str;
344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    str++;
364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return result;
384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
40d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannWideString ChangeSlashToPDF(const wchar_t* str) {
41d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  WideString result;
424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  while (*str) {
434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (*str == '\\' || *str == ':')
44d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      result += L'/';
454d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    else
464d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      result += *str;
474d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
484d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    str++;
494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return result;
514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
52d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif  // _FX_PLATFORM_APPLE_ || _FX_PLATFORM_WINDOWS_
534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
544d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}  // namespace
554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
56d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannCPDF_FileSpec::CPDF_FileSpec(CPDF_Object* pObj) : m_pObj(pObj) {
57d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  ASSERT(m_pObj);
58d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
59d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
60d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannCPDF_FileSpec::~CPDF_FileSpec() {}
61d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
62d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannWideString CPDF_FileSpec::DecodeFileName(const WideString& filepath) {
634d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (filepath.GetLength() <= 1)
64d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return WideString();
654d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
66d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
67d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (filepath.Left(sizeof("/Mac") - 1) == WideStringView(L"/Mac"))
684d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return ChangeSlashToPlatform(filepath.c_str() + 1);
694d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return ChangeSlashToPlatform(filepath.c_str());
70d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#elif _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
714d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
72d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (filepath[0] != L'/')
734d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return ChangeSlashToPlatform(filepath.c_str());
74d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (filepath[1] == L'/')
754d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return ChangeSlashToPlatform(filepath.c_str() + 1);
76d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (filepath[2] == L'/') {
77d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    WideString result;
78d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    result += filepath[1];
79d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    result += L':';
804d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    result += ChangeSlashToPlatform(filepath.c_str() + 2);
814d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return result;
824d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
83d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  WideString result;
84d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  result += L'\\';
854d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  result += ChangeSlashToPlatform(filepath.c_str());
864d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return result;
874d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#else
88d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return WideString(filepath);
894d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
904d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
914d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
92d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannWideString CPDF_FileSpec::GetFileName() const {
93d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  WideString csFileName;
944d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (CPDF_Dictionary* pDict = m_pObj->AsDictionary()) {
95d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    csFileName = pDict->GetUnicodeTextFor("UF");
96d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (csFileName.IsEmpty()) {
97d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      csFileName =
98d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann          WideString::FromLocal(pDict->GetStringFor("F").AsStringView());
994d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
1004d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (pDict->GetStringFor("FS") == "URL")
101d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      return csFileName;
102d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
103d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (csFileName.IsEmpty()) {
104d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      constexpr const char* keys[] = {"DOS", "Mac", "Unix"};
105d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      for (const auto* key : keys) {
106d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        if (pDict->KeyExist(key)) {
107d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann          csFileName =
108d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann              WideString::FromLocal(pDict->GetStringFor(key).AsStringView());
109d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann          break;
110d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        }
1114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
1124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
1134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else if (m_pObj->IsString()) {
114d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    csFileName = WideString::FromLocal(m_pObj->GetString().AsStringView());
1154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
116d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return DecodeFileName(csFileName);
1174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
1184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
119d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannCPDF_Stream* CPDF_FileSpec::GetFileStream() const {
120d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Dictionary* pDict = m_pObj->AsDictionary();
121d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!pDict)
122d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return nullptr;
123d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
124d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  // Get the embedded files dictionary.
125d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Dictionary* pFiles = pDict->GetDictFor("EF");
126d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!pFiles)
127d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return nullptr;
128d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
129d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  // Get the file stream of the highest precedence with its file specification
130d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  // string available. Follows the same precedence order as GetFileName().
131d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  constexpr const char* keys[] = {"UF", "F", "DOS", "Mac", "Unix"};
132d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  size_t end = pDict->GetStringFor("FS") == "URL" ? 2 : FX_ArraySize(keys);
133d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (size_t i = 0; i < end; ++i) {
134d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    const ByteString& key = keys[i];
135d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!pDict->GetUnicodeTextFor(key).IsEmpty()) {
136d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      CPDF_Stream* pStream = pFiles->GetStreamFor(key);
137d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (pStream)
138d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        return pStream;
139d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
140d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
141d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return nullptr;
1424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
1434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
144d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannCPDF_Dictionary* CPDF_FileSpec::GetParamsDict() const {
145d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Stream* pStream = GetFileStream();
146d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!pStream)
147d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return nullptr;
148d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
149d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Dictionary* pDict = pStream->GetDict();
150d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!pDict)
151d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return nullptr;
152d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
153d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return pDict->GetDictFor("Params");
154d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
155d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
156d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannWideString CPDF_FileSpec::EncodeFileName(const WideString& filepath) {
1574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (filepath.GetLength() <= 1)
158d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return WideString();
1594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
160d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
161d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (filepath[1] == L':') {
162d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    WideString result(L'/');
163d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    result += filepath[0];
164d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (filepath[2] != L'\\')
165d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      result += L'/';
1664d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1674d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    result += ChangeSlashToPDF(filepath.c_str() + 2);
1684d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return result;
1694d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
170d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (filepath[0] == L'\\' && filepath[1] == L'\\')
1714d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return ChangeSlashToPDF(filepath.c_str() + 1);
1724d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
173d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (filepath[0] == L'\\')
174d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return L'/' + ChangeSlashToPDF(filepath.c_str());
1754d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return ChangeSlashToPDF(filepath.c_str());
176d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#elif _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
177d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (filepath.Left(sizeof("Mac") - 1) == L"Mac")
178d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return L'/' + ChangeSlashToPDF(filepath.c_str());
1794d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return ChangeSlashToPDF(filepath.c_str());
1804d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#else
181d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return WideString(filepath);
1824d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
1834d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
1844d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
185d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid CPDF_FileSpec::SetFileName(const WideString& wsFileName) {
186d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  WideString wsStr = EncodeFileName(wsFileName);
1874d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (m_pObj->IsString()) {
188d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    m_pObj->SetString(ByteString::FromUnicode(wsStr));
1894d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else if (CPDF_Dictionary* pDict = m_pObj->AsDictionary()) {
190d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    pDict->SetNewFor<CPDF_String>("F", ByteString::FromUnicode(wsStr), false);
1914d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    pDict->SetNewFor<CPDF_String>("UF", PDF_EncodeText(wsStr), false);
1924d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
1934d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
194