VirtualBox

source: vbox/trunk/src/VBox/Main/ExtPackUtil.cpp@ 33973

Last change on this file since 33973 was 33862, checked in by vboxsync, 14 years ago

iprt/cpp/ministring.h: Changed the substring constructors to match std::string. As I feared, this caused some minor issues with the format+va_list constructor, fortunately it's only when passing a_cchSrc=0. While at it, I've added the one missing std::string constructor, the repeat character constructor.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.9 KB
Line 
1/* $Id: ExtPackUtil.cpp 33862 2010-11-08 17:07:49Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Extension Pack Utilities and definitions, VBoxC, VBoxSVC, ++.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * Oracle Corporation confidential
10 * All rights reserved
11 */
12
13
14/*******************************************************************************
15* Header Files *
16*******************************************************************************/
17#include "include/ExtPackUtil.h"
18
19#include <iprt/ctype.h>
20#include <iprt/dir.h>
21#include <iprt/file.h>
22#include <iprt/param.h>
23#include <iprt/path.h>
24#include <iprt/string.h>
25#include <iprt/cpp/xml.h>
26
27#include <VBox/log.h>
28
29
30/**
31 * Reads the extension pack description.
32 *
33 * @returns NULL on success, pointer to an error message on failure (caller
34 * deletes it).
35 * @param a_pszDir The directory containing the description file.
36 * @param a_pExtPackDesc Where to store the description file.
37 * @param a_pObjInfo Where to store the object info for the file (unix
38 * attribs). Optional.
39 */
40iprt::MiniString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
41{
42 /*
43 * Clear the description.
44 */
45 a_pExtPackDesc->strName.setNull();
46 a_pExtPackDesc->strDescription.setNull();
47 a_pExtPackDesc->strVersion.setNull();
48 a_pExtPackDesc->uRevision = 0;
49 a_pExtPackDesc->strMainModule.setNull();
50
51 /*
52 * Validate, open and parse the XML file.
53 */
54 char szFilePath[RTPATH_MAX];
55 int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME);
56 if (RT_FAILURE(vrc))
57 return new iprt::MiniString("No VirtualBoxExtensionPack element");
58
59 RTFSOBJINFO ObjInfo;
60 vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
61 if (RT_FAILURE(vrc))
62 return &(new iprt::MiniString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc);
63 if (a_pObjInfo)
64 *a_pObjInfo = ObjInfo;
65 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
66 {
67 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
68 return new iprt::MiniString("The XML file is symlinked, that is not allowed");
69 return &(new iprt::MiniString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode);
70 }
71
72 xml::Document Doc;
73 xml::XmlFileParser Parser;
74 try
75 {
76 Parser.read(szFilePath, Doc);
77 }
78 catch (xml::XmlError Err)
79 {
80 return new iprt::MiniString(Err.what());
81 }
82 xml::ElementNode *pRoot = Doc.getRootElement();
83
84 /*
85 * Get the main element and check its version.
86 */
87 const xml::ElementNode *pVBoxExtPackElm = pRoot->findChildElement(NULL, "VirtualBoxExtensionPack");
88 if (!pVBoxExtPackElm)
89 return new iprt::MiniString("No VirtualBoxExtensionPack element");
90
91 iprt::MiniString strFormatVersion;
92 if (!pVBoxExtPackElm->getAttributeValue("version", strFormatVersion))
93 return new iprt::MiniString("Missing format version");
94 if (!strFormatVersion.equals("1.0"))
95 return &(new iprt::MiniString("Unsupported format version: "))->append(strFormatVersion);
96
97 /*
98 * Read and validate the name.
99 */
100 const xml::ElementNode *pNameElm = pVBoxExtPackElm->findChildElement("Name");
101 if (!pNameElm)
102 return new iprt::MiniString("The 'Name' element is missing");
103 const char *pszName = pNameElm->getValue();
104 if (!VBoxExtPackIsValidName(pszName))
105 return &(new iprt::MiniString("Invalid name: "))->append(pszName);
106
107 const xml::ElementNode *pDescElm = pVBoxExtPackElm->findChildElement("Description");
108 if (!pDescElm)
109 return new iprt::MiniString("The 'Description' element is missing");
110 const char *pszDesc = pDescElm->getValue();
111 if (!pszDesc || *pszDesc == '\0')
112 return new iprt::MiniString("The 'Description' element is empty");
113 if (strpbrk(pszDesc, "\n\r\t\v\b") != NULL)
114 return new iprt::MiniString("The 'Description' must not contain control characters");
115
116 const xml::ElementNode *pVersionElm = pVBoxExtPackElm->findChildElement("Version");
117 if (!pVersionElm)
118 return new iprt::MiniString("The 'Version' element is missing");
119 const char *pszVersion = pVersionElm->getValue();
120 if (!pszVersion || *pszVersion == '\0')
121 return new iprt::MiniString("The 'Version' element is empty");
122 if (!VBoxExtPackIsValidVersionString(pszVersion))
123 return &(new iprt::MiniString("Invalid version string: "))->append(pszVersion);
124
125 uint32_t uRevision;
126 if (!pVersionElm->getAttributeValue("revision", uRevision))
127 uRevision = 0;
128
129 const xml::ElementNode *pMainModuleElm = pVBoxExtPackElm->findChildElement("MainModule");
130 if (!pMainModuleElm)
131 return new iprt::MiniString("The 'MainModule' element is missing");
132 const char *pszMainModule = pMainModuleElm->getValue();
133 if (!pszMainModule || *pszMainModule == '\0')
134 return new iprt::MiniString("The 'MainModule' element is empty");
135 if (!VBoxExtPackIsValidMainModuleString(pszVersion))
136 return &(new iprt::MiniString("Invalid main module string: "))->append(pszMainModule);
137
138 /*
139 * Everything seems fine, fill in the return values and return successfully.
140 */
141 a_pExtPackDesc->strName = pszName;
142 a_pExtPackDesc->strDescription = pszDesc;
143 a_pExtPackDesc->strVersion = pszVersion;
144 a_pExtPackDesc->uRevision = uRevision;
145 a_pExtPackDesc->strMainModule = pszMainModule;
146
147 return NULL;
148}
149
150
151/**
152 * Extract the extension pack name from the tarball path.
153 *
154 * @returns String containing the name on success, the caller must delete it.
155 * NULL if no valid name was found or if we ran out of memory.
156 * @param pszTarball The path to the tarball.
157 */
158iprt::MiniString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball)
159{
160 /*
161 * Skip ahead to the filename part and count the number of characters
162 * that matches the criteria for a extension pack name.
163 */
164 const char *pszSrc = RTPathFilename(pszTarball);
165 if (!pszSrc)
166 return NULL;
167
168 size_t off = 0;
169 while (RT_C_IS_ALNUM(pszSrc[off]) || pszSrc[off] == ' ')
170 off++;
171
172 /*
173 * Check min and max name limits.
174 */
175 if ( off > VBOX_EXTPACK_NAME_MIN_LEN
176 || off < VBOX_EXTPACK_NAME_MIN_LEN)
177 return NULL;
178
179 /*
180 * Make a duplicate of the name and return it.
181 */
182 iprt::MiniString *pStrRet = new iprt::MiniString(pszSrc, off);
183 Assert(VBoxExtPackIsValidName(pStrRet->c_str()));
184 return pStrRet;
185}
186
187
188/**
189 * Validates the extension pack name.
190 *
191 * @returns true if valid, false if not.
192 * @param pszName The name to validate.
193 * @sa VBoxExtPackExtractNameFromTarballPath
194 */
195bool VBoxExtPackIsValidName(const char *pszName)
196{
197 if (!pszName)
198 return false;
199
200 /*
201 * Check the characters making up the name, only english alphabet
202 * characters, decimal digits and spaces are allowed.
203 */
204 size_t off = 0;
205 while (pszName[off])
206 {
207 if (!RT_C_IS_ALNUM(pszName[off]) && !pszName[off] == ' ')
208 return false;
209 off++;
210 }
211
212 /*
213 * Check min and max name limits.
214 */
215 if ( off > VBOX_EXTPACK_NAME_MIN_LEN
216 || off < VBOX_EXTPACK_NAME_MIN_LEN)
217 return false;
218
219 return true;
220}
221
222/**
223 * Validates the extension pack version string.
224 *
225 * @returns true if valid, false if not.
226 * @param pszVersion The version string to validate.
227 */
228bool VBoxExtPackIsValidVersionString(const char *pszVersion)
229{
230 if (!pszVersion || *pszVersion == '\0')
231 return false;
232
233 /* 1.x.y.z... */
234 if (!RT_C_IS_DIGIT(*pszVersion))
235 return false;
236 for (;;)
237 {
238 while (RT_C_IS_DIGIT(*pszVersion))
239 pszVersion++;
240 if (*pszVersion != '.')
241 break;
242 }
243
244 /* upper case string + numbers indicating the build type */
245 if (*pszVersion == '-' || *pszVersion == '_')
246 {
247 do
248 pszVersion++;
249 while ( RT_C_IS_DIGIT(*pszVersion)
250 || RT_C_IS_UPPER(*pszVersion)
251 || *pszVersion == '-'
252 || *pszVersion == '_');
253 }
254
255 /* revision or nothing */
256 if (*pszVersion != '\0')
257 {
258 if (*pszVersion != 'r')
259 return false;
260 do
261 pszVersion++;
262 while (RT_C_IS_DIGIT(*pszVersion));
263 }
264
265 return *pszVersion == '\0';
266}
267
268/**
269 * Validates the extension pack main module string.
270 *
271 * @returns true if valid, false if not.
272 * @param pszMainModule The main module string to validate.
273 */
274bool VBoxExtPackIsValidMainModuleString(const char *pszMainModule)
275{
276 if (!pszMainModule || *pszMainModule == '\0')
277 return false;
278
279 /* Restricted charset, no extensions (dots). */
280 while ( RT_C_IS_ALNUM(*pszMainModule)
281 || *pszMainModule == '-'
282 || *pszMainModule == '_')
283 pszMainModule++;
284
285 return *pszMainModule == '\0';
286}
287
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette