SettingsFile.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * The contents of this file are subject to the Mozilla Public
  3. * License Version 1.1 (the "License"); you may not use this file
  4. * except in compliance with the License. You may obtain a copy of
  5. * the License at http://www.mozilla.org/MPL/
  6. *
  7. * Software distributed under the License is distributed on an "AS
  8. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9. * implied. See the License for the specific language governing
  10. * rights and limitations under the License.
  11. *
  12. * The Original Code is Vision.
  13. *
  14. * The Initial Developer of the Original Code is The Vision Team.
  15. * Portions created by The Vision Team are
  16. * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights
  17. * Reserved.
  18. *
  19. * Contributor(s): Wade Majors <wade@ezri.org>
  20. * Rene Gollent
  21. */
  22. #include "SettingsFile.h"
  23. #include "Vision.h" // for debug output
  24. #include <Path.h>
  25. #include <File.h>
  26. #include <Directory.h>
  27. #include <Roster.h>
  28. #include <Application.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include <fs_attr.h>
  32. #include <stdio.h>
  33. #include <errno.h>
  34. SettingsFile::SettingsFile(char const*lname,char const*bname,directory_which d) {
  35. check=B_OK;
  36. if (d!=(directory_which)-1) { // -1 means "absolute path"
  37. if ((check=find_directory(d,&path))!=B_OK) return;
  38. } else {
  39. if ((check=path.SetTo("/"))!=B_OK) return;
  40. }
  41. if (bname==NULL) { // no base name, try to figure it out from the signature
  42. app_info ai;
  43. char*sig=ai.signature;
  44. if ((check=be_app->GetAppInfo(&ai))!=B_OK) return;
  45. int plen=strlen("application/x-vnd.");
  46. if (strncmp(sig,"application/x-vnd.",plen)) {
  47. plen=strlen("application/");
  48. if (strncmp(sig,"application/",plen)) {
  49. check=B_BAD_VALUE;
  50. return; // the signature is really broken. bail out.
  51. }
  52. }
  53. sig+=plen;
  54. bool founddot=false;
  55. char*sep;
  56. while ((sep=strchr(sig,'.'))!=NULL) { // replace each '.' by a '/' in the signature to build a relative path
  57. *sep='/';
  58. founddot=true;
  59. }
  60. if (!founddot&&((sep=strchr(sig,'-'))!=NULL)) { // no '.' was found. replace the first '-' by a '/', if there's a '-'
  61. *sep='/';
  62. }
  63. if ((check=path.Append(sig))!=B_OK) { path.Unset();return; }
  64. } else {
  65. if ((check=path.Append(bname))!=B_OK) { path.Unset();return; }
  66. }
  67. if (lname==NULL) {
  68. if ((check=path.Append("Settings"))!=B_OK) { path.Unset();return; }
  69. } else {
  70. if ((check=path.Append(lname))!=B_OK) { path.Unset();return; }
  71. }
  72. }
  73. status_t SettingsFile::InitCheck() const {
  74. return check;
  75. }
  76. status_t SettingsFile::Load() {
  77. status_t ret;
  78. BFile file(path.Path(),B_READ_ONLY);
  79. ret=file.InitCheck();
  80. if (ret!=B_OK) {
  81. return ret;
  82. }
  83. ret=file.Lock();
  84. if (ret!=B_OK) {
  85. return ret;
  86. }
  87. ret=Unflatten(&file);
  88. if (ret!=B_OK) {
  89. file.Unlock();
  90. MakeEmpty();
  91. return ret;
  92. }
  93. if (vision_app->fDebugSettings)
  94. PrintToStream();
  95. /*
  96. ret=file.RewindAttrs();
  97. if (ret!=B_OK) {
  98. file.Unlock();
  99. MakeEmpty();
  100. return ret;
  101. }
  102. char attr_name[B_ATTR_NAME_LENGTH];
  103. while ((ret=file.GetNextAttrName(attr_name))!=B_ENTRY_NOT_FOUND) { // walk all the attributes of the settings file
  104. if (ret!=B_OK) {
  105. file.Unlock();
  106. return ret;
  107. }
  108. // found an attribute
  109. attr_info ai;
  110. ret=file.GetAttrInfo(attr_name,&ai);
  111. if (ret!=B_OK) {
  112. file.Unlock();
  113. return ret;
  114. }
  115. switch (ai.type) {
  116. case B_CHAR_TYPE :
  117. case B_STRING_TYPE :
  118. case B_BOOL_TYPE :
  119. case B_INT8_TYPE :
  120. case B_INT16_TYPE :
  121. case B_INT32_TYPE :
  122. case B_INT64_TYPE :
  123. case B_UINT8_TYPE :
  124. case B_UINT16_TYPE :
  125. case B_UINT32_TYPE :
  126. case B_UINT64_TYPE :
  127. case B_FLOAT_TYPE :
  128. case B_DOUBLE_TYPE :
  129. case B_OFF_T_TYPE :
  130. case B_SIZE_T_TYPE :
  131. case B_SSIZE_T_TYPE :
  132. case B_POINT_TYPE :
  133. case B_RECT_TYPE :
  134. case B_RGB_COLOR_TYPE :
  135. case B_TIME_TYPE :
  136. case B_MIME_TYPE : {
  137. char*partial_name=strdup(attr_name);
  138. if (partial_name==NULL) {
  139. file.Unlock();
  140. return B_NO_MEMORY;
  141. }
  142. ret=_ExtractAttribute(this,&file,attr_name,partial_name,&ai);
  143. free(partial_name);
  144. if (ret!=B_OK) {
  145. file.Unlock();
  146. return ret;
  147. }
  148. break;
  149. }
  150. }
  151. }
  152. */
  153. file.Unlock();
  154. return B_OK;
  155. }
  156. status_t SettingsFile::_ExtractAttribute(BMessage*m,BFile*f,const char*full_name,char*partial_name,attr_info*ai) {
  157. status_t ret;
  158. char*end=strchr(partial_name,':');
  159. if (end==NULL) { // found a leaf
  160. if (!m->HasData(partial_name,ai->type)) { // the name does not exist in the message - ignore it
  161. return B_OK;
  162. }
  163. void* buffer=malloc(ai->size);
  164. if (buffer==NULL) { // cannot allocate space to hold the data
  165. return B_NO_MEMORY;
  166. }
  167. if (f->ReadAttr(full_name,ai->type,0,buffer,ai->size)!=ai->size) { // cannot read the data
  168. free(buffer);
  169. return B_IO_ERROR;
  170. }
  171. ret=m->ReplaceData(partial_name,ai->type,buffer,ai->size);
  172. if (ret!=B_OK) { // cannot replace the data
  173. free(buffer);
  174. return ret;
  175. }
  176. free(buffer);
  177. return B_OK;
  178. }
  179. if (end[1]!=':') { // found an un-numbered sub-message
  180. *(end++)='\0'; // zero-terminate the name, point to the rest of the sub-string
  181. if (!m->HasMessage(partial_name)) { // archived message does not contain that entry. go away.
  182. return B_OK;
  183. }
  184. BMessage subm;
  185. ret=m->FindMessage(partial_name,&subm); // extract the sub-message
  186. if (ret!=B_OK) {
  187. return ret;
  188. }
  189. ret=_ExtractAttribute(&subm,f,full_name,end,ai); // keep processing
  190. if (ret!=B_OK) {
  191. return ret;
  192. }
  193. ret=m->ReplaceMessage(partial_name,&subm); // replace the sub-message
  194. if (ret!=B_OK) {
  195. return ret;
  196. }
  197. return B_OK;
  198. } else { // found a numbered entry
  199. char* endptr;
  200. errno=0;
  201. *end='\0'; // zero-terminate the name
  202. int32 r=strtol(end+2,&endptr,10); // get the entry number
  203. if (errno!=0) {
  204. return B_OK;
  205. }
  206. if (r>=1000000000) { // sanity-check.
  207. return B_OK;
  208. }
  209. if (*endptr==':') { // this is a numbered message
  210. if (!m->HasMessage(partial_name,r)) { // archived message does not contain that entry, go away
  211. return B_OK;
  212. }
  213. BMessage subm;
  214. ret=m->FindMessage(partial_name,r,&subm); // extract the sub-message
  215. if (ret!=B_OK) {
  216. return ret;
  217. }
  218. ret=_ExtractAttribute(&subm,f,full_name,endptr+1,ai); // recurse
  219. if (ret!=B_OK) {
  220. return ret;
  221. }
  222. ret=m->ReplaceMessage(partial_name,r,&subm); // replace the sub-message
  223. if (ret!=B_OK) {
  224. return ret;
  225. }
  226. return B_OK;
  227. } else if (*endptr=='\0') { // this is a numbered leaf
  228. if (!m->HasData(partial_name,ai->type,r)) { // archived message does not contain this leaf
  229. return B_OK;
  230. }
  231. void* buffer=malloc(ai->size);
  232. if (buffer==NULL) {
  233. return B_NO_MEMORY;
  234. }
  235. if (f->ReadAttr(full_name,ai->type,0,buffer,ai->size)!=ai->size) { // extract the attribute data
  236. free(buffer);
  237. return B_IO_ERROR;
  238. }
  239. ret=m->ReplaceData(partial_name,ai->type,r,buffer,ai->size); // and replace it in the message
  240. if (ret!=B_OK) {
  241. free(buffer);
  242. return ret;
  243. }
  244. free(buffer);
  245. return B_OK;
  246. }
  247. }
  248. return B_OK;
  249. }
  250. status_t SettingsFile::Save() const {
  251. status_t ret;
  252. BFile file(path.Path(),B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE);
  253. ret=file.InitCheck();
  254. if (ret != B_OK) { // try to create the parent directory if creating the file fails the first time
  255. BPath parent;
  256. ret=path.GetParent(&parent);
  257. if (ret!=B_OK) {
  258. return ret;
  259. }
  260. ret=create_directory(parent.Path(),0777);
  261. if (ret!=B_OK) {
  262. return ret;
  263. }
  264. ret=file.SetTo(path.Path(),B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE);
  265. }
  266. if (ret!=B_OK) {
  267. return ret;
  268. }
  269. ret=file.Lock(); // lock the file to do atomic attribute transactions on it.
  270. if (ret!=B_OK) {
  271. return ret;
  272. }
  273. if (vision_app->fDebugSettings)
  274. PrintToStream();
  275. ret=Flatten(&file);
  276. if (ret!=B_OK) {
  277. file.Unlock();
  278. return ret;
  279. }
  280. /*
  281. ret=_StoreAttributes(this,&file);
  282. if (ret!=B_OK) {
  283. file.Unlock();
  284. return ret;
  285. }
  286. */
  287. file.Unlock();
  288. return B_OK;
  289. }
  290. status_t SettingsFile::_StoreAttributes(BMessage const*m,BFile*f,const char*basename) {
  291. #if B_BEOS_VERSION_DANO
  292. const char *namefound;
  293. #else
  294. char* namefound;
  295. #endif
  296. type_code typefound;
  297. int32 countfound;
  298. status_t ret;
  299. for (int32 i=0;i<m->CountNames(B_ANY_TYPE);i++) { // walk the entries in the message
  300. ret=m->GetInfo(B_ANY_TYPE,i,&namefound,&typefound,&countfound);
  301. if (ret!=B_OK) {
  302. return ret;
  303. }
  304. if (strchr(namefound,':')!=NULL) { // do not process anything that contains a colon (considered a magic char)
  305. break;
  306. }
  307. switch (typefound) {
  308. case B_MESSAGE_TYPE : { // found a sub-message
  309. if (countfound==1) { // single sub-message
  310. char* lname=(char*)malloc(strlen(basename)+strlen(namefound)+2); // allocate space for the base name
  311. if (lname==NULL) {
  312. return B_NO_MEMORY;
  313. }
  314. sprintf(lname,"%s%s:",basename,namefound); // create the base name for the sub-message
  315. BMessage subm;
  316. ret=m->FindMessage(namefound,&subm);
  317. if (ret!=B_OK) {
  318. free(lname);
  319. return ret;
  320. }
  321. ret=_StoreAttributes(&subm,f,lname); // and process the sub-message with the base name
  322. if (ret!=B_OK) {
  323. free(lname);
  324. return ret;
  325. }
  326. free(lname);
  327. } else if (countfound<1000000000) { // (useless in 32-bit) sanity check
  328. char* lname=(char*)malloc(strlen(basename)+strlen(namefound)+11); // allocate space for the base name
  329. if (lname==NULL) {
  330. return B_NO_MEMORY;
  331. }
  332. sprintf(lname,"%ld",countfound-1); // find the length of the biggest number for that field
  333. char format[12];
  334. sprintf(format,"%%s%%s::%%0%ldld:",strlen(lname)); // create the sprintf format
  335. for (int32 j=0;j<countfound;j++) {
  336. sprintf(lname,format,basename,namefound,j); // create the base name for the sub-message
  337. BMessage subm;
  338. ret=m->FindMessage(namefound,j,&subm);
  339. if (ret!=B_OK) {
  340. free(lname);
  341. return ret;
  342. }
  343. ret=_StoreAttributes(&subm,f,lname); // process the sub-message with the base name
  344. if (ret!=B_OK) {
  345. free(lname);
  346. return ret;
  347. }
  348. }
  349. free(lname);
  350. }
  351. break;
  352. }
  353. case B_CHAR_TYPE :
  354. case B_STRING_TYPE :
  355. case B_BOOL_TYPE :
  356. case B_INT8_TYPE :
  357. case B_INT16_TYPE :
  358. case B_INT32_TYPE :
  359. case B_INT64_TYPE :
  360. case B_UINT8_TYPE :
  361. case B_UINT16_TYPE :
  362. case B_UINT32_TYPE :
  363. case B_UINT64_TYPE :
  364. case B_FLOAT_TYPE :
  365. case B_DOUBLE_TYPE :
  366. case B_OFF_T_TYPE :
  367. case B_SIZE_T_TYPE :
  368. case B_SSIZE_T_TYPE :
  369. case B_POINT_TYPE :
  370. case B_RECT_TYPE :
  371. case B_RGB_COLOR_TYPE :
  372. case B_TIME_TYPE :
  373. case B_MIME_TYPE : { // found a supported type. the code is basically the same.
  374. if (countfound==1) {
  375. char* lname=(char*)malloc(strlen(basename)+strlen(namefound)+1);
  376. if (lname==NULL) {
  377. return B_NO_MEMORY;
  378. }
  379. sprintf(lname,"%s%s",basename,namefound);
  380. const void* datafound;
  381. ssize_t sizefound;
  382. ret=m->FindData(namefound,typefound,&datafound,&sizefound);
  383. if (ret!=B_OK) {
  384. free(lname);
  385. return ret;
  386. }
  387. sizefound=f->WriteAttr(lname,typefound,0,datafound,sizefound);
  388. if (sizefound<0) {
  389. free(lname);
  390. return sizefound;
  391. }
  392. free(lname);
  393. } else if (countfound<1000000000) {
  394. char* lname=(char*)malloc(strlen(basename)+strlen(namefound)+10);
  395. if (lname==NULL) {
  396. return B_NO_MEMORY;
  397. }
  398. sprintf(lname,"%ld",countfound-1);
  399. char format[12];
  400. sprintf(format,"%%s%%s::%%0%ldld",strlen(lname));
  401. for (int32 j=0;j<countfound;j++) {
  402. sprintf(lname,format,basename,namefound,j);
  403. const void* datafound;
  404. ssize_t sizefound;
  405. ret=m->FindData(namefound,typefound,j,&datafound,&sizefound);
  406. if (ret!=B_OK) {
  407. free(lname);
  408. return ret;
  409. }
  410. sizefound=f->WriteAttr(lname,typefound,0,datafound,sizefound);
  411. if (sizefound<0) {
  412. free(lname);
  413. return sizefound;
  414. }
  415. }
  416. free(lname);
  417. }
  418. break;
  419. }
  420. }
  421. }
  422. return B_OK;
  423. }