• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfdoc/cpdf_filespec.h"
8 
9 #include <vector>
10 
11 #include "build/build_config.h"
12 #include "constants/stream_dict_common.h"
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_name.h"
15 #include "core/fpdfapi/parser/cpdf_object.h"
16 #include "core/fpdfapi/parser/cpdf_stream.h"
17 #include "core/fpdfapi/parser/cpdf_string.h"
18 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
19 #include "core/fxcrt/fx_system.h"
20 
21 namespace {
22 
23 #if defined(OS_MACOSX) || defined(OS_WIN)
ChangeSlashToPlatform(const wchar_t * str)24 WideString ChangeSlashToPlatform(const wchar_t* str) {
25   WideString result;
26   while (*str) {
27     if (*str == '/') {
28 #if defined(OS_MACOSX)
29       result += L':';
30 #else
31       result += L'\\';
32 #endif
33     } else {
34       result += *str;
35     }
36     str++;
37   }
38   return result;
39 }
40 
ChangeSlashToPDF(const wchar_t * str)41 WideString ChangeSlashToPDF(const wchar_t* str) {
42   WideString result;
43   while (*str) {
44     if (*str == '\\' || *str == ':')
45       result += L'/';
46     else
47       result += *str;
48 
49     str++;
50   }
51   return result;
52 }
53 #endif  // defined(OS_MACOSX) || defined(OS_WIN)
54 
55 }  // namespace
56 
CPDF_FileSpec(const CPDF_Object * pObj)57 CPDF_FileSpec::CPDF_FileSpec(const CPDF_Object* pObj) : m_pObj(pObj) {
58   ASSERT(m_pObj);
59 }
60 
CPDF_FileSpec(CPDF_Object * pObj)61 CPDF_FileSpec::CPDF_FileSpec(CPDF_Object* pObj)
62     : m_pObj(pObj), m_pWritableObj(pObj) {
63   ASSERT(m_pObj);
64 }
65 
~CPDF_FileSpec()66 CPDF_FileSpec::~CPDF_FileSpec() {}
67 
DecodeFileName(const WideString & filepath)68 WideString CPDF_FileSpec::DecodeFileName(const WideString& filepath) {
69   if (filepath.GetLength() <= 1)
70     return WideString();
71 
72 #if defined(OS_MACOSX)
73   if (filepath.First(sizeof("/Mac") - 1) == WideStringView(L"/Mac"))
74     return ChangeSlashToPlatform(filepath.c_str() + 1);
75   return ChangeSlashToPlatform(filepath.c_str());
76 #elif defined(OS_WIN)
77 
78   if (filepath[0] != L'/')
79     return ChangeSlashToPlatform(filepath.c_str());
80   if (filepath[1] == L'/')
81     return ChangeSlashToPlatform(filepath.c_str() + 1);
82   if (filepath[2] == L'/') {
83     WideString result;
84     result += filepath[1];
85     result += L':';
86     result += ChangeSlashToPlatform(filepath.c_str() + 2);
87     return result;
88   }
89   WideString result;
90   result += L'\\';
91   result += ChangeSlashToPlatform(filepath.c_str());
92   return result;
93 #else
94   return WideString(filepath);
95 #endif
96 }
97 
GetFileName() const98 WideString CPDF_FileSpec::GetFileName() const {
99   WideString csFileName;
100   if (const CPDF_Dictionary* pDict = m_pObj->AsDictionary()) {
101     const CPDF_String* pUF = ToString(pDict->GetDirectObjectFor("UF"));
102     if (pUF)
103       csFileName = pUF->GetUnicodeText();
104     if (csFileName.IsEmpty()) {
105       const CPDF_String* pK =
106           ToString(pDict->GetDirectObjectFor(pdfium::stream::kF));
107       if (pK)
108         csFileName = WideString::FromDefANSI(pK->GetString().AsStringView());
109     }
110     if (pDict->GetStringFor("FS") == "URL")
111       return csFileName;
112 
113     if (csFileName.IsEmpty()) {
114       for (const auto* key : {"DOS", "Mac", "Unix"}) {
115         const CPDF_String* pValue = ToString(pDict->GetDirectObjectFor(key));
116         if (pValue) {
117           csFileName =
118               WideString::FromDefANSI(pValue->GetString().AsStringView());
119           break;
120         }
121       }
122     }
123   } else if (const CPDF_String* pString = m_pObj->AsString()) {
124     csFileName = WideString::FromDefANSI(pString->GetString().AsStringView());
125   }
126   return DecodeFileName(csFileName);
127 }
128 
GetFileStream() const129 const CPDF_Stream* CPDF_FileSpec::GetFileStream() const {
130   const CPDF_Dictionary* pDict = m_pObj->AsDictionary();
131   if (!pDict)
132     return nullptr;
133 
134   // Get the embedded files dictionary.
135   const CPDF_Dictionary* pFiles = pDict->GetDictFor("EF");
136   if (!pFiles)
137     return nullptr;
138 
139   // List of keys to check for the file specification string.
140   // Follows the same precedence order as GetFileName().
141   static constexpr const char* kKeys[] = {"UF", "F", "DOS", "Mac", "Unix"};
142   size_t end = pDict->GetStringFor("FS") == "URL" ? 2 : FX_ArraySize(kKeys);
143   for (size_t i = 0; i < end; ++i) {
144     ByteString key = kKeys[i];
145     if (!pDict->GetUnicodeTextFor(key).IsEmpty()) {
146       const CPDF_Stream* pStream = pFiles->GetStreamFor(key);
147       if (pStream)
148         return pStream;
149     }
150   }
151   return nullptr;
152 }
153 
GetFileStream()154 CPDF_Stream* CPDF_FileSpec::GetFileStream() {
155   return const_cast<CPDF_Stream*>(
156       static_cast<const CPDF_FileSpec*>(this)->GetFileStream());
157 }
158 
GetParamsDict() const159 const CPDF_Dictionary* CPDF_FileSpec::GetParamsDict() const {
160   const CPDF_Stream* pStream = GetFileStream();
161   if (!pStream)
162     return nullptr;
163 
164   const CPDF_Dictionary* pDict = pStream->GetDict();
165   return pDict ? pDict->GetDictFor("Params") : nullptr;
166 }
167 
GetParamsDict()168 CPDF_Dictionary* CPDF_FileSpec::GetParamsDict() {
169   return const_cast<CPDF_Dictionary*>(
170       static_cast<const CPDF_FileSpec*>(this)->GetParamsDict());
171 }
172 
EncodeFileName(const WideString & filepath)173 WideString CPDF_FileSpec::EncodeFileName(const WideString& filepath) {
174   if (filepath.GetLength() <= 1)
175     return WideString();
176 
177 #if defined(OS_WIN)
178   if (filepath[1] == L':') {
179     WideString result(L'/');
180     result += filepath[0];
181     if (filepath[2] != L'\\')
182       result += L'/';
183 
184     result += ChangeSlashToPDF(filepath.c_str() + 2);
185     return result;
186   }
187   if (filepath[0] == L'\\' && filepath[1] == L'\\')
188     return ChangeSlashToPDF(filepath.c_str() + 1);
189 
190   if (filepath[0] == L'\\')
191     return L'/' + ChangeSlashToPDF(filepath.c_str());
192   return ChangeSlashToPDF(filepath.c_str());
193 #elif defined(OS_MACOSX)
194   if (filepath.First(sizeof("Mac") - 1).EqualsASCII("Mac"))
195     return L'/' + ChangeSlashToPDF(filepath.c_str());
196   return ChangeSlashToPDF(filepath.c_str());
197 #else
198   return WideString(filepath);
199 #endif
200 }
201 
SetFileName(const WideString & wsFileName)202 void CPDF_FileSpec::SetFileName(const WideString& wsFileName) {
203   if (!m_pWritableObj) {
204     NOTREACHED();
205     return;
206   }
207 
208   WideString wsStr = EncodeFileName(wsFileName);
209   if (m_pObj->IsString()) {
210     m_pWritableObj->SetString(wsStr.ToDefANSI());
211   } else if (CPDF_Dictionary* pDict = m_pWritableObj->AsDictionary()) {
212     pDict->SetNewFor<CPDF_String>(pdfium::stream::kF, wsStr.ToDefANSI(), false);
213     pDict->SetNewFor<CPDF_String>("UF", wsStr);
214   }
215 }
216